o
    i~d                     @   sp  d dl Z d dlZd dlZd dlZd dlZd dlmZmZ d dl	m	Z	 d dl
Z
ddlmZmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ d dlmZ dZdZdZde
jdeje fddZdedefddZdedefddZ de
jdeje fddZ!de
j"de#defddZ$de
j"de%fddZ&d e'd!eje' de'fd"d#Z(d$ejej) d%eje d&eje% dejej) fd'd(Z*d)ej+e'ejej) f d*ejej) dej+e'ej)f fd+d,Z,d$ejej) d-eje d*ejej) dejej) fd.d/Z-d0ejej) d$ejej) d-eje d*ejej) dej.ejej) ejej) f f
d1d2Z/G d3d4 d4Z0G d5d6 d6Z1dS )7    N)asynccontextmanagercontextmanager)random   )File!convert_file_dict_to_httpx_tuples)FORCE_MULTIPART)jsonable_encoder)encode_query)remove_none_from_dict)RequestOptions)RequestFilesg      ?g      N@g?response_headersreturnc                 C   s   |  d}|dur!z|dkrt|d W S dW S  ty    Y nw |  d}|du r,dS td|r7t|}n,tj|}|du rCdS |d du rW|dd d |d	d  }tj	|}|t

  }|dk rid}|S )
z
    This function parses the `Retry-After` header in a HTTP response and returns the number of seconds to wait.

    Inspired by the urllib3 retry implementation.
    zretry-after-msNr   i  zretry-afterz^\s*[0-9]+\s*$	   )r   
   )getint	Exceptionrematchfloatemailutilsparsedate_tz	mktime_tztime)r   retry_after_msretry_aftersecondsretry_date_tuple
retry_date r"   M/home/ubuntu/.local/lib/python3.10/site-packages/deepgram/core/http_client.py_parse_retry_after   s,   


r$   delayc                 C   s   dt  t  }| | S )z7Add positive jitter (0-20%) to prevent thundering herd.r   r   JITTER_FACTORr%   jitter_multiplierr"   r"   r#   _add_positive_jitterB   s   r*   c                 C   s   dt  d t  }| | S )u5   Add symmetric jitter (±10%) for exponential backoff.r   g      ?r&   r(   r"   r"   r#   _add_symmetric_jitterH   s   r+   c              	   C   sX   |  d}|du rdS zt|}|t  }|dkr|W S W dS  ttfy+   Y dS w )z
    Parse the X-RateLimit-Reset header (Unix timestamp in seconds).
    Returns seconds to wait, or None if header is missing/invalid.
    zx-ratelimit-resetNr   )r   r   r   
