kitten-cloud-function
Version:
用于编程猫源码云功能(云变量、云列表等)的客户端工具
278 lines (277 loc) • 12 kB
JavaScript
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;