U
    —ùi37  ã                   @  sð  U d Z ddlmZ ddlZddlZddlmZ ddlmZ ddl	m
Z
mZ ddlZddlmZmZmZmZ e
rzddlmZ d	d
lmZ d	dlmZ dZdZdZdZdZeeƒ d¡jdd�Z G dd„ de!ƒZ"G dd„ de"ƒZ#G dd„ de"ƒZ$dddœdd„Z%G dd „ d ej&ƒZ'G d!d"„ d"ƒZ(d#d$œd%d&„Z)d#d$œd'd(„Z*d#d$œd)d*„Z+d#d$œd+d,„Z,dZ-d-e.d.< e,ƒ �rˆe*ƒ �rˆe)ƒ �sˆe+ƒ �sˆe(ƒ Z-ndZ-d/d0d1œd2d3„Z/d4a0d5d$œd6d7„Z1d4a2d5d$œd8d9„Z3d/d:d1œd;d<„Z4d=d$œd>d?„Z5d#d$œd@dA„Z6dS )BaÓ  
Support for streaming http requests in emscripten.

A few caveats -

Firstly, you can't do streaming http in the main UI thread, because atomics.wait isn't allowed.
Streaming only works if you're running pyodide in a web worker.

Secondly, this uses an extra web worker and SharedArrayBuffer to do the asynchronous fetch
operation, so it requires that you have crossOriginIsolation enabled, by serving over https
(or from localhost) with the two headers below set:

    Cross-Origin-Opener-Policy: same-origin
    Cross-Origin-Embedder-Policy: require-corp

You can tell if cross origin isolation is successfully enabled by looking at the global crossOriginIsolated variable in
javascript console. If it isn't, streaming requests will fallback to XMLHttpRequest, i.e. getting the whole
request into a buffer and then returning it. it shows a warning in the javascript console in this case.

Finally, the webworker which does the streaming fetch is created on initial import, but will only be started once
control is returned to javascript. Call `await wait_for_streaming_ready()` to wait for streaming fetch.

NB: in this code, there are a lot of javascript objects. They are named js_*
to make it clear what type of object they are.
é    )ÚannotationsN)ÚParser)Úfiles)ÚTYPE_CHECKINGÚAny)ÚJsArrayÚJsExceptionÚJsProxyÚto_js)ÚBufferé   )ÚEmscriptenRequest)ÚEmscriptenResponse)z
user-agentéÿÿÿÿéþÿÿÿéýÿÿÿéüÿÿÿzemscripten_fetch_worker.jszutf-8)Úencodingc                      s0   e Zd Zd	dddœddddœ‡ fdd„Z‡  ZS )
Ú_RequestErrorN©ÚrequestÚresponsez
str | NonezEmscriptenRequest | NoneúEmscriptenResponse | None)Úmessager   r   c                  s$   || _ || _|| _tƒ  | j¡ d S ©N)r   r   r   ÚsuperÚ__init__)Úselfr   r   r   ©Ú	__class__© úD/tmp/pip-unpacked-wheel-z24cd2a5/urllib3/contrib/emscripten/fetch.pyr   C   s    z_RequestError.__init__)N)Ú__name__Ú
__module__Ú__qualname__r   Ú__classcell__r    r    r   r!   r   B   s
    þûr   c                   @  s   e Zd ZdS )Ú_StreamingErrorN©r"   r#   r$   r    r    r    r!   r&   P   s   r&   c                   @  s   e Zd ZdS )Ú_TimeoutErrorNr'   r    r    r    r!   r(   T   s   r(   zdict[str, Any]r	   )Údict_valÚreturnc                 C  s   t | tjjd�S )N)Zdict_converter)r
   ÚjsZObjectZfromEntries)r)   r    r    r!   Ú_obj_from_dictX   s    r,   c                      s¢   e Zd Zdddddddœdd„Zd	d