ValueError	TypeError)r   reset_time_str
reset_timer%   r"   r"   r#   _parse_x_ratelimit_resetN   s   
r0   responseretriesc                 C   s`   t | j}|dur|dkrt|tS t| j}|dur"tt|tS tttd| t}t|S )a  
    Determine the amount of time to wait before retrying a request.
    This function begins by trying to parse a retry-after header from the response, and then proceeds to use exponential backoff
    with a jitter to determine the number of seconds to wait.
    Nr   g       @)	r$   headersminMAX_RETRY_DELAY_SECONDSr0   r*   INITIAL_RETRY_DELAY_SECONDSpowr+   )r1   r2   r   ratelimit_resetbackoffr"   r"   r#   _retry_timeoutb   s   


r:   c                 C   s   g d}| j dkp| j |v S )N)i  i  i  i  )status_code)r1   retryable_400sr"   r"   r#   _should_retryx   s   r=   base_urlpathc                 C   s"   |s| S |  d d|d S )a  
    Build a full URL by joining a base URL with a path.

    This function correctly handles base URLs that contain path prefixes (e.g., tenant-based URLs)
    by using string concatenation instead of urllib.parse.urljoin(), which would incorrectly
    strip path components when the path starts with '/'.

    Example:
        >>> _build_url("https://cloud.example.com/org/tenant/api", "/users")
        'https://cloud.example.com/org/tenant/api/users'

    Args:
        base_url: The base URL, which may contain path prefixes.
        path: The path to append. Can be None or empty string.

    Returns:
        The full URL with base_url and path properly joined.
    /)rstriplstrip)r>   r?   r"   r"   r#   
_build_url}   s   rC   datarequest_filesforce_multipartc                 C   s(   | durt | tjr|s|rt| S | S )z
    Filter None values from data body for multipart/form requests.
    This prevents httpx from converting None to empty strings in multipart encoding.
    Only applies when files are present or force_multipart is True.
    N)
isinstancetypingMappingr   )rD   rE   rF   r"   r"   r#   &_maybe_filter_none_from_multipart_data   s   
rJ   originalomitc                 C   s6   |d u r| S i }|   D ]\}}||ur|||< q|S N)items)rK   rL   newkeyvaluer"   r"   r#   remove_omit_from_dict   s   rR   request_optionsc                 C   sv   | d u r|d urt |di pi S d S t| tjs t | }|S i t t| ||d ur6t |di p5i ni }|S Nadditional_body_parameters)r	   r   rG   rH   rI   rR   )rD   rS   rL   data_contentr"   r"   r#   maybe_filter_request_body   s$   
rW   jsonc                 C   sx   d }d }|d urt |||}nt | ||}t|d uo|d}|i kr,| d u r,|s,d }|i kr8|d u r8|s8d }||fS rT   )rW   boolr   )rX   rD   rS   rL   	json_body	data_bodyhas_additional_body_parametersr"   r"   r#   get_request_body   s   r]   c                    @   s  e Zd Zdddejdejg eje f dejg ej	e
e
f f dejejg e
f  fddZd	eje
 d
e
fddZ	ddddddddddddddeje
 de
deje
 dejej	e
ejf  dejej dejej dejejeeje eje f  dejejej	e
ejejeeje f  f ejeje
ef  f  dejej	e
ejf  deje dedejej deje d
ejfddZe	ddddddddddddddeje
 de
deje
 dejej	e
ejf  dejej dejej dejejeeje eje f  dejejej	e
ejejeeje f  f ejeje
ef  f  dejej	e
ejf  deje dedejej deje d
ejej fddZdS ) 
HttpClientN)r>   httpx_clientbase_timeoutbase_headersr>   c                C   s   || _ || _|| _|| _d S rM   )r>   r`   ra   r_   )selfr_   r`   ra   r>   r"   r"   r#   __init__   s   
zHttpClient.__init__maybe_base_urlr   c                 C   2   |}| j d ur|d u r|   }|d u rtd|S NzNA base_url is required to make this request, please provide one and try again.r>   r,   rb   rd   r>   r"   r"   r#   get_base_url      zHttpClient.get_base_urlr   r>   paramsrX   rD   contentfilesr3   rS   r2   rL   rF   r?   methodrl   rX   rD   rm   rn   r3   rS   r2   rL   rF   c                C   s  |  |}|
d ur|
dd ur|
dn|  }t|||
|d\}}|d ur9||ur9t|tr9ttt||nd }|d u sEt	|dkrI|rIt
}t|||}tttti |d urZ|ni |
d urh|
di pgi ni |}| jj|t||tti |  |	d ur|	ni |
d ur|
di pi ni |r|nd |||||d	}|
d ur|
ddnd}t|d	r||k rtt||d
 | j||||||||	|
|d |dS |S )Ntimeout_in_secondsrX   rD   rS   rL   r   additional_query_parametersadditional_headers	ro   urlr3   rl   rX   rD   rm   rn   timeoutmax_retries   r1   r1   r2   r   r?   ro   r>   rl   rX   rm   rn   r3   rS   r2   rL   )ri   r   r`   r]   rG   dictr   rR   r   lenr   rJ   r
   r	   r_   requestrC   ra   r=   r   sleepr:   )rb   r?   ro   r>   rl   rX   rD   rm   rn   r3   rS   r2   rL   rF   rv   rZ   r[   rE   _encoded_paramsr1   rw   r"   r"   r#   r~      s   

 
	
zHttpClient.requestc                c   sn   |  |}|
d ur|
dd ur|
dn|  }|d ur0||ur0t|tr0ttt||nd }|d u s<t|dkr@|r@t	}t
|||
|d\}}t|||}tttti |d ur[|ni |
d urg|
di ni |}| jj|t||tti |  |	d ur|	ni |
d ur|
di ni |r|nd |||||d	}|V  W d    d S 1 sw   Y  d S )Nrp   r   rq   rr   rs   rt   )ri   r   r`   rG   r|   r   rR   r   r}   r   r]   rJ   r
   r	   r_   streamrC   ra   )rb   r?   ro   r>   rl   rX   rD   rm   rn   r3   rS   r2   rL   rF   rv   rE   rZ   r[   r   r   r"   r"   r#   r   f  sl   


	"zHttpClient.streamrM   )__name__
__module____qualname__httpxClientrH   CallableOptionalr   Dictstrrc   ri   AnyUnionbytesIteratorAsyncIteratorr   ListTupler   r   rY   Responser~   r   r   r"   r"   r"   r#   r^      s    


 	
"

f

 	
"

r^   c                    @   s  e Zd Zddddejdejg eje f dejg ej	e
e
f f dejejg e
f  dejejg ejej	e
e
f  f  f
dd	Zd
ej	e
e
f fddZdeje
 d
e
fddZ	d"dddddddddddddeje
 de
deje
 dejej	e
ejf  dejej dejej dejejeeje eje f  dejejej	e
ejejeeje f  f ejeje
ef  f  dejej	e
ejf  deje dedejej deje d
ejfddZe	d"dddddddddddddeje
 de
deje
 dejej	e
ejf  dejej dejej dejejeeje eje f  dejejej	e
ejejeeje f  f ejeje
ef  f  dejej	e
ejf  deje dedejej deje d
ejej fd d!ZdS )#AsyncHttpClientN)r>   async_base_headersr_   r`   ra   r>   r   c                C   s"   || _ || _|| _|| _|| _d S rM   )r>   r`   ra   r   r_   )rb   r_   r`   ra   r>   r   r"   r"   r#   rc     s
   	
