Skip to main content
Glama

Malaysia Prayer Time MCP Server

client.cpython-311.pyc22.7 kB
� �$�g�G���dZddlZddlZddlmZddlmZmZmZmZm Z m Z ddl Z ddl m Z ddlmZddlmZmZeje��Ze�ej��ejsGej��Ze�ejd ����e�e��e d e � ��ZGd �d e��ZGd�de��Z Gd�de��Z!Gd�de��Z"Gd�d��Z#e#��Z$dS)a) Async HTTP client for interacting with the waktusolat.app API. This module provides a high-level interface to the waktusolat.app API with: - Automatic connection pooling and timeouts - Retry logic for transient failures - Type-safe responses using Pydantic models - Comprehensive error handling �N)�datetime)�List�Dict�Any�Optional�TypeVar�Type)� BaseModel�)�config)� PrayerTimes�Zonez4%(asctime)s - %(name)s - %(levelname)s - %(message)s�T)�boundc��eZdZdZdS)�APIErrorzBase exception for API errors.N��__name__� __module__� __qualname__�__doc__���Q/Users/aman/2) personal/mcp-server-malaysia-prayer-time/src/waktu_solat/client.pyrr$s������(�(��Drrc��eZdZdZdS)�ValidationErrorz#Raised when input validation fails.Nrrrrrr*s������-�-��Drrc��eZdZdZdS)� ResponseErrorz(Raised when the API response is invalid.Nrrrrrr0�������2�2��Drrc��eZdZdZdS)�ConnectionErrorz(Raised when connection to the API fails.Nrrrrr!r!6rrr!c��eZdZdZdd�Zdd�Zd�Zdejfd�Z de d e de e e ffd �Z d e deefd �Zdeefd �Zd e de e e ffd�ZdS)� HTTPClientz-Async HTTP client for the waktusolat.app API.�returnNc��tjtjtjj��tjtjjtjj������|_tjj � d��|_ d|_ tjd|j ��std���dS)z&Initialize a new HTTP client instance.��max_connections�max_keepalive_connections��timeout�limits�/�z ^https?://z,Base URL must start with http:// or https://N)�httpx� AsyncClient�Timeoutr �httpr*�Limits�pool_connections�_client�base_url�rstrip� _base_url� _retry_count�re�matchr��selfs r�__init__zHTTPClient.__init__?s���49�4E��M�&�+�"5�6�6��<� &� � <�*0�+�*F����5 �5 �5 �� �%�k�2�9�9�#�>�>���!"����x� �t�~�6�6� R�!�"P�Q�Q� Q� R� Rrc�� K�|S)zSetup the async context.rr;s r� __aenter__zHTTPClient.__aenter__Os ����� rc��K�|jr� t�d��|j����d{V��n4#t$r'}t�d|����Yd}~nd}~wwxYwt�d��d|_dS#t�d��d|_wxYwdS)zCleanup the async context.zClosing HTTP client connectionNzError closing HTTP client: zHTTP client connection closed)r4�logger�debug�aclose� Exception�error)r<�exc_type�exc_val�exc_tb�es r� __aexit__zHTTPClient.__aexit__Ss����� �<� $� $�� � �=�>�>�>��l�)�)�+�+�+�+�+�+�+�+�+�+��� @� @� @�� � �>�1�>�>�?�?�?�?�?�?�?�?����� @����� � �<�=�=�=�#�� � � ��� � �<�=�=�=�#�� �#�#�#�#� $� $s/�9A�B� A6�A1�,B�1A6�6B�#B?c��2K�|js�t�d��tjtjt jj��tj t jj t jj ������|_|jS)z� Get the httpx client instance, creating it if needed. Returns: The httpx AsyncClient instance Raises: RuntimeError: If the client cannot be initialized z!Creating new HTTP client instancer&r)) r4rArBr.r/r0r r1r*r2r3r;s r� _get_clientzHTTPClient._get_client_s~�����|� � �L�L�<� =� =� =� �,�� �f�k�&9�:�:��|�$*�K�$@�.4�k�.J�������D�L��|�r�method�pathc��K�|�d��sd|��}|j�|��}|����d{V��}t�d|�d|����ddd�|�di���}||d<t |j��D�]-} |jj ||fi|���d{V��}|� �� |� ��} nS#t$rF} t� d |j����td t!| �������d} ~ wwxYw| std ���t�d |�d | ����| cS#t"j$r�} d| jj�d | jj��} ||jdz kr)t� | ��t+| ���t�d|dz�d| ����Yd} ~ ��[d} ~ wt"j$rw} dt!| ����} ||jdz kr)t� | ��t1| ���t�d|dz�d| ����Yd} ~ ���d} ~ wt2$r@} dt!| ����} t� | ��t+| ���d} ~ wwxYwdS)a� Make an HTTP request to the API with retry logic. Args: method: HTTP method (GET, POST, etc.) path: API endpoint path **kwargs: Additional arguments to pass to httpx Returns: API response data as dictionary Raises: RuntimeError: If client is not initialized APIError: If the request fails after retries r,NzMaking z request to zMalaysiaPrayerTimeMCP/0.2.0zapplication/json)z User-Agent�Accept�headerszInvalid JSON response content: zInvalid JSON response: zEmpty response from APIz$Successfully received response from �: zHTTP r zRequest failed (attempt z): zRequest failed: zUnexpected error: )� startswithr7rLrArB�get�ranger8r4�request�raise_for_status�json� ValueErrorrE�textr�strr.�HTTPStatusError�response� status_coder�warning� RequestErrorr!rD) r<rMrN�kwargs�url�clientrQ�attemptr]�datarI� error_msgs r�_requestzHTTPClient._requesttsj���� ���s�#�#� ��t�:�:�D���'��'�'���'�'�)�)�)�)�)�)�)�)��� � �8�v�8�8�3�8�8�9�9�9�8�(� � ��j�j��B�'�'� �� $��y���T�.�/�/�$ *�$ *�G�# *�!5���!5�f�c�!L�!L�V�!L�!L�L�L�L�L�L�L���)�)�+�+�+�L�#�=�=�?�?�D�D��!�L�L�L��L�L�!R�8�=�!R�!R�S�S�S�'�(J�#�a�&�&�(J�(J�K�K�K�����L���� �C�'�(A�B�B�B�� � �Q�C�Q�Q�4�Q�Q�R�R�R�� � � ���(� W� W� W�O�A�J�$:�O�O�a�j�o�O�O� ��d�/�!�3�3�3��L�L��+�+�+�"�9�-�-�-����U�'�A�+�U�U�)�U�U�V�V�V�V�V�V�V�V������%� W� W� W�7�s�1�v�v�7�7� ��d�/�!�3�3�3��L�L��+�+�+�)�)�4�4�4����U�'�A�+�U�U�)�U�U�V�V�V�V�V�V�V�V������ *� *� *�9��Q���9�9� �� � �Y�'�'�'��y�)�)�)����� *����C$ *�$ *sW�.E&� C�E&� D.�(AD)�)D.�.5E&�&K�5A6G1�1K�A,I5�5 K�;J=�=K�zonec ��� �K�tjd|��std���t�d|����|�dd|�����d{V��}t |t��r(d|vr$t |dt��r |d}nlt |t��r|}nTt� dt|���d |����td t|��j �d |�����|st� d |����gSg}|D�]��t�fd �dD����st� d������<d}d�vr��d��}�n�t |t��r,|�dt!j��j��nt!j��j}t |t��rL|�dt!j���d�������n7t!j���d�����}��dd��}t |t*��rp t!j|d��j} nV#t0$rG t!j|d��j} n(#t0$rt!j��j} YnwxYwYnwxYw|} |�d| d�d|d��}gd�} i} | D]�} ��| ��} | �d| | <�t | t2��rz t!j| ��}|�d��| | <�b#t0t6t8f$r2}t� d| �d| �d|����d| | <Yd}~��d}~wwxYwt | t*��r| nd| | <��||r(t!j|d���d��nd ��d!��| d"| d#| d$| d%| d&| d'd(� } |�t=j|������^#t0$r+}t� d)��d*|����Yd}~���d}~wwxYw|st� d+|����gS|S),a' Fetch prayer times for a specific zone. Args: zone: Zone code (e.g., 'SGR01') Returns: List of prayer times for the zone Raises: ValidationError: If zone format is invalid APIError: If the request fails �^[A-Z]{3}\d{2}$�-Invalid zone format. Expected format: 'ABC12'z Fetching prayer times for zone: �GET� /v2/solat/N�prayers�Invalid data format received: �. Data: �8Invalid prayer times data format in response. Received: �, data: zNo prayer times found for zone c3� �K�|]}|�vV�� dS�Nr)�.0�key�items �r� <genexpr>z.HTTPClient.get_prayer_times.<locals>.<genexpr>�s;���������t� ������r)�day�fajr�dhuhr�asr�maghrib�isha�syurukz&Skipping incomplete prayer time data: �date�year�monthz%bryr z%B�-�02d�rzrr{r|r}r~�%H:%M�Error converting timestamp � for rR�%Y-%m-%dz%A��imsakrzrr{r|r}r~) r�ryr�rzrr{r|r}r~z#Skipping invalid prayer time data: z . Error: z0Could not parse any valid prayer times for zone ) r9r:rrA�inforg� isinstance�dict�listrE�typerrr_�allrTr�nowr��strftime�upperr[�strptimer�rY�int� fromtimestamp�OSError� OverflowError�appendr �model_validate)r<rhre� prayers_data� prayer_times�date_strr�r�ry� month_num� time_fields�times�field� time_value�dtrI� transformedrws @r�get_prayer_timeszHTTPClient.get_prayer_times�s�������x�*�D�1�1� S�!�"Q�R�R� R�� � �=�t�=�=�>�>�>��]�]�5�*=�t�*=�*=�>�>�>�>�>�>�>�>�� �t�T� "� "� ��T�!�!��4� �?�D�1�1�"� � �?�L�L� ��d� #� #� ��L�L� �L�L�T�$�t�*�*�T�T�d�T�T� U� U� U��n�4�PT�:�:�K^�n�n�hl�n�n��� � � � �N�N�C�T�C�C� D� D� D��I�� � �X �X �D������W������ ����N��N�N�O�O�O���H���~�~��8�8�F�+�+��� "�$��-�-�-�D�H�H�V�X�\�^�^�%8�9�9�9�!����,��"�$��-�-�?�D�H�H�W�h�l�n�n�&=�&=�d�&C�&C�&I�&I�&K�&K�L�L�L�!����0�0��6�6�<�<�>�>�� �h�h�u�a�(�(���e�S�)�)� &�=�$,�$5�e�T�$B�$B�$H� � ��%�=�=�=�=�(0�(9�%��(F�(F�(L�I�I��)�=�=�=�(0� ���(<�I�I�I�=������=����!&�I�"�>�>�Y�>�>�>�S�>�>�>��P�O�O�K��E�$� W� W��!�X�X�e�_�_� ��%�#'�E�%�L���j�#�.�.� W�,�%�3�J�?�?��')�{�{�7�';�';��e� � ��&���?�,�,�,����W�*�W�W�5�W�W�TU�W�W����(,��e� � � � � � ����� ,����2<�J��1L�1L�#V�:�:�RV�E�%�L�L�!� ��H�%�h� �;�;�D�D�T�J�J�J�����'�*�*��f� ���/��w���U�|� ��+��f� ���K�  ��#�#�K�$>�{�$K�$K�L�L�L�L��� � � ����W�T�W�W�TU�W�W�X�X�X���������� ���� � � �N�N�T�d�T�T� U� U� U��I��sf�)K� L�K*�)L�*"L� L�L�L�L�#,N�O�'(O�O�''R� S� S�Sc ���K�t�d��|�dd���d{V��}t�d|����t |t ��st d���g}|D�]��t�fd�dD����st�d ������<�d r�d r�d st�d ������r�d � ���d � ���d � ��d�}t|� ����st�d|������ t�d|����tj |��}t�d|����|� |����e#t$rA}t�d�d �dt|���d|����Yd}~���d}~wwxYw|s)t�d��t d���|S)z� Fetch all available zones. Returns: List of available prayer time zones Raises: APIError: If the request fails zFetching available zonesrlz/zonesNzRaw zones response: z%Invalid zones data format in responsec3� �K�|]}|�vV�� dSrtr)ru�krws �rrxz'HTTPClient.get_zones.<locals>.<genexpr>Zs'�����L�L�Q�q�D�y�L�L�L�L�L�Lr)�daerah� jakimCode�negeriz1Skipping zone data with missing required fields: r�r�r�z/Skipping zone data with empty required fields: )�name�coder�z1Skipping zone with empty values after stripping: z"Attempting to validate zone data: zSuccessfully validated zone: zValidation failed for zone rRz. Transformed data: z$No valid zones found in API responsez1Failed to parse any valid zones from API response)rAr�rgrBr�r�rr�r_�strip�valuesrr�r�rYr[rE)r<re�zonesr��validated_zonerIrws @r� get_zoneszHTTPClient.get_zonesEs������ � � �.�/�/�/��]�]�5�(�3�3�3�3�3�3�3�3��� � �2�D�2�2�3�3�3��$��%�%� I�� G�H�H� H����# �# �D��L�L�L�L�*K�L�L�L�L�L� ����N��N�N�������>� ��k�):� �$�x�.� ����W�QU�W�W�X�X�X���X��,�,�.�.��[�)�/�/�1�1��x�.�.�.�0�0���K��{�)�)�+�+�,�,� ����U� �U�U����� �� � �O�+�O�O�P�P�P�!%�!4�[�!A�!A��� � �M�^�M�M�N�N�N�� � �^�,�,�,�,��� � � ����7�$�{�2C�7�7�s�1�v�v�7�7�)4�7�7�������������  ����� U� �L�L�?� @� @� @�� S�T�T� T�� s�?A#G$�$ H/�.6H*�*H/c ��K�tjd|��std���t�d|����|�dd|�����d{V��}t |t��r(d|vr$t |dt��r |d}nlt |t��r|}nTt� dt|���d |����td t|��j �d |�����tj���d ��}d}|D]#}d |vr|�d ��|kr|}n�$|s:tj��j}|D]}|�d��|kr|}n� |s(|r&t�d|�d���|d}|std���gd�}i} |D]�} |�| ��} | �d| | <�t | t&��rz tj| ��} | �d��| | <�b#t*t,t.f$r2} t�d| �d| �d| ����d| | <Yd} ~ ��d} ~ wwxYwt | t0��r| nd| | <��tj�����}gd�}d}d}t5|��D]�\}}|| vs| |�� tj| |d�����}||kr|dkr ||dz }|}n7�\#t*$r)t�d|�d| |����Y��wxYw|s|sd}d}||| d�S)aB Get the current prayer time status for a zone. Args: zone: Zone code (e.g., 'SGR01') Returns: Dictionary containing current prayer time information Raises: ValidationError: If zone format is invalid APIError: If the request fails rjrkz'Fetching current prayer time for zone: rlrmNrnrorprqrrr�r�ryzNo exact date match found for z. Using first available day.rz#No prayer times available for todayr�r�r�r�rRr zInvalid time format for r~rz)�current_prayer� next_prayerr�)r9r:rrAr�rgr�r�r�rEr�rrrr�r�rTryr_r�r�rYr�r�r[�time� enumerater�)r<rhrer��today� today_datarw� current_dayr�r�r�r�r�rIr�rnr�r��i�prayer� prayer_times r�get_current_prayerzHTTPClient.get_current_prayer�sx�����x�*�D�1�1� S�!�"Q�R�R� R�� � �D�d�D�D�E�E�E��]�]�5�*=�t�*=�*=�>�>�>�>�>�>�>�>�� �t�T� "� "� ��T�!�!��4� �?�D�1�1�"� � �?�L�L� ��d� #� #� ��L�L� �L�L�T�$�t�*�*�T�T�d�T�T� U� U� U��n�4�PT�:�:�K^�n�n�hl�n�n��� � � ���'�'� �3�3��� �!� � �D���~�~�$�(�(�6�"2�"2�e�";�";�!� ����� �"�,�.�.�,�K�$� � ���8�8�E�?�?�k�1�1�!%�J��E�2� � )�l� )� �N�N�T��T�T�T� � � �&�a��J�� G�� E�F�F� F�L�K�K� ��� � S� S�E�#����.�.�J��!�#��e� ���*�c�*�*� S�(�!�/� �;�;�B�#%�;�;�w�#7�#7�E�%�L�L��"�G�]�;�(�(�(��N�N�S�j�S�S�u�S�S�PQ�S�S����$(�E�%�L�L�L�L�L�L����� (����.8� �C�-H�-H�R�z�z�d��e� � ��l�n�n�!�!�#�#��G�G�G����� �"�7�+�+� U� U�I�A�v��U�"�"�e�F�m�&;�� U�&�/��f� �w�G�G�L�L�N�N� ���$�$��1�u�u�)0��Q����"(�K��E� %�� � U� U� U����S�&�S�S�E�&�M�S�S�T�T�T�T�T� U����� !�k� !�#�N� �K�-�&�!� � � s+�,H;�;J�(I?�?J�3AL<�<0M/�.M/)r$N)r$r#)rrrrr=r?rJr.r/rLr[rrrgrr r�rr�r�rrrr#r#<s,������7�7�R�R�R�R� ���� $� $� $��5�#4�����*C*�S�C*��C*�$�s�C�x�.�C*�C*�C*�C*�JJ�3�J�4� �3D�J�J�J�J�X=��d��=�=�=�=�~u �S�u �T�#�s�(�^�u �u �u �u �u �u rr#)%r�loggingr9r�typingrrrrrr r.�pydanticr r �modelsr r� getLoggerrrA�setLevel�DEBUG�handlers� StreamHandler�handler� setFormatter� Formatter� addHandlerrrDrrrr!r#rcrrr�<module>r�s+�������� � � � �������;�;�;�;�;�;�;�;�;�;�;�;�;�;�;�;� � � � �������������%�%�%�%�%�%�%�%� �� �8� $� $������ �������#�g�#�%�%�G� ������P�Q�Q���� ���g���� �G�C�y�!�!�!�� � � � � �y� � � �  � � � � �h� � � �  � � � � �H� � � �  � � � � �h� � � � } �} �} �} �} �} �} �} �B ������r

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/amanasmuei/mcp-server-malaysia-prayer-time'

If you have feedback or need assistance with the MCP directory API, please join our Discord server