o
    3i&1                     @   s  U d dl Z d dlZd dlZd dlZd dlmZ d dlmZmZmZ d dl	m
Z
 d dlmZ d dlmZmZmZmZmZ d dl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 eee e ee e!f f  Z"dZ#dZ$dZ%e&ej'ej(ej)dfg Z*e"e+d< de#fde$fde%ffD ]\Z,Z-e.ee,re*/ej0e1ee,e-f qg dZ2de3de3fddZ4eG dd dZ5G dd deZ6dWdee" dej7fddZ8	dWdee" dej7fd d!Z9e8 a:e9 a;da<ee" e+d"< d#a=dej7fd$d%Z>dej7fd&d'Z?dee" ddfd(d)Z@dXd*d+ZAdXd,d-ZBd.ZCd/ZDeCZEd0e ZFd1ee3 de3fd2d3ZG			4	5	dYd6e3d1ee3 d7eHd8e d9eej7 dejIfd:d;ZJd#d<d=ejId>e3d?eHdeejIef fd@dAZK		4	5dZd6e3d1ee3 d7eHd8e def
dBdCZL		4	5dZd6e3d1ee3 d7eHd8e def
dDdEZM		F	5d[dGe3dHe3d1ee3 dIe3d8e defdJdKZN		4	5dZd6e3d1ee3 d7eHd8e dejIf
dLdMZO			d\d6e3de3d1ee3 d8ee  dNee3 de5fdOdPZPG dQdR dReQZRG dSdT dTeRZSejTjUZVejTjWZXG dUdV dVe jYZZdS )]    N)	dataclass)datedatetimetimezone)GzipFile)BytesIO)AnyListOptionalTupleUnion)tzutc)HTTPAdapter)HTTPConnection)Retry)remove_trailing_slash)VERSION<         KEEP_ALIVE_SOCKET_OPTIONSTCP_KEEPIDLETCP_KEEPINTVLTCP_KEEPCNT)i  i  i  i  i  urlreturnc                 C   s   t dd| S )zKMask token values in URLs for safe logging, keeping first 10 chars visible.z(token=)([^&]{10})[^&]*z\1\2...)resub)r    r   ]/lsinfo/ai/hellotax_ai/llm_service/venv_embed/lib/python3.10/site-packages/posthog/request.py_mask_tokens_in_url0   s   r    c                   @   s6   e Zd ZU dZeed< dZee ed< dZ	e
ed< dS )GetResponsez.Response from a GET request with ETag support.dataNetagFnot_modified)__name__
__module____qualname____doc__r   __annotations__r#   r
   strr$   boolr   r   r   r   r!   5   s
   
 r!   c                       s<   e Zd ZdZdddee f fddZ fddZ  ZS )	HTTPAdapterWithSocketOptionsz-HTTPAdapter with configurable socket options.Nsocket_optionsr.   c                   s   || _ t j|i | d S N)r.   super__init__)selfr.   argskwargs	__class__r   r   r1   A   s   z%HTTPAdapterWithSocketOptions.__init__c                    s*   | j d ur
| j |d< t j|i | d S )Nr.   )r.   r0   init_poolmanager)r2   r3   r4   r5   r   r   r7   E   s   

z-HTTPAdapterWithSocketOptions.init_poolmanager)	r%   r&   r'   r(   r
   SocketOptionsr1   r7   __classcell__r   r   r5   r   r,   >   s    r,   r.   c                 C   s.   t tdddd| d}t }|d| |S )z;Build a session for general requests (batch, decide, etc.).   )totalconnectreadmax_retriesr.   https://)r,   r   requestsSessionmountr.   adaptersessionr   r   r   _build_sessionK   s   rG   c              	   C   s6   t tddddtdgd| d}t }|d| |S )a8  
    Build a session for feature flag requests with POST retries.

    Feature flag requests are idempotent (read-only), so retrying POST
    requests is safe. This session retries on transient server errors
    (408, 5xx) and network failures with exponential backoff
    (0.5s, 1s delays between retries).
    r:   g      ?POST)r;   r<   r=   backoff_factorstatus_forcelistallowed_methodsr>   r@   )r,   r   RETRY_STATUS_FORCELISTrA   rB   rC   rD   r   r   r   _build_flags_sessionZ   s   rM   _socket_optionsTc                   C      t rtS ttS r/   )_pooling_enabled_sessionrG   rN   r   r   r   r   _get_session{      rR   c                   C   rO   r/   )rP   _flags_sessionrM   rN   r   r   r   r   _get_flags_session   rS   rU   c                 C   s$   | t krdS | a t| at| adS )z
    Configure socket options for all HTTP connections.

    Example:
        from posthog import set_socket_options
        set_socket_options([(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)])
    N)rN   rG   rQ   rM   rT   r-   r   r   r   set_socket_options   s
   	rV   c                   C   s   t t dS )zDEnable TCP keepalive to prevent idle connections from being dropped.N)rV   r   r   r   r   r   enable_keep_alive   s   rW   c                   C   s   da dS )zGDisable connection reuse, creating a fresh connection for each request.FN)rP   r   r   r   r   disable_connection_reuse   s   rX   zhttps://us.i.posthog.comzhttps://eu.i.posthog.comzposthog-python/hostc                 C   s,   | pt }t|}|dv rtS |dkrtS |S )z"Determines the server host to use.)zhttps://app.posthog.comzhttps://us.posthog.comzhttps://eu.posthog.com)DEFAULT_HOSTr   US_INGESTION_ENDPOINTEU_INGESTION_ENDPOINT)rY   host_or_defaulttrimmed_hostr   r   r   determine_server_host   s   r_   F   api_keygziptimeoutrF   c                 K   s   t d}|}tjt d |d< t|pt| }	| |d< tj	|t
