2024-09-16 20:59:39 +02:00
|
|
|
// Copyright 2024, Command Line Inc.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
2024-09-17 04:35:36 +02:00
|
|
|
import { wpsReconnectHandler } from "@/app/store/wps";
|
2024-09-16 20:59:39 +02:00
|
|
|
import { WshClient } from "@/app/store/wshclient";
|
2024-10-17 23:34:02 +02:00
|
|
|
import { makeTabRouteId, WshRouter } from "@/app/store/wshrouter";
|
2024-09-16 20:59:39 +02:00
|
|
|
import { getWSServerEndpoint } from "@/util/endpoints";
|
2024-10-10 19:12:42 +02:00
|
|
|
import { addWSReconnectHandler, ElectronOverrideOpts, globalWS, initGlobalWS, WSControl } from "./ws";
|
2024-09-16 20:59:39 +02:00
|
|
|
|
|
|
|
let DefaultRouter: WshRouter;
|
2024-10-17 23:34:02 +02:00
|
|
|
let TabRpcClient: WshClient;
|
2024-09-16 20:59:39 +02:00
|
|
|
|
|
|
|
async function* rpcResponseGenerator(
|
|
|
|
openRpcs: Map<string, ClientRpcEntry>,
|
|
|
|
command: string,
|
|
|
|
reqid: string,
|
|
|
|
timeout: number
|
|
|
|
): AsyncGenerator<any, void, boolean> {
|
|
|
|
const msgQueue: RpcMessage[] = [];
|
|
|
|
let signalFn: () => void;
|
|
|
|
let signalPromise = new Promise<void>((resolve) => (signalFn = resolve));
|
|
|
|
let timeoutId: NodeJS.Timeout = null;
|
|
|
|
if (timeout > 0) {
|
|
|
|
timeoutId = setTimeout(() => {
|
|
|
|
msgQueue.push({ resid: reqid, error: "EC-TIME: timeout waiting for response" });
|
|
|
|
signalFn();
|
|
|
|
}, timeout);
|
|
|
|
}
|
|
|
|
const msgFn = (msg: RpcMessage) => {
|
|
|
|
msgQueue.push(msg);
|
|
|
|
signalFn();
|
|
|
|
// reset signal promise
|
|
|
|
signalPromise = new Promise<void>((resolve) => (signalFn = resolve));
|
|
|
|
};
|
|
|
|
openRpcs.set(reqid, {
|
|
|
|
reqId: reqid,
|
|
|
|
startTs: Date.now(),
|
|
|
|
command: command,
|
|
|
|
msgFn: msgFn,
|
|
|
|
});
|
|
|
|
yield null;
|
|
|
|
try {
|
|
|
|
while (true) {
|
|
|
|
while (msgQueue.length > 0) {
|
|
|
|
const msg = msgQueue.shift()!;
|
|
|
|
if (msg.error != null) {
|
|
|
|
throw new Error(msg.error);
|
|
|
|
}
|
|
|
|
if (!msg.cont && msg.data == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const shouldTerminate = yield msg.data;
|
|
|
|
if (shouldTerminate) {
|
|
|
|
sendRpcCancel(reqid);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!msg.cont) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
await signalPromise;
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
openRpcs.delete(reqid);
|
|
|
|
if (timeoutId != null) {
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function sendRpcCancel(reqid: string) {
|
|
|
|
const rpcMsg: RpcMessage = { reqid: reqid, cancel: true };
|
|
|
|
DefaultRouter.recvRpcMessage(rpcMsg);
|
|
|
|
}
|
|
|
|
|
|
|
|
function sendRpcResponse(msg: RpcMessage) {
|
|
|
|
DefaultRouter.recvRpcMessage(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
function sendRpcCommand(
|
|
|
|
openRpcs: Map<string, ClientRpcEntry>,
|
|
|
|
msg: RpcMessage
|
|
|
|
): AsyncGenerator<RpcMessage, void, boolean> {
|
|
|
|
DefaultRouter.recvRpcMessage(msg);
|
|
|
|
if (msg.reqid == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const rtnGen = rpcResponseGenerator(openRpcs, msg.command, msg.reqid, msg.timeout);
|
|
|
|
rtnGen.next(); // start the generator (run the initialization/registration logic, throw away the result)
|
|
|
|
return rtnGen;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function consumeGenerator(gen: AsyncGenerator<any, any, any>) {
|
|
|
|
let idx = 0;
|
|
|
|
try {
|
|
|
|
for await (const msg of gen) {
|
|
|
|
console.log("gen", idx, msg);
|
|
|
|
idx++;
|
|
|
|
}
|
|
|
|
const result = await gen.return(undefined);
|
|
|
|
console.log("gen done", result.value);
|
|
|
|
} catch (e) {
|
|
|
|
console.log("gen error", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (globalThis.window != null) {
|
|
|
|
globalThis["consumeGenerator"] = consumeGenerator;
|
|
|
|
}
|
|
|
|
|
2024-09-19 19:42:53 +02:00
|
|
|
function initElectronWshrpc(electronClient: WshClient, eoOpts: ElectronOverrideOpts) {
|
2024-09-18 08:10:09 +02:00
|
|
|
DefaultRouter = new WshRouter(new UpstreamWshRpcProxy());
|
|
|
|
const handleFn = (event: WSEventType) => {
|
|
|
|
DefaultRouter.recvRpcMessage(event.data);
|
|
|
|
};
|
2024-10-10 19:12:42 +02:00
|
|
|
initGlobalWS(getWSServerEndpoint(), "electron", handleFn, eoOpts);
|
2024-09-18 08:10:09 +02:00
|
|
|
globalWS.connectNow("connectWshrpc");
|
|
|
|
DefaultRouter.registerRoute(electronClient.routeId, electronClient);
|
|
|
|
addWSReconnectHandler(() => {
|
|
|
|
DefaultRouter.reannounceRoutes();
|
|
|
|
});
|
|
|
|
addWSReconnectHandler(wpsReconnectHandler);
|
|
|
|
}
|
|
|
|
|
2024-10-06 22:40:02 +02:00
|
|
|
function shutdownWshrpc() {
|
|
|
|
globalWS?.shutdown();
|
|
|
|
}
|
|
|
|
|
2024-10-17 23:34:02 +02:00
|
|
|
function initWshrpc(tabId: string): WSControl {
|
2024-09-16 20:59:39 +02:00
|
|
|
DefaultRouter = new WshRouter(new UpstreamWshRpcProxy());
|
|
|
|
const handleFn = (event: WSEventType) => {
|
|
|
|
DefaultRouter.recvRpcMessage(event.data);
|
|
|
|
};
|
2024-10-17 23:34:02 +02:00
|
|
|
initGlobalWS(getWSServerEndpoint(), tabId, handleFn);
|
2024-09-16 20:59:39 +02:00
|
|
|
globalWS.connectNow("connectWshrpc");
|
2024-10-17 23:34:02 +02:00
|
|
|
TabRpcClient = new WshClient(makeTabRouteId(tabId));
|
|
|
|
DefaultRouter.registerRoute(TabRpcClient.routeId, TabRpcClient);
|
2024-09-17 04:35:36 +02:00
|
|
|
addWSReconnectHandler(() => {
|
|
|
|
DefaultRouter.reannounceRoutes();
|
|
|
|
});
|
|
|
|
addWSReconnectHandler(wpsReconnectHandler);
|
|
|
|
return globalWS;
|
2024-09-16 20:59:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
class UpstreamWshRpcProxy implements AbstractWshClient {
|
|
|
|
recvRpcMessage(msg: RpcMessage): void {
|
|
|
|
const wsMsg: WSRpcCommand = { wscommand: "rpc", message: msg };
|
|
|
|
globalWS?.pushMessage(wsMsg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-17 23:34:02 +02:00
|
|
|
export { DefaultRouter, initElectronWshrpc, initWshrpc, sendRpcCommand, sendRpcResponse, shutdownWshrpc, TabRpcClient };
|