From 59008fb9648a1c358308b3cd61ec0d4063cdc635 Mon Sep 17 00:00:00 2001 From: Koushik Dutta Date: Tue, 21 Mar 2023 21:16:08 -0700 Subject: [PATCH] server: fix bug where python async generator aclose is not called on rpc objects --- server/package-lock.json | 4 ++-- server/python/rpc-iterator-test.py | 10 +++++++--- server/python/rpc.py | 8 ++++++++ server/test/rpc-python-test.ts | 16 ++++++++++------ 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/server/package-lock.json b/server/package-lock.json index 67be78142e..9157d1a716 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/server", - "version": "0.7.22", + "version": "0.7.23", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@scrypted/server", - "version": "0.7.22", + "version": "0.7.23", "license": "ISC", "dependencies": { "@mapbox/node-pre-gyp": "^1.0.10", diff --git a/server/python/rpc-iterator-test.py b/server/python/rpc-iterator-test.py index cf7e8fe753..ac333aff5f 100644 --- a/server/python/rpc-iterator-test.py +++ b/server/python/rpc-iterator-test.py @@ -1,13 +1,13 @@ import asyncio import rpc -from rpc_reader import prepare_peer_readloop +from rpc_reader import prepare_peer_readloop, RpcFileTransport import traceback class Bar: pass async def main(): - peer, peerReadLoop = await prepare_peer_readloop(loop, 4, 3) + peer, peerReadLoop = await prepare_peer_readloop(loop, RpcFileTransport(4, 3)) peer.params['foo'] = 3 jsoncopy = {} jsoncopy[rpc.RpcPeer.PROPERTY_JSON_COPY_SERIALIZE_CHILDREN] = True @@ -35,8 +35,12 @@ async def main(): test = await peer.getParam('test') print(test) try: - async for c in test: + i = 0 + async for c in await test(): print(c) + if i == 5: + break + i = i + 1 except: traceback.print_exc() print('all done iterating') diff --git a/server/python/rpc.py b/server/python/rpc.py index 35b2d8526c..d67f9eb4b7 100644 --- a/server/python/rpc.py +++ b/server/python/rpc.py @@ -79,6 +79,14 @@ async def __anext__(self): raise raise Exception('RpcProxy is not an async iterable') + async def aclose(self): + if self.__dict__[RpcPeer.PROPERTY_PROXY_PROPERTIES] and 'Symbol(Symbol.asyncIterator)' in self.__dict__[RpcPeer.PROPERTY_PROXY_PROPERTIES]: + try: + return await RpcProxyMethod(self, self.__dict__[RpcPeer.PROPERTY_PROXY_PROPERTIES]['Symbol(Symbol.asyncIterator)']['return'])() + except RPCResultError as e: + pass + raise Exception('RpcProxy is not an async iterable') + def __getattr__(self, name): if name == '__proxy_finalizer_id': return self.dict['__proxy_entry']['finalizerId'] diff --git a/server/test/rpc-python-test.ts b/server/test/rpc-python-test.ts index 4e1f838da9..d406dc2233 100644 --- a/server/test/rpc-python-test.ts +++ b/server/test/rpc-python-test.ts @@ -1,9 +1,8 @@ import child_process from 'child_process'; +import net from 'net'; import path from 'path'; import type { Readable, Writable } from "stream"; import { createDuplexRpcPeer } from '../src/rpc-serializer'; -import assert from 'assert'; -import net from 'net'; async function main() { const server = net.createServer(client => { @@ -21,12 +20,17 @@ async function main() { const rpcPeer = createDuplexRpcPeer('node', 'python', cp.stdio[3] as Readable, cp.stdio[4] as Writable); async function* test() { - yield 1; - yield 2; - yield 3; + try { + for (let i = 0; ; i++) { + yield i; + } + } + finally { + console.log('closed'); + } } - rpcPeer.params['test'] = test(); + rpcPeer.params['test'] = test; // const foo = await rpcPeer.getParam('foo'); // assert.equal(foo, 3);