UNPKG

kitten-cloud-function

Version:

用于编程猫源码云功能(云变量、云列表等)的客户端工具

261 lines (260 loc) 9.81 kB
import { WebSocketProxy } from "../../../utils/web-socket-proxy"; import { CodemaoWorkEditor } from "../../../codemao/work/codemao-work-editor"; import { CodemaoWork } from "../../../codemao/work/codemao-work"; import { Signal } from "../../../utils/signal"; import { KittenCloudWebSocketMessageType } from "./kitten-cloud-web-socket-message-type"; import { None } from "../../../utils/other"; import { CodemaoWebSocket } from "../../../codemao/codemao-environment"; const KITTEN_WEB_SOCKET_URL_PARAMS = { [CodemaoWorkEditor.NEMO.symbol]: { authorization_type: 5, stag: 2, EIO: 3, transport: "websocket" }, [CodemaoWorkEditor.KITTEN.symbol]: { authorization_type: 1, stag: 1, EIO: 3, transport: "websocket" }, [CodemaoWorkEditor.KITTEN_N.symbol]: { authorization_type: 5, stag: 3, token: "", EIO: 3, transport: "websocket" }, }; export class KittenCloudWebSocket { constructor(argument) { var _a; this.autoReconnect = true; this.autoReconnectIntervalTime = 8000; this.isOpened = false; this.socketResolve = None; this.beforeSend = new Signal(); this.manage = argument instanceof CodemaoWork; this.beforeSend = new Signal(); this.sended = new Signal(); this.opened = new Signal(); this.disconnected = new Signal(); this.received = new Signal(); this.errored = new Signal(); this.closed = new Signal(); this.pingHandlerArray = []; if (argument instanceof CodemaoWork) { this.work = argument; } else { this.work = new CodemaoWork({ id: parseInt((_a = new URL(argument.url).searchParams.get("session_id")) !== null && _a !== void 0 ? _a : "0") }); } this.setSocket(argument); } changeWebSocket(argument) { this.setSocket(argument); } setSocket(argument) { this.socket = this.getSocket(argument); if (this.socketResolve != None) { this.socketResolve(this.socket); this.socketResolve = None; } this.socket.then((socket) => { socket.beforeSend.connect((message) => { this.beforeSend.emit(message); }); socket.sended.connect((message) => { this.sended.emit(message); }); socket.received.connect((message) => { this.handleReceived(message.data); }); socket.errored.connect((error) => { this.errored.emit(error); }); socket.closed.connect((event) => { this.handleClose(event); }); }).catch((reason) => { this.errored.emit(reason); }); } async getSocket(argument) { if (typeof argument == "string") { return new WebSocketProxy(await CodemaoWebSocket(argument)); } else if (argument instanceof CodemaoWork) { const url = await (async () => { const scheme = typeof global == "object" || window.location.protocol != "http:" ? "wss" : "ws"; const host = ["socketcv", "codemao", "cn"].join("."); const port = 9096; const path = "/cloudstorage/"; const particularParams = KITTEN_WEB_SOCKET_URL_PARAMS[(await argument.info.editor).symbol]; if (particularParams == None) { throw new Error(`不支持的作品类型: ${(await argument.info.editor).name}`); } const params = `session_id=${await argument.info.id}&${Object.entries(particularParams) .map(([key, value]) => `${key}=${value}`) .join("&")}`; return `${scheme}://${host}:${port}${path}?${params}`; })(); const socket = new WebSocketProxy(await CodemaoWebSocket(url)); return socket; } else if (argument instanceof WebSocket) { return new WebSocketProxy(argument); } else { return argument; } } handleReceived(message) { var _a, _b; try { const type = parseInt((_b = (_a = /^[0-9]+/.exec(message)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : "-1"); const data = message.length == type.toString().length ? None : JSON.parse(message.slice(type.toString().length)); if (!this.manage && type != KittenCloudWebSocketMessageType.MESSAGE) { return; } switch (type) { case KittenCloudWebSocketMessageType.UPGRADE: if (data == None) { throw new Error("升级数据为空"); } if (typeof data != "object" || !("pingInterval" in data) || !("pingTimeout" in data) || typeof data.pingInterval != "number" || typeof data.pingTimeout != "number") { throw new Error("无法识别的升级数据格式"); } this.startPing(data.pingInterval, data.pingTimeout); break; case KittenCloudWebSocketMessageType.ERROR: this.handleServerError(); break; case KittenCloudWebSocketMessageType.PONG: clearTimeout(this.pingHandlerArray.shift()); break; case KittenCloudWebSocketMessageType.CONNECT: this.opened.emit(); break; case KittenCloudWebSocketMessageType.CLOSE: this.handleServerClose(); break; case KittenCloudWebSocketMessageType.MESSAGE: if (data == None) { throw new Error("消息数据为空"); } if (!Array.isArray(data) || data.length != 2 || typeof data[0] != "string") { throw new Error("无法识别的消息格式"); } if (typeof data[1] == "string") { try { data[1] = JSON.parse(data[1]); } catch (error) { } } this.received.emit(data); break; default: throw new Error(`未知消息类型: ${type}`); } } catch (error) { this.errored.emit(error); } } startPing(interval, timeout) { if (this.pingHandler != None) { this.stopPing(); } this.pingHandlerArray = []; this.pingHandler = setInterval(() => { this.socket.then((socket) => { socket.send(KittenCloudWebSocketMessageType.PING.toString()); this.pingHandlerArray.push(setTimeout(() => { this.clientErrorClose(new Error("保活超时")); }, timeout)); }); }, interval); } stopPing() { if (this.pingHandler != None) { clearInterval(this.pingHandler); } for (const timeout of this.pingHandlerArray) { clearTimeout(timeout); } } send(message) { this.socket.then((socket) => { if (typeof message != "string") { message = JSON.stringify(message); } socket.send(`${KittenCloudWebSocketMessageType.MESSAGE.toString()}${message}`); }).catch((reason) => { this.errored.emit(reason); }); } handleClose(event) { this.disconnected.emit(); if (!this.isOpened || !this.autoReconnect) { this.closed.emit(event); return; } else { this.isOpened = false; if (this.manage) { let url; this.socket.then((socket) => { url = socket.url; }); this.socket = new Promise((resolve) => { setTimeout(() => { this.socketResolve = resolve; this.setSocket(url); }, this.autoReconnectIntervalTime); }); } else { this.socket = new Promise((resolve, reject) => { this.socketResolve = resolve; setTimeout(() => { this.closed.emit(event); reject(new Error("重连等待超时")); }); }); } } } handleServerError() { this.errored.emit(new Error("服务器错误")); this.socket.then((socket) => { try { socket.close(); } catch (error) { } }); } clientErrorClose(error) { this.errored.emit(error); this.socket.then((socket) => { socket.send(KittenCloudWebSocketMessageType.ERROR.toString()); socket.close(); }); } handleServerClose() { this.socket.then((socket) => { try { socket.close(); } catch (error) { } }); } close() { this.socket.then((socket) => { socket.send(KittenCloudWebSocketMessageType.CLOSE.toString()); this.isOpened = false; socket.close(); }).catch((reason) => { this.errored.emit(reason); }); } }