mirror of
https://github.com/wavetermdev/backup.git
synced 2026-08-05 13:57:07 -07:00
initwshrpc in electron (#391)
This commit is contained in:
@@ -3,10 +3,22 @@
|
||||
|
||||
import debug from "debug";
|
||||
import { sprintf } from "sprintf-js";
|
||||
import type { WebSocket as ElectronWebSocketType } from "ws";
|
||||
|
||||
let ElectronWebSocket: typeof ElectronWebSocketType;
|
||||
const AuthKeyHeader = "X-AuthKey";
|
||||
|
||||
if (typeof window === "undefined") {
|
||||
try {
|
||||
const WebSocket = require("ws") as typeof ElectronWebSocketType;
|
||||
ElectronWebSocket = WebSocket;
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
const dlog = debug("wave:ws");
|
||||
|
||||
const MaxWebSocketSendSize = 1024 * 1024; // 1MB
|
||||
const WarnWebSocketSendSize = 1024 * 1024; // 1MB
|
||||
const MaxWebSocketSendSize = 5 * 1024 * 1024; // 5MB
|
||||
const reconnectHandlers: (() => void)[] = [];
|
||||
|
||||
function addWSReconnectHandler(handler: () => void) {
|
||||
@@ -23,7 +35,7 @@ function removeWSReconnectHandler(handler: () => void) {
|
||||
type WSEventCallback = (arg0: WSEventType) => void;
|
||||
|
||||
class WSControl {
|
||||
wsConn: any;
|
||||
wsConn: WebSocket | ElectronWebSocketType;
|
||||
open: boolean;
|
||||
opening: boolean = false;
|
||||
reconnectTimes: number = 0;
|
||||
@@ -35,12 +47,14 @@ class WSControl {
|
||||
wsLog: string[] = [];
|
||||
baseHostPort: string;
|
||||
lastReconnectTime: number = 0;
|
||||
authKey: string = null; // used only by electron
|
||||
|
||||
constructor(baseHostPort: string, windowId: string, messageCallback: WSEventCallback) {
|
||||
constructor(baseHostPort: string, windowId: string, messageCallback: WSEventCallback, authKey?: string) {
|
||||
this.baseHostPort = baseHostPort;
|
||||
this.messageCallback = messageCallback;
|
||||
this.windowId = windowId;
|
||||
this.open = false;
|
||||
this.authKey = authKey;
|
||||
setInterval(this.sendPing.bind(this), 5000);
|
||||
}
|
||||
|
||||
@@ -51,7 +65,13 @@ class WSControl {
|
||||
this.lastReconnectTime = Date.now();
|
||||
dlog("try reconnect:", desc);
|
||||
this.opening = true;
|
||||
this.wsConn = new WebSocket(this.baseHostPort + "/ws?windowid=" + this.windowId);
|
||||
if (ElectronWebSocket) {
|
||||
this.wsConn = new ElectronWebSocket(this.baseHostPort + "/ws?windowid=" + this.windowId, {
|
||||
headers: { [AuthKeyHeader]: this.authKey },
|
||||
});
|
||||
} else {
|
||||
this.wsConn = new WebSocket(this.baseHostPort + "/ws?windowid=" + this.windowId);
|
||||
}
|
||||
this.wsConn.onopen = this.onopen.bind(this);
|
||||
this.wsConn.onmessage = this.onmessage.bind(this);
|
||||
this.wsConn.onclose = this.onclose.bind(this);
|
||||
@@ -172,6 +192,9 @@ class WSControl {
|
||||
console.log("ws message too large", byteSize, data.wscommand, msg.substring(0, 100));
|
||||
return;
|
||||
}
|
||||
if (byteSize > WarnWebSocketSendSize) {
|
||||
console.log("ws message large", byteSize, data.wscommand, msg.substring(0, 100));
|
||||
}
|
||||
this.wsConn.send(msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -92,16 +92,21 @@ class WshClient {
|
||||
// TODO implement a timeout (setTimeout + sendResponse)
|
||||
const helper = new RpcResponseHelper(this, msg);
|
||||
const handlerName = `handle_${msg.command}`;
|
||||
let prtn: any = null;
|
||||
if (handlerName in this) {
|
||||
prtn = this[handlerName](helper, msg.data);
|
||||
return;
|
||||
} else {
|
||||
prtn = this.handle_default(helper, msg);
|
||||
}
|
||||
try {
|
||||
let result: any = null;
|
||||
let prtn: any = null;
|
||||
if (handlerName in this) {
|
||||
prtn = this[handlerName](helper, msg.data);
|
||||
} else {
|
||||
prtn = this.handle_default(helper, msg);
|
||||
}
|
||||
if (prtn instanceof Promise) {
|
||||
await prtn;
|
||||
result = await prtn;
|
||||
} else {
|
||||
result = prtn;
|
||||
}
|
||||
if (!helper.done) {
|
||||
helper.sendResponse({ data: result });
|
||||
}
|
||||
} catch (e) {
|
||||
if (!helper.done) {
|
||||
|
||||
@@ -12,6 +12,11 @@ class RpcApiType {
|
||||
return client.wshRpcCall("authenticate", data, opts);
|
||||
}
|
||||
|
||||
// command "blockinfo" [call]
|
||||
BlockInfoCommand(client: WshClient, data: string, opts?: RpcOpts): Promise<BlockInfoData> {
|
||||
return client.wshRpcCall("blockinfo", data, opts);
|
||||
}
|
||||
|
||||
// command "connconnect" [call]
|
||||
ConnConnectCommand(client: WshClient, data: string, opts?: RpcOpts): Promise<void> {
|
||||
return client.wshRpcCall("connconnect", data, opts);
|
||||
@@ -207,6 +212,11 @@ class RpcApiType {
|
||||
return client.wshRpcCall("test", data, opts);
|
||||
}
|
||||
|
||||
// command "webselector" [call]
|
||||
WebSelectorCommand(client: WshClient, data: CommandWebSelectorData, opts?: RpcOpts): Promise<string[]> {
|
||||
return client.wshRpcCall("webselector", data, opts);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const RpcApi = new RpcApiType();
|
||||
|
||||
@@ -31,6 +31,9 @@ class WshRouter {
|
||||
constructor(upstreamClient: AbstractWshClient) {
|
||||
this.routeMap = new Map();
|
||||
this.rpcMap = new Map();
|
||||
if (upstreamClient == null) {
|
||||
throw new Error("upstream client cannot be null");
|
||||
}
|
||||
this.upstreamClient = upstreamClient;
|
||||
}
|
||||
|
||||
@@ -46,34 +49,17 @@ class WshRouter {
|
||||
}
|
||||
|
||||
// returns true if the message was sent
|
||||
_sendRoutedMessage(msg: RpcMessage, destRouteId: string): boolean {
|
||||
_sendRoutedMessage(msg: RpcMessage, destRouteId: string) {
|
||||
const client = this.routeMap.get(destRouteId);
|
||||
if (client) {
|
||||
client.recvRpcMessage(msg);
|
||||
return true;
|
||||
}
|
||||
if (!this.upstreamClient) {
|
||||
// there should always be an upstream client
|
||||
return false;
|
||||
}
|
||||
this.upstreamClient?.recvRpcMessage(msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
_handleNoRoute(msg: RpcMessage) {
|
||||
dlog("no route for message", msg);
|
||||
if (util.isBlank(msg.reqid)) {
|
||||
// send a message instead
|
||||
if (msg.command == "message") {
|
||||
return;
|
||||
}
|
||||
const nrMsg = { command: "message", route: msg.source, data: { message: `no route for ${msg.route}` } };
|
||||
this._sendRoutedMessage(nrMsg, SysRouteName);
|
||||
return;
|
||||
}
|
||||
// send an error response
|
||||
const nrMsg = { resid: msg.reqid, error: `no route for ${msg.route}` };
|
||||
this._sendRoutedMessage(nrMsg, msg.source);
|
||||
// there should always an upstream client
|
||||
if (!this.upstreamClient) {
|
||||
throw new Error(`no upstream client for message: ${msg}`);
|
||||
}
|
||||
this.upstreamClient?.recvRpcMessage(msg);
|
||||
}
|
||||
|
||||
_registerRouteInfo(reqid: string, sourceRouteId: string, destRouteId: string) {
|
||||
@@ -102,18 +88,17 @@ class WshRouter {
|
||||
}
|
||||
if (!util.isBlank(msg.command)) {
|
||||
// send + register routeinfo
|
||||
const ok = this._sendRoutedMessage(msg, msg.route);
|
||||
if (!ok) {
|
||||
this._handleNoRoute(msg);
|
||||
return;
|
||||
if (!util.isBlank(msg.reqid)) {
|
||||
this._registerRouteInfo(msg.reqid, msg.source, msg.route);
|
||||
}
|
||||
this._registerRouteInfo(msg.reqid, msg.source, msg.route);
|
||||
this._sendRoutedMessage(msg, msg.route);
|
||||
return;
|
||||
}
|
||||
if (!util.isBlank(msg.reqid)) {
|
||||
const routeInfo = this.rpcMap.get(msg.reqid);
|
||||
if (!routeInfo) {
|
||||
// no route info, discard
|
||||
dlog("no route info for reqid, discarding", msg);
|
||||
return;
|
||||
}
|
||||
this._sendRoutedMessage(msg, routeInfo.destRouteId);
|
||||
@@ -123,6 +108,7 @@ class WshRouter {
|
||||
const routeInfo = this.rpcMap.get(msg.resid);
|
||||
if (!routeInfo) {
|
||||
// no route info, discard
|
||||
dlog("no route info for resid, discarding", msg);
|
||||
return;
|
||||
}
|
||||
this._sendRoutedMessage(msg, routeInfo.sourceRouteId);
|
||||
|
||||
@@ -114,11 +114,24 @@ if (globalThis.window != null) {
|
||||
globalThis["consumeGenerator"] = consumeGenerator;
|
||||
}
|
||||
|
||||
function initElectronWshrpc(electronClient: WshClient, authKey: string) {
|
||||
DefaultRouter = new WshRouter(new UpstreamWshRpcProxy());
|
||||
const handleFn = (event: WSEventType) => {
|
||||
DefaultRouter.recvRpcMessage(event.data);
|
||||
};
|
||||
globalWS = new WSControl(getWSServerEndpoint(), "electron", handleFn, authKey);
|
||||
globalWS.connectNow("connectWshrpc");
|
||||
DefaultRouter.registerRoute(electronClient.routeId, electronClient);
|
||||
addWSReconnectHandler(() => {
|
||||
DefaultRouter.reannounceRoutes();
|
||||
});
|
||||
addWSReconnectHandler(wpsReconnectHandler);
|
||||
}
|
||||
|
||||
function initWshrpc(windowId: string): WSControl {
|
||||
DefaultRouter = new WshRouter(new UpstreamWshRpcProxy());
|
||||
const handleFn = (event: WSEventType) => {
|
||||
DefaultRouter.recvRpcMessage(event.data);
|
||||
// handleIncomingRpcMessage(globalOpenRpcs, event);
|
||||
};
|
||||
globalWS = new WSControl(getWSServerEndpoint(), windowId, handleFn);
|
||||
globalWS.connectNow("connectWshrpc");
|
||||
@@ -144,6 +157,7 @@ class UpstreamWshRpcProxy implements AbstractWshClient {
|
||||
|
||||
export {
|
||||
DefaultRouter,
|
||||
initElectronWshrpc,
|
||||
initWshrpc,
|
||||
sendRawRpcMessage,
|
||||
sendRpcCommand,
|
||||
|
||||
Vendored
+23
@@ -25,6 +25,14 @@ declare global {
|
||||
meta?: MetaType;
|
||||
};
|
||||
|
||||
// wshrpc.BlockInfoData
|
||||
type BlockInfoData = {
|
||||
blockid: string;
|
||||
tabid: string;
|
||||
windowid: string;
|
||||
meta: MetaType;
|
||||
};
|
||||
|
||||
// webcmd.BlockInputWSCommand
|
||||
type BlockInputWSCommand = {
|
||||
wscommand: "blockinput";
|
||||
@@ -147,6 +155,15 @@ declare global {
|
||||
meta: MetaType;
|
||||
};
|
||||
|
||||
// wshrpc.CommandWebSelectorData
|
||||
type CommandWebSelectorData = {
|
||||
windowid: string;
|
||||
blockid: string;
|
||||
tabid: string;
|
||||
selector: string;
|
||||
opts?: WebSelectorOpts;
|
||||
};
|
||||
|
||||
// wconfig.ConfigError
|
||||
type ConfigError = {
|
||||
file: string;
|
||||
@@ -641,6 +658,12 @@ declare global {
|
||||
updates?: WaveObjUpdate[];
|
||||
};
|
||||
|
||||
// wshrpc.WebSelectorOpts
|
||||
type WebSelectorOpts = {
|
||||
all?: boolean;
|
||||
inner?: boolean;
|
||||
};
|
||||
|
||||
// wconfig.WidgetConfigType
|
||||
type WidgetConfigType = {
|
||||
"display:order"?: number;
|
||||
|
||||
Reference in New Issue
Block a user