kitten-cloud-function
Version:
用于编程猫源码云功能(云变量、云列表等)的客户端工具
265 lines (264 loc) • 10.8 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.KittenCloudWebSocket = void 0;
const web_socket_proxy_1 = require("../../../utils/web-socket-proxy");
const codemao_work_editor_1 = require("../../../codemao/work/codemao-work-editor");
const codemao_work_1 = require("../../../codemao/work/codemao-work");
const signal_1 = require("../../../utils/signal");
const kitten_cloud_web_socket_message_type_1 = require("./kitten-cloud-web-socket-message-type");
const other_1 = require("../../../utils/other");
const codemao_environment_1 = require("../../../codemao/codemao-environment");
const KITTEN_WEB_SOCKET_URL_PARAMS = {
[codemao_work_editor_1.CodemaoWorkEditor.NEMO.symbol]: {
authorization_type: 5,
stag: 2,
EIO: 3,
transport: "websocket"
},
[codemao_work_editor_1.CodemaoWorkEditor.KITTEN.symbol]: {
authorization_type: 1,
stag: 1,
EIO: 3,
transport: "websocket"
},
[codemao_work_editor_1.CodemaoWorkEditor.KITTEN_N.symbol]: {
authorization_type: 5,
stag: 3,
token: "",
EIO: 3,
transport: "websocket"
},
};
class KittenCloudWebSocket {
constructor(argument) {
var _a;
this.autoReconnect = true;
this.autoReconnectIntervalTime = 8000;
this.isOpened = false;
this.socketResolve = other_1.None;
this.beforeSend = new signal_1.Signal();
this.manage = argument instanceof codemao_work_1.CodemaoWork;
this.beforeSend = new signal_1.Signal();
this.sended = new signal_1.Signal();
this.opened = new signal_1.Signal();
this.disconnected = new signal_1.Signal();
this.received = new signal_1.Signal();
this.errored = new signal_1.Signal();
this.closed = new signal_1.Signal();
this.pingHandlerArray = [];
if (argument instanceof codemao_work_1.CodemaoWork) {
this.work = argument;
}
else {
this.work = new codemao_work_1.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 != other_1.None) {
this.socketResolve(this.socket);
this.socketResolve = other_1.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 web_socket_proxy_1.WebSocketProxy(await (0, codemao_environment_1.CodemaoWebSocket)(argument));
}
else if (argument instanceof codemao_work_1.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 == other_1.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 web_socket_proxy_1.WebSocketProxy(await (0, codemao_environment_1.CodemaoWebSocket)(url));
return socket;
}
else if (argument instanceof WebSocket) {
return new web_socket_proxy_1.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 ?
other_1.None : JSON.parse(message.slice(type.toString().length));
if (!this.manage && type != kitten_cloud_web_socket_message_type_1.KittenCloudWebSocketMessageType.MESSAGE) {
return;
}
switch (type) {
case kitten_cloud_web_socket_message_type_1.KittenCloudWebSocketMessageType.UPGRADE:
if (data == other_1.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 kitten_cloud_web_socket_message_type_1.KittenCloudWebSocketMessageType.ERROR:
this.handleServerError();
break;
case kitten_cloud_web_socket_message_type_1.KittenCloudWebSocketMessageType.PONG:
clearTimeout(this.pingHandlerArray.shift());
break;
case kitten_cloud_web_socket_message_type_1.KittenCloudWebSocketMessageType.CONNECT:
this.opened.emit();
break;
case kitten_cloud_web_socket_message_type_1.KittenCloudWebSocketMessageType.CLOSE:
this.handleServerClose();
break;
case kitten_cloud_web_socket_message_type_1.KittenCloudWebSocketMessageType.MESSAGE:
if (data == other_1.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 != other_1.None) {
this.stopPing();
}
this.pingHandlerArray = [];
this.pingHandler = setInterval(() => {
this.socket.then((socket) => {
socket.send(kitten_cloud_web_socket_message_type_1.KittenCloudWebSocketMessageType.PING.toString());
this.pingHandlerArray.push(setTimeout(() => {
this.clientErrorClose(new Error("保活超时"));
}, timeout));
});
}, interval);
}
stopPing() {
if (this.pingHandler != other_1.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(`${kitten_cloud_web_socket_message_type_1.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(kitten_cloud_web_socket_message_type_1.KittenCloudWebSocketMessageType.ERROR.toString());
socket.close();
});
}
handleServerClose() {
this.socket.then((socket) => {
try {
socket.close();
}
catch (error) { }
});
}
close() {
this.socket.then((socket) => {
socket.send(kitten_cloud_web_socket_message_type_1.KittenCloudWebSocketMessageType.CLOSE.toString());
this.isOpened = false;
socket.close();
}).catch((reason) => {
this.errored.emit(reason);
});
}
}
exports.KittenCloudWebSocket = KittenCloudWebSocket;
;