œdd„Zdd
œdd„Zedd
œdd„ƒZd	d
œ‡ fdd„Zdd
œdd„Z	dd
œdd„Z
dd
œdd„Zdddœdd„Z‡  ZS )Ú_ReadStreamr   Úfloatr	   Úintr   )Ú
int_bufferÚbyte_bufferÚtimeoutÚworkerÚconnection_idr   c                 C  sT   || _ || _d| _d| _|| _|| _|dkr8td| ƒnd | _d| _d| _	|| _
d S )Nr   éè  TF)r0   r1   Úread_posÚread_lenr4   r3   r/   r2   Úis_liveÚ
_is_closedr   )r   r0   r1   r2   r3   r4   r   r    r    r!   r   ]   s    	z_ReadStream.__init__ÚNone©r*   c                 C  s   |   ¡  d S r   )Úclose©r   r    r    r!   Ú__del__q   s    z_ReadStream.__del__Úboolc                 C  s   | j S r   )r9   r=   r    r    r!   Ú	is_closedu   s    z_ReadStream.is_closedc                 C  s   |   ¡ S r   )r@   r=   r    r    r!   Úclosedy   s    z_ReadStream.closedc                   s\   |   ¡ sXd| _d| _d | _d | _d| _d | _| jrN| j 	t
d| jiƒ¡ d| _tƒ  ¡  d S )Nr   Tr<   F)r@   r7   r6   r0   r1   r9   r   r8   r3   ÚpostMessager,   r4   r   r<   r=   r   r    r!   r<   }   s    z_ReadStream.closec                 C  s   dS ©NTr    r=   r    r    r!   ÚreadableŠ   s    z_ReadStream.readablec                 C  s   dS ©NFr    r=   r    r    r!   Úwritable�   s    z_ReadStream.writablec                 C  s   dS rE   r    r=   r    r    r!   Úseekable�   s    z_ReadStream.seekabler   )Úbyte_objr*   c                 C  s>  | j std| jd d�‚| jdkràtj | j dt¡ | j 	t
d| jiƒ¡ tj | j dt| j¡dkrft‚| j d }|dkr†|| _d| _nZ|tkrÎ| j d }tj ¡ }| | j d|¡¡}td|› �| jd d�‚nd| _|  ¡  dS t| jtt|ƒƒƒ}| j | j| j| ¡ ¡ }|t|ƒd|…< |  j|8  _|  j|7  _|S )	Nz,No buffer for stream in _ReadStream.readintor   r   ZgetMorez	timed-outr   úException thrown in fetch: F)r0   r&   r   r7   r+   ÚAtomicsÚstoreÚERROR_TIMEOUTr3   rB   r,   r4   Úwaitr2   r(   r6   ÚERROR_EXCEPTIONÚTextDecoderÚnewÚdecoder1   Úslicer8   r<   ÚminÚlenÚ
memoryviewÚsubarrayÚto_py)r   rH   Zdata_lenÚ
string_lenÚ
js_decoderÚjson_strZ
ret_lengthrV   r    r    r!   Úreadinto“   sN    ý
ÿÿ


ý ÿz_ReadStream.readinto)r"   r#   r$   r   r>   r@   ÚpropertyrA   r<   rD   rF   rG   r[   r%   r    r    r   r!   r-   \   s   r-   c                   @  s*   e Zd Zddœdd„Zdddœdd	„Zd
S )Ú_StreamingFetcherr:   r;   c                   sd   dˆ _ tj tgtddiƒ¡}ddddœ‡ fdd„}tj |¡}tjj	 |¡ˆ _
tjj |¡ˆ _d S )	NFÚtypezapplication/javascriptr	   r:   )Újs_resolve_fnÚjs_reject_fnr*   c                   s>   dddœ‡‡fdd„}dddœ‡ fdd„}|ˆj _|ˆj _d S )Nr	   r:   )Úer*   c                   s   dˆ_ ˆ | ƒ d S rC   )Ústreaming_ready©ra   )r_   r   r    r!   ÚonMsgÌ   s    zC_StreamingFetcher.__init__.<locals>.promise_resolver.<locals>.onMsgc                   s   ˆ | ƒ d S r   r    rc   )r`   r    r!   ÚonErrÐ   s    zC_StreamingFetcher.__init__.<locals>.promise_resolver.<locals>.onErr)Ú	js_workerZ	onmessageÚonerror)r_   r`   rd   re   r=   )r`   r_   r!   Úpromise_resolverË   s    z4_StreamingFetcher.__init__.<locals>.promise_resolver)rb   r+   ÚBlobrP   Ú_STREAMING_WORKER_CODEr,   ÚURLZcreateObjectURLZ
globalThisÚWorkerrf   ZPromiseÚjs_worker_ready_promise)r   Zjs_data_blobrh   Zjs_data_urlr    r=   r!   r   Ã   s     
ÿz_StreamingFetcher.__init__r   r   ©r   r*   c                 C  s´  dd„ |j  ¡ D ƒ}|j}|t|ƒ|jdœ}|jdkrDtd|j ƒnd }tj 	d¡}tj
 	|¡}tj 	|d¡}tj |dt¡ tj |d¡ tj 	|jtj¡j}	| j t||	|dœƒ¡ tj |dt|¡ |d tkrætd	|d d
�‚nÊ|d tk�rP|d }
tj 	¡ }| | d|
¡¡}t |¡}t||d |d t |||j| j|d |ƒd�S |d t!k�r˜|d }
tj 	¡ }| | d|
¡¡}t"d|› �|d d
�‚nt"d|d › �|d d
�‚d S )Nc                 S  s   i | ]\}}|t kr||“qS r    )ÚHEADERS_TO_IGNORE)Ú.0ÚkÚvr    r    r!   Ú
<dictcomp>Û   s      z*_StreamingFetcher.send.<locals>.<dictcomp>)ÚheadersÚbodyÚmethodr   r5   i   é   )ÚbufferÚurlZfetchParamsz'Timeout connecting to streaming requestr   r   Ústatusrt   ZconnectionID)r   Ústatus_codert   ru   rI   z%Unknown status from worker in fetch: )#rt   Úitemsru   r
   rv   r2   r/   r+   ZSharedArrayBufferrP   Z
Int32ArrayZ
Uint8ArrayrJ   rK   rL   Únotifyrk   ry   ÚlocationÚhrefrf   rB   r,   rM   r(   ÚSUCCESS_HEADERrO   rQ   rR   ÚjsonÚloadsr   r-   rN   r&   )r   r   rt   ru   Z
fetch_datar2   Zjs_shared_bufferZjs_int_bufferZjs_byte_bufferZjs_absolute_urlrX   rY   rZ   Zresponse_objr    r    r!   ÚsendÚ   sv    ÿýÿÿ
ý

úü
  ÿýz_StreamingFetcher.sendN)r"   r#   r$   r   rƒ   r    r    r    r!   r]   Â   s   r]   r?   r;   c                   C  s    t tdƒot tdƒotjtjkS )NÚwindowr   )Úhasattrr+   r   r„   r    r    r    r!   Úis_in_browser_main_thread$  s    r†   c                   C  s   t tdƒotjS )NÚcrossOriginIsolated)r…   r+   r‡   r    r    r    r!   Úis_cross_origin_isolated(  s    rˆ   c                   C  s2   t tdƒo0t tjdƒo0t tjjdƒo0tjjjdkS )NÚprocessÚreleaseÚnameÚnode)r…   r+   r‰   rŠ   r‹   r    r    r    r!   Ú
is_in_node,  s    

ÿþür�   c                   C  s   t tdƒot tdƒS )Nrl   ri   )r…   r+   r    r    r    r!   Úis_worker_available5  s    rŽ   z_StreamingFetcher | NoneÚ_fetcherr   r   rn   c                 C  s"   t rtƒ rt  | ¡S tƒ  d S d S r   )r�   rb   rƒ   Ú_show_streaming_warning©r   r    r    r!   Úsend_streaming_requestD  s    

r’   Fr:   c                  C  s   t sda d} tj | ¡ d S )NTz8Warning: Timeout is not available on main browser thread)Ú_SHOWN_TIMEOUT_WARNINGr+   ÚconsoleÚwarn)r   r    r    r!   Ú_show_timeout_warningO  s    r–   c                  C  sb   t s^da d} tƒ s| d7 } tƒ r(| d7 } tƒ s6| d7 } tƒ dkrH| d7 } dd	lm} | | ¡ d S )
NTz%Can't stream HTTP requests because: 
z$  Page is not cross-origin isolated
z+  Python is running in main browser thread
z> Worker or Blob classes are not available in this environment.Fz² Streaming fetch worker isn't ready. If you want to be sure that streaming fetch
is working, you need to call: 'await urllib3.contrib.emscripten.fetch.wait_for_streaming_ready()`r   )r”   )Ú_SHOWN_STREAMING_WARNINGrˆ   r†   rŽ   rb   r+   r”   r•   )r   r”   r    r    r!   r�   Z  s    
r�   r   c              
   C  sL  zÜt j ¡ }tƒ s0d|_| jrFt| jd ƒ|_n| d¡ | jrFtƒ  | 	| j