zAsyncHttpClient.__init__r   c                    s"   | j d ur|   I d H S |  S rM   )r   ra   )rb   r"   r"   r#   _get_headers  s   
zAsyncHttpClient._get_headersrd   c                 C   re   rf   rg   rh   r"   r"   r#   ri     rj   zAsyncHttpClient.get_base_urlr   rk   r?   ro   rl   rX   rD   rm   rn   r3   rS   r2   rL   rF   c                   s  |  |}|
d ur|
dd ur|
dn|  }|d ur0||ur0t|tr0ttt||nd }|d u s<t|dkr@|r@t	}t
|||
|d\}}t|||}|  I d H }tttti |d urb|ni |
d urp|
di poi ni |}| jj|t||tti ||	d ur|	ni |
d ur|
di pi ni |r|nd |||||d	I d H }|
d ur|
ddnd}t|d	r||k rtt||d
I d H  | j||||||||	|
|d |dI d H S |S )Nrp   r   rq   rr   rs   rt   rw   rx   ry   rz   r   r{   )ri   r   r`   rG   r|   r   rR   r   r}   r   r]   rJ   r   r
   r	   r_   r~   rC   r=   asyncior   r:   )rb   r?   ro   r>   rl   rX   rD   rm   rn   r3   rS   r2   rL   rF   rv   rE   rZ   r[   _headersr   r1   rw   r"   r"   r#   r~     s   

 
	
zAsyncHttpClient.requestc                C  s  |  |}|
d ur|
dd ur|
dn|  }|d ur0||ur0t|tr0ttt||nd }|d u s<t|dkr@|r@t	}t
|||
|d\}}t|||}|  I d H }tttti |d urb|ni |
d urn|
di ni |d}| jj|t||tti ||	d ur|	ni |
d ur|
di ni |r|nd |||||d	4 I d H }|V  W d   I d H  d S 1 I d H sw   Y  d S )Nrp   r   rq   rr   )rL   rs   rt   )ri   r   r`   rG   r|   r   rR   r   r}   r   r]   rJ   r   r
   r	   r_   r   rC   )rb   r?   ro   r>   rl   rX   rD   rm   rn   r3   rS   r2   rL   rF   rv   rE   rZ   r[   r   r   r   r"   r"   r#   r   B  sn   


	.zAsyncHttpClient.streamrM   )r   r   r   r   AsyncClientrH   r   r   r   r   r   	Awaitablerc   r   ri   r   r   r   r   r   r   r   r   r   r   rY   r   r~   r   r   r"   r"   r"   r#   r     s    "


 	
"

i

 	
"

r   )2r   email.utilsr   r   r   rH   
contextlibr   r   r   r   filer   r   rF   r   r	   query_encoderr
   r   rS   r   httpx._typesr   r6   r5   r'   Headersr   r   r$   r*   r+   r0   r   r   r:   rY   r=   r   rC   r   rJ   r   rR   rW   r   r]   r^   r   r"   r"   r"   r#   <module>   s   )












 S