def test_rpc(): a0.File.remove("foo.rpc.a0") assert not os.path.exists("/dev/shm/alephzero/foo.rpc.a0") cv = threading.Condition() class State: requests = [] cancels = [] replies = [] def onrequest(req): with cv: State.requests.append(req.pkt.payload) if req.pkt.payload == b"reply": req.reply(b"reply") if req.pkt.payload.startswith(b"sleep"): time.sleep(0.2) req.reply(b"slept") cv.notify() def oncancel(id): with cv: State.cancels.append(id) cv.notify() server = a0.RpcServer("foo", onrequest, oncancel) assert os.path.exists("/dev/shm/alephzero/foo.rpc.a0") def onreply(pkt): with cv: State.replies.append(pkt.payload) cv.notify() client = a0.RpcClient("foo") client.send("reply", onreply) client.send("reply", onreply) pkt = a0.Packet("cancel") client.send(pkt, onreply) client.cancel(pkt.id) with cv: cv.wait_for(lambda: (len(State.requests) == 3 and len(State.cancels) == 1 and len(State.replies) == 2)) reply = client.send_blocking("sleep") assert reply.payload == b"slept" reply = client.send_blocking("sleep", timeout=a0.TimeMono.now() + 0.3) assert reply.payload == b"slept" with pytest.raises(RuntimeError, match="Connection timed out"): client.send_blocking("sleep", timeout=a0.TimeMono.now() + 0.1)
async def test_rpc(sandbox): await sandbox.WaitUntilStartedAsync(timeout=1.0) ns = types.SimpleNamespace() ns.collected_requests = [] def on_request(req): ns.collected_requests.append(req.pkt.payload.decode("utf-8")) req.reply(f"success_{len(ns.collected_requests)}") tm = a0.TopicManager({"container": "aaa"}) topic = tm.rpc_server_topic("bbb") server = a0.RpcServer(topic, on_request, None) # noqa: F841 async with aiohttp.ClientSession() as session: endpoint = "http://localhost:24880/api/rpc" rpc_data = { "container": "aaa", "topic": "bbb", "packet": { "payload": "", }, } # Normal request. rpc_data["packet"]["payload"] = base64.b64encode(b"request_0").decode( "utf-8") async with session.post(endpoint, data=json.dumps(rpc_data)) as resp: assert resp.status == 200 resp_pkt = await resp.json() assert base64.b64decode(resp_pkt.get("payload", "")) == b"success_1" # Normal request. rpc_data["packet"]["payload"] = base64.b64encode(b"request_1").decode( "utf-8") async with session.post(endpoint, data=json.dumps(rpc_data)) as resp: assert resp.status == 200 resp_pkt = await resp.json() assert base64.b64decode(resp_pkt.get("payload", "")) == b"success_2" # Missing "container". rpc_data.pop("container") async with session.post(endpoint, data=json.dumps(rpc_data)) as resp: assert resp.status == 400 assert await resp.text() == "Missing required 'container' field." rpc_data["container"] = "aaa" # Missing "topic". rpc_data.pop("topic") async with session.post(endpoint, data=json.dumps(rpc_data)) as resp: assert resp.status == 400 assert await resp.text() == "Missing required 'topic' field." rpc_data["topic"] = "bbb" # Not JSON. async with session.post(endpoint, data="not json") as resp: assert resp.status == 400 assert await resp.text() == "Body must be json." # Not JSON object. async with session.post(endpoint, data=json.dumps("not object")) as resp: assert resp.status == 400 assert await resp.text() == "Body must be a json object." assert ns.collected_requests == ["request_0", "request_1"]
def test_rpc(sandbox): ns = types.SimpleNamespace() ns.collected_requests = [] def on_request(req): ns.collected_requests.append(req.pkt.payload) req.reply(f"success_{len(ns.collected_requests) - 1}") server = a0.RpcServer("mytopic", on_request, None) endpoint = f"http://localhost:{os.environ['PORT_STR']}/api/rpc" rpc_data = { "topic": "mytopic", "packet": { "payload": "", }, } # Normal request. rpc_data["packet"]["payload"] = "request_0" resp = requests.post(endpoint, data=json.dumps(rpc_data)) assert resp.status_code == 200 assert sorted([k for k, v in resp.json()["headers"]]) == [ "a0_dep", "a0_req_id", "a0_rpc_type", "a0_time_mono", "a0_time_wall", "a0_transport_seq", "a0_writer_id", "a0_writer_seq", ] assert resp.json()["payload"] == "success_0" # Missing "topic". rpc_data.pop("topic") resp = requests.post(endpoint, data=json.dumps(rpc_data)) assert resp.status_code == 400 assert resp.text == "Request missing required field: topic" rpc_data["topic"] = "mytopic" # Not JSON. resp = requests.post(endpoint, data="not json") assert resp.status_code == 400 assert resp.text == "Request must be json." # Not JSON object. resp = requests.post(endpoint, data=json.dumps("not object")) assert resp.status_code == 400 assert resp.text == "Request must be a json object." # Base64 Request Encoding. rpc_data["packet"]["payload"] = btoa("request_1") rpc_data["request_encoding"] = "base64" resp = requests.post(endpoint, data=json.dumps(rpc_data)) assert resp.status_code == 200 assert resp.json()["payload"] == "success_1" del rpc_data["request_encoding"] # Base64 Response Encoding. print("Base64 Response Encoding.", flush=True, file=sys.stderr) rpc_data["packet"]["payload"] = "request_2" rpc_data["response_encoding"] = "base64" resp = requests.post(endpoint, data=json.dumps(rpc_data)) assert resp.status_code == 200 assert atob(resp.json()["payload"]) == "success_2" assert ns.collected_requests == [b"request_0", b"request_1", b"request_2"]
import a0 import time def onrequest(req): pkt = req.pkt payload = pkt.payload.decode("utf-8") print(f"Request (id={pkt.id}): {payload}") req.reply(f"echo {payload}") print("Listening for 60 sec") server = a0.RpcServer("topic", onrequest, None) time.sleep(60) print("Done!")
import a0 import time a0.InitGlobalTopicManager('''{ "container": "stuff_doer" }''') def onrequest(req): print('Request (id={}):'.format(req.pkt.id), req.pkt.payload) req.reply('No path found. Try again later') def oncancel(id): print('Cancel req:', id) print('Listening for 60 sec') server = a0.RpcServer('navigate', onrequest, oncancel) time.sleep(60) print('Done!')