| jd¡ | j ¡ D ] \}}| ¡ tkrb| ||¡ qb| t| jƒ¡ ttƒ  | ¡ ¡ƒ}tƒ s¾|j ¡  ¡ }n|j d¡}t|j||| d�W S  tk
�rF } zJ|jdk�rt |j!| d�‚n*|jd	k�r(t"|j!| d�‚nt"|j!| d�‚W 5 d }~X Y nX d S )
NZarraybufferr5   ztext/plain; charset=ISO-8859-15FzISO-8859-15)r{   rt   ru   r   ÚTimeoutErrorr‘   ZNetworkError)#r+   ZXMLHttpRequestrP   r†   ZresponseTyper2   r/   ZoverrideMimeTyper–   Úopenrv   ry   rt   r|   Úlowerro   ZsetRequestHeaderrƒ   r
   ru   Údictr   ÚparsestrZgetAllResponseHeadersr   rW   ÚtobytesÚencoder   rz   r   r‹   r(   r   r   )r   Zjs_xhrr‹   Úvaluert   ru   Úerrr    r    r!   Úsend_requestm  s<    

   ÿr¡   zbool | Nonec                   C  s   t r
t jS d S d S r   )r�   rb   r    r    r    r!   rb   –  s    rb   c                   Ã  s   t rt jI d H  dS dS d S )NTF)r�   rm   r    r    r    r!   Úwait_for_streaming_ready�  s    r¢   )7Ú__doc__Ú
__future__r   Úior�   Úemail.parserr   Úimportlib.resourcesr   Útypingr   r   r+   Zpyodide.ffir   r   r	   r
   Ztyping_extensionsr   r   r   r   r   ro   r€   ZSUCCESS_EOFrL   rN   Ú__package__ÚjoinpathÚ	read_textrj   Ú	Exceptionr   r&   r(   r,   Ú	RawIOBaser-   r]   r†   rˆ   r�   rŽ   r�   Ú__annotations__r’   r“   r–   r—   r�   r¡   rb   r¢   r    r    r    r!   Ú<module>   sf   ÿþÿfb	ÿÿþ)