d}
|d|
|	 dtd}|r\d	|d
< t }t|dd}||
d W d   n1 sSw   Y  | }
|p`t j|	|
||d}|jdkrr|d |S )zPost the `kwargs` to the APIposthog)tzsentAtra   )clszmaking request: %s to url: %szapplication/json)zContent-Type
User-Agentrb   zContent-Encodingw)fileobjmodezutf-8N)r"   headersrc      data uploaded successfully)logging	getLoggerr   nowr   	isoformatr   rZ   jsondumpsDatetimeSerializerdebug
USER_AGENTr   r   writeencodegetvaluerR   poststatus_code)ra   rY   pathrb   rc   rF   r4   logbodyr   r"   rl   bufgzresr   r   r   r{      s*   





r{   )return_jsonr   success_messager   c          	      C   s@  t d}| jdkr:|| |r|  n| }t|tr8d|v r8t|d tr8d|d v r8|d t	| jd|S d }| j
d}|ryzt|}W n. ttfyx   zdd	lm} td
||ttj  }W n ttfyu   Y nw Y nw z|  }|d| t| j|d |d ttfy   t| j| j|dw )Nrd   rm   quotaLimitedfeature_flagsz[FEATURE FLAGS] PostHog feature flags quota limited, resetting feature flag data.  Learn more about billing limits at https://posthog.com/docs/billing/limits-alertszFeature flags quota limitedzRetry-Afterr   )parsedate_to_datetimeg        zreceived response: %sdetail)retry_after)ro   rp   r|   rv   rs   
isinstancedictlistwarningQuotaLimitErrorrl   getfloat
ValueError	TypeErroremail.utilsr   maxr   rq   r   utctotal_secondsAPIErrorKeyErrortext)	r   r   r   r~   responser   retry_after_headerr   payloadr   r   r   _process_response   sT   



r   c                 K   s$   t | |d||fi |}t|ddS )z+Post the `kwargs to the decide API endpointz/decide/?v=4z"Feature flags decided successfullyr   r{   r   ra   rY   rb   rc   r4   r   r   r   r   decide	  s   r   c                 K   s*   t | |d||fdt i|}t|ddS )zAPost the kwargs to the flags API endpoint with automatic retries.z/flags/?v=2rF   z$Feature flags evaluated successfullyr   )r{   rU   r   r   r   r   r   flags  s   	r    personal_api_keyproject_api_keykeyc                 C   s    t | d| d| ||}|jS )z<Get remote config flag value from remote_config API endpointz%/api/projects/@current/feature_flags/z/remote_config?token=)r   r"   )r   r   rY   r   rc   r   r   r   r   remote_config+  s   r   c                 K   s&   t | |d||fi |}t|dddS )z6Post the `kwargs` to the batch API endpoint for eventsz/batch/rn   F)r   r   r   r   r   r   r   
batch_post<  s   r   r#   c                 C   s   t d}t|p	t| }d|  td}|r||d< t j|||d}t|}	|jdkrD|	d|	 d |j
d	}
td
|
p@|ddS t|d|	 dd}|j
d	}
t||
ddS )a  
    Make a GET request with optional ETag support.

    If an etag is provided, sends If-None-Match header. Returns GetResponse with:
    - not_modified=True and data=None if server returns 304
    - not_modified=False and data=response if server returns 200
    rd   z	Bearer %s)Authorizationrh   zIf-None-Match)rl   rc   i0  zGET z returned 304 Not ModifiedETagNT)r"   r#   r$   z completed successfullyr   F)ro   rp   r   rZ   rw   rR   r   r    r|   rv   rl   r!   r   )ra   r   rY   rc   r#   r~   full_urlrl   r   
masked_urlresponse_etagr"   r   r   r   r   J  s    

r   c                   @   s:   e Zd Z	d	deeef dedee fddZdd Z	dS )
r   Nstatusmessager   c                 C   s   || _ || _|| _d S r/   )r   r   r   )r2   r   r   r   r   r   r   r1   r  s   
zAPIError.__init__c                 C   s   d}| | j| jS )Nz[PostHog] {0} ({1}))formatr   r   )r2   msgr   r   r   __str__y  s   zAPIError.__str__r/   )
r%   r&   r'   r   intr*   r
   r   r1   r   r   r   r   r   r   q  s    

r   c                   @   s   e Zd ZdS )r   N)r%   r&   r'   r   r   r   r   r   ~  s    r   c                   @   s   e Zd ZdefddZdS )ru   objc                 C   s$   t |ttfr| S tj| |S r/   )r   r   r   rr   rs   JSONEncoderdefault)r2   r   r   r   r   r     s   zDatetimeSerializer.defaultN)r%   r&   r'   r   r   r   r   r   r   ru     s    ru   r/   )r   N)NNFr`   N)NFr`   )Nr   r`   )NNN)[rs   ro   r   socketdataclassesr   r   r   r   rb   r   ior   typingr   r	   r
   r   r   rA   dateutil.tzr   requests.adaptersr   urllib3.connectionr   urllib3.util.retryr   posthog.utilsr   posthog.versionr   r   bytesr8   KEEPALIVE_IDLE_SECONDSKEEPALIVE_INTERVAL_SECONDSKEEPALIVE_PROBE_COUNTr   default_socket_options
SOL_SOCKETSO_KEEPALIVEr   r)   attrvaluehasattrappendSOL_TCPgetattrrL   r*   r    r!   r,   rB   rG   rM   rQ   rT   rN   rP   rR   rU   rV   rW   rX   r[   r\   rZ   rw   r_   r+   Responser{   r   r   r   r   r   r   	Exceptionr   r   
exceptionsTimeoutRequestsTimeoutConnectionErrorRequestsConnectionErrorr   ru   r   r   r   r   <module>   sL  
 




&
2




'