Skip to content

Instantly share code, notes, and snippets.

@char101
Created June 16, 2023 04:23
Show Gist options
  • Save char101/edb6b46da01c1c26b4c72a76b49d3b3c to your computer and use it in GitHub Desktop.
Save char101/edb6b46da01c1c26b4c72a76b49d3b3c to your computer and use it in GitHub Desktop.
Simple javascript - python rpc via websocket
class RemoteService {
#id = 0;
#socket = null;
#queue = new Map();
constructor(wsUrl) {
this.#socket = new WebSocket(wsUrl);
this.#socket.addEventListener('error', error => console.log('socket error: ', error));
this.#socket.addEventListener('message', this._onMessage.bind(this));
return new Promise((resolve, reject) => {
this.#socket.addEventListener('open', () => {
this._onOpen(resolve);
});
});
}
_send(msg) {
msg.id = ++this.#id;
if (this.#id === 2147483647) {
this.#id = 0;
}
this.#socket.send(JSON.stringify(msg));
return new Promise((resolve, reject) => {
this.#queue.set(msg.id, [msg.cmd, resolve, reject]);
});
}
async _onOpen(callback) {
const names = await this._send({cmd: 'list'});
const send = this._send.bind(this);
for (const name of names) {
this[name] = new Proxy({}, {
get(target, prop, receiver) {
return (...args) => send({cmd: 'call', name, prop, args});
}
});
}
callback(this);
}
_onMessage(event) {
const data = JSON.parse(event.data);
const [cmd, resolve, reject] = this.#queue.get(data.id);
this.#queue.delete(data.id);
if (!data.err) {
resolve(data.data);
} else {
reject('remote exception: ' + data.err);
}
}
}
(async function() {
const remote = await new RemoteService('ws://127.0.0.1:3021');
console.log(await remote.test.hello('world'));
})();
import asyncio
import traceback
from websockets.server import serve
from yapic import json
class Test:
def hello(self, text):
return f'hello {text}'
services = {
'test': Test(),
}
async def handler(socket):
async for message in socket:
msg = json.loads(message)
err = None
match msg['cmd']:
case 'list':
data = list(services.keys())
case 'call':
try:
data = getattr(services[msg['name']], msg['prop'])(*msg['args'])
except Exception as _err:
print(traceback.format_exc())
err = str(_err)
await socket.send(json.dumps({
'id': msg['id'],
'err': err,
'data': data,
}))
async def main():
async with serve(handler, '127.0.0.1', 3021):
await asyncio.Future()
asyncio.run(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment