mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-20 07:51:20 +02:00
Websockets for plugin runtime communication (#156)
This commit is contained in:
@@ -1,52 +1,52 @@
|
||||
import type { InternalEvent } from '@yaakapp/api';
|
||||
import { createChannel, createClient, Status } from 'nice-grpc';
|
||||
import { EventChannel } from './EventChannel';
|
||||
import type { PluginRuntimeClient} from './gen/plugins/runtime';
|
||||
import { PluginRuntimeDefinition } from './gen/plugins/runtime';
|
||||
import { PluginHandle } from './PluginHandle';
|
||||
import WebSocket from 'ws';
|
||||
|
||||
const port = process.env.PORT || '50051';
|
||||
|
||||
const channel = createChannel(`localhost:${port}`, undefined, {
|
||||
'grpc.max_receive_message_length': Number.MAX_SAFE_INTEGER,
|
||||
'grpc.max_send_message_length': Number.MAX_SAFE_INTEGER,
|
||||
});
|
||||
const client: PluginRuntimeClient = createClient(PluginRuntimeDefinition, channel);
|
||||
const port = process.env.YAAK_PLUGIN_SERVER_PORT || '9442';
|
||||
|
||||
const events = new EventChannel();
|
||||
const plugins: Record<string, PluginHandle> = {};
|
||||
|
||||
(async () => {
|
||||
const ws = new WebSocket(`ws://localhost:${port}`);
|
||||
|
||||
ws.on('message', async (e: Buffer) => {
|
||||
try {
|
||||
for await (const e of client.eventStream(events.listen())) {
|
||||
const pluginEvent: InternalEvent = JSON.parse(e.event);
|
||||
// Handle special event to bootstrap plugin
|
||||
if (pluginEvent.payload.type === 'boot_request') {
|
||||
const plugin = new PluginHandle(pluginEvent.pluginRefId, pluginEvent.payload, events);
|
||||
plugins[pluginEvent.pluginRefId] = plugin;
|
||||
}
|
||||
|
||||
// Once booted, forward all events to the plugin worker
|
||||
const plugin = plugins[pluginEvent.pluginRefId];
|
||||
if (!plugin) {
|
||||
console.warn('Failed to get plugin for event by', pluginEvent.pluginRefId);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pluginEvent.payload.type === 'terminate_request') {
|
||||
await plugin.terminate();
|
||||
console.log('Terminated plugin worker', pluginEvent.pluginRefId);
|
||||
delete plugins[pluginEvent.pluginRefId];
|
||||
}
|
||||
|
||||
plugin.sendToWorker(pluginEvent);
|
||||
}
|
||||
console.log('Stream ended');
|
||||
} catch (err: any) {
|
||||
if (err.code === Status.CANCELLED) {
|
||||
console.log('Stream was cancelled by server');
|
||||
} else {
|
||||
console.log('Client stream errored', err);
|
||||
}
|
||||
await handleIncoming(e.toString());
|
||||
} catch (err) {
|
||||
console.log('Failed to handle incoming plugin event', err);
|
||||
}
|
||||
})();
|
||||
});
|
||||
ws.on('open', (e) => console.log('Plugin runtime connected to websocket', e));
|
||||
ws.on('error', (e) => console.error('Plugin runtime websocket error', e));
|
||||
ws.on('close', (e) => console.log('Plugin runtime websocket closed', e));
|
||||
|
||||
// Listen for incoming events from plugins
|
||||
events.listen((e) => {
|
||||
const eventStr = JSON.stringify(e);
|
||||
ws.send(eventStr);
|
||||
});
|
||||
|
||||
async function handleIncoming(msg: string) {
|
||||
const pluginEvent: InternalEvent = JSON.parse(msg);
|
||||
// Handle special event to bootstrap plugin
|
||||
if (pluginEvent.payload.type === 'boot_request') {
|
||||
const plugin = new PluginHandle(pluginEvent.pluginRefId, pluginEvent.payload, events);
|
||||
plugins[pluginEvent.pluginRefId] = plugin;
|
||||
}
|
||||
|
||||
// Once booted, forward all events to the plugin worker
|
||||
const plugin = plugins[pluginEvent.pluginRefId];
|
||||
if (!plugin) {
|
||||
console.warn('Failed to get plugin for event by', pluginEvent.pluginRefId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pluginEvent.payload.type === 'terminate_request') {
|
||||
await plugin.terminate();
|
||||
console.log('Terminated plugin worker', pluginEvent.pluginRefId);
|
||||
delete plugins[pluginEvent.pluginRefId];
|
||||
}
|
||||
|
||||
plugin.sendToWorker(pluginEvent);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user