UNPKG

kitten-cloud-function

Version:

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

278 lines (277 loc) 12 kB
import { CodemaoWork } from "./codemao/work/codemao-work"; import { KittenCloudOnlineUserNumber } from "./module/kitten-cloud-online-user-number"; import { KittenCloudWebSocket } from "./module/network/web-socket/kitten-cloud-web-socket"; import { Signal } from "./utils/signal"; import { KittenCloudFunctionConfigLayer } from "./module/kitten-cloud-function-config-layer"; import { KittenCloudPublicVariableGroup } from "./module/cloud-data/group/kitten-cloud-public-variable-group"; import { KittenCloudDataType } from "./module/cloud-data/kitten-cloud-data-type"; import { KittenCloudSendMessageType } from "./module/network/kitten-cloud-send-message-type"; import { KittenCloudReceiveMessageType } from "./module/network/kitten-cloud-receive-message-type"; import { KittenCloudPrivateVariableGroup } from "./module/cloud-data/group/kitten-cloud-private-variable-group"; import { CodemaoUser } from "./codemao/user/codemao-user"; import { None } from "./utils/other"; import { KittenCloudListGroup } from "./module/cloud-data/group/kitten-cloud-list-group"; export let __diff = None; let __importDiff = None; /** * 源码云功能主类,用于管理源码云的连接、数据、事件等。 */ export class KittenCloudFunction extends KittenCloudFunctionConfigLayer { /** * 当从全局 WebSocket 中捕获到源码云的连接,会将其转换为 KittenCloudFunction 实例并通过该信号通知。 * * 该功能会污染全局 WebSocket,仅在该信号被访问时才会启用。 * * 仅在浏览器中可用。 */ static get caught() { if (KittenCloudFunction.__caught == null) { KittenCloudFunction.__caught = new Signal(); KittenCloudFunction.startCatch(); } return KittenCloudFunction.__caught; } static startCatch() { let originalWebSocket = WebSocket; new Function("newWebSocket", ` newWebSocket.prototype = WebSocket.prototype; window.WebSocket = newWebSocket; `)(function (url) { var _a; let socket = new originalWebSocket(url); if (typeof url == "string") { url = new URL(url); } if (!KittenCloudFunction.caught.isEmpty() && url.hostname == ["socketcv", "codemao", "cn"].join(".") && url.pathname == "/cloudstorage/") { let workID = parseInt((_a = url.searchParams.get("session_id")) !== null && _a !== void 0 ? _a : "0"); let instance = KittenCloudFunction.__caughtInstance[workID]; if (instance == null) { instance = new KittenCloudFunction(socket); KittenCloudFunction.__caughtInstance[workID] = instance; } else { instance.socket.changeWebSocket(socket); } KittenCloudFunction.caught.emit(instance); } return socket; }); } constructor(argument) { super(); if (typeof argument == "number") { argument = new CodemaoWork({ id: argument }); } const work = argument instanceof CodemaoWork ? argument : null; if (!(argument instanceof KittenCloudWebSocket)) { argument = new KittenCloudWebSocket(argument); } this.socket = argument; this.work = this.socket.work; this.autoReconnectIntervalTime.changed.connect(({ newValue }) => { if (typeof newValue == "boolean") { this.socket.autoReconnect = newValue; return; } this.socket.autoReconnect = true; this.socket.autoReconnectIntervalTime = newValue; }); this.socket.opened.connect(async () => { if (work != null) { this.send(KittenCloudSendMessageType.JOIN, (await work.info.id).toString()); } }); this.socket.received.connect((message) => { this.handleReceived(message); }); this.opened = new Signal(); this.disconnected = new Signal(); this.closed = new Signal(); this.errored = new Signal(); this.socket.disconnected.connect(() => { this.disconnected.emit(); }); this.socket.closed.connect(() => { this.closed.emit(); }); this.socket.errored.connect((error) => { this.errored.emit(error); }); this.onlineUserNumber = new Promise((resolve, reject) => { this.onlineUserNumberResolve = resolve; this.onlineUserNumberReject = reject; }); this.onlineUserNumber.catch((__ignore) => { }); this.socket.errored.connect((error) => { var _a; (_a = this.onlineUserNumberReject) === null || _a === void 0 ? void 0 : _a.call(this, error); }); this.privateVariable = new KittenCloudPrivateVariableGroup(this); this.publicVariable = new KittenCloudPublicVariableGroup(this); this.list = new KittenCloudListGroup(this); if (__importDiff == None) { __importDiff = (async () => { __diff = await import("diff"); })(); } } /** * 等待连接打开,如果连接打开时出错则抛出异常。 */ waitOpen() { return new Promise((resolve, reject) => { const onOpen = () => { this.opened.disconnect(onOpen); this.opened.disconnect(onError); resolve(); }; const onError = (error) => { this.opened.disconnect(onOpen); this.opened.disconnect(onError); reject(error); }; this.opened.connect(onOpen); this.errored.connect(onError); }); } /** * 关闭该连接。 */ close() { this.socket.close(); } send(type, message) { this.socket.send([type, message]); } handleReceived(message) { (async () => { const [type, data] = message; switch (type) { case KittenCloudReceiveMessageType.JOIN: this.send(KittenCloudSendMessageType.GET_ALL_DATA, {}); break; case KittenCloudReceiveMessageType.RECEIVE_ALL_DATA: if (data == null) { throw new Error("获取全部数据数据为空"); } if (typeof data != "object" || !Array.isArray(data)) { throw new Error(`无法识别的获取全部数据数据:${data}`); } const dataArray = data; const privateVariableArray = [], publicVariableArray = [], listArray = []; for (const item of dataArray) { if (item == null) { continue; } if (typeof item != "object") { throw new Error(`无法识别的获取全部数据数据中的数据:${item}`); } if (!("cvid" in item && typeof item.cvid == "string" && "name" in item && typeof item.name == "string" && "value" in item && typeof (item.value == "string" || item.value == "number" || Array.isArray(item.value)) && "type" in item && typeof item.type == "number")) { throw new Error(`无法识别的获取全部数据数据中的数据:${item}`); } const { cvid, name, value, type } = item; if (type == KittenCloudDataType.PRIVATE_VARIABLE) { privateVariableArray.push({ cvid, name, value }); } else if (type == KittenCloudDataType.PUBLIC_VARIABLE) { publicVariableArray.push({ cvid, name, value }); } else if (type == KittenCloudDataType.LIST) { listArray.push({ cvid, name, value }); } else { throw new Error(`无法识别的获取全部数据数据中的数据数据:${item},数据类型 ${type} 不支持`); } } this.privateVariable.update(privateVariableArray); this.publicVariable.update(publicVariableArray); this.list.update(listArray); if (listArray.length != 0) { if (__diff == None) { await __importDiff; } } this.opened.emit(); break; case KittenCloudReceiveMessageType.UPDATE_PRIVATE_VARIABLE: this.privateVariable.handleCloudUpdate(data); break; case KittenCloudReceiveMessageType.RECEIVE_PRIVATE_VARIABLE_RANKING_LIST: this.privateVariable.handleReceiveRankingList(data); break; case KittenCloudReceiveMessageType.UPDATE_PUBLIC_VARIABLE: this.publicVariable.handleCloudUpdate(data); break; case KittenCloudReceiveMessageType.UPDATE_LIST: this.list.handleCloudUpdate(data); break; case KittenCloudReceiveMessageType.UPDATE_ONLINE_USER_NUMBER: if (data == null) { throw new Error("在线用户数量数据为空"); } if (typeof data != "object" || !("total" in data) || typeof data.total != "number") { throw new Error(`无法识别的在线用户数量数据:${data}`); } if (this.onlineUserNumberResolve != null) { this.onlineUserNumberResolve(new KittenCloudOnlineUserNumber(data.total)); delete this.onlineUserNumberResolve; } else { (await this.onlineUserNumber).update({ total: data.total }); } break; default: throw new Error(`无法识别的消息类型:${type}`); } })().catch((error) => { this.errored.emit(error); }); } /** * 获取云数据实例。 * * @param index 该数据的名称或 cvid * @returns 对应云数据实例 * @throws 如果不存在该云数据实例,则抛出异常 */ async get(index) { const groupArray = [ this.privateVariable, this.publicVariable, this.list ]; for (const group of groupArray) { try { return await group.get(index); } catch (error) { } } throw new Error(`云数据 ${index} 不存在`); } async getAll() { const groupArray = [ this.privateVariable, this.publicVariable, this.list ]; const result = []; for (const group of groupArray) { result.push(...await group.getAll()); } return result; } /** * 当前用户。 * * @returns CodemaoUser */ static get user() { if (KittenCloudFunction._user == None) { KittenCloudFunction._user = new CodemaoUser(); } return KittenCloudFunction._user; } } KittenCloudFunction.__caughtInstance = {}; KittenCloudFunction._user = None;