22import base64
33import itertools
44import json
5+ import time
56import threading
67from collections .abc import Mapping
78from typing import Callable
@@ -96,6 +97,8 @@ def __init__(self):
9697 self ._objects = {}
9798 self ._cache = {}
9899
100+ next (self ._request_id ) # make sure first id is 1, in case 0 is interpreted as None
101+
99102 def _call_data (self , id , prop , args , ignore_result = False ):
100103 buffer = []
101104 args = self ._dump_data (args , buffer )
@@ -313,7 +316,11 @@ async def _on_message_async(self, message: str):
313316 self ._requests [request_id ] = self ._load_data (data .get ("value" , None ))
314317 if key and data .get ("cache" , False ):
315318 self ._cache [key ] = self ._requests [request_id ]
316- event .set ()
319+
320+ if isinstance (event , asyncio .Future ):
321+ event .set_result (self ._requests [request_id ])
322+ else :
323+ event .set ()
317324 return
318325
319326 case "call" :
@@ -407,11 +414,10 @@ def _on_message(self, message: str):
407414
408415
409416class PyodideLink (LinkBase ):
410- def __init__ (self , send_message , size_buffer , result_buffer ):
417+ def __init__ (self , send_message ):
411418 super ().__init__ ()
412419 self ._send_message = send_message
413- self ._size_buffer = size_buffer
414- self ._result_buffer = result_buffer
420+ self ._requests = {}
415421
416422 def create_proxy (self , func , ignore_return_value = False ):
417423 id_ = id (func )
@@ -424,26 +430,23 @@ def create_proxy(self, func, ignore_return_value=False):
424430 }
425431
426432 def _send_data (self , metadata , data , key = None ):
427- if type (data ) is bytes :
428- self ._send_message (data )
429- else :
430- if (
431- metadata .get ("request_id" , None ) is not None
432- and metadata ["type" ] != "response"
433- and not metadata .get ("ignore_return_value" , False )
434- ):
435- import js
436-
437- js .Atomics .store (self ._size_buffer , 0 , 0 )
438- self ._send_message (data )
439- js .Atomics .wait (self ._size_buffer , 0 , 0 , 10000 )
440- n = self ._size_buffer [0 ]
441- res = bytes (self ._result_buffer .slice (0 , n ))
442- s = res .decode ("utf-8" )
443- data = json .loads (s )
444- return self ._load_data (data .get ("value" , None ))
445- else :
446- self ._send_message (data )
433+ """Send data to the remote environment,
434+ if request_id is set, (blocking-)wait for the response and return it"""
435+ request_id = metadata .get ("request_id" , None )
436+ type = metadata .get ("type" , None )
437+ event = None
438+ self ._send_message (data )
439+ if type != "response" and request_id is not None :
440+ # from pyodide.ffi import run_sync
441+ import asyncio
442+ event = asyncio .Future ()
443+ self ._requests [request_id ] = event , key
444+ # todo: this shouldn't be necessary
445+ # but run_sync(event) gives an error
446+ while not event .done ():
447+ time .sleep (0.001 )
448+
449+ return self ._requests .pop (request_id )
447450
448451
449452class LinkBaseAsync (LinkBase ):
0 commit comments