rustdesk/flutter/web/js/src/websock.ts

184 lines
4.8 KiB
TypeScript
Raw Normal View History

2022-01-18 02:02:39 +08:00
import * as message from "./message.js";
import * as rendezvous from "./rendezvous.js";
2022-01-20 18:02:20 +08:00
import * as globals from "./globals";
2022-01-18 02:02:39 +08:00
type Keys = "message" | "open" | "close" | "error";
2022-01-17 18:11:14 +08:00
export default class Websock {
2022-01-18 02:02:39 +08:00
_websocket: WebSocket;
_eventHandlers: { [key in Keys]: Function };
2022-02-05 01:55:23 +08:00
_buf: (rendezvous.RendezvousMessage | message.Message)[];
2022-01-19 22:26:23 +08:00
_status: any;
2022-01-20 01:00:35 +08:00
_latency: number;
2022-01-20 18:02:20 +08:00
_secretKey: [Uint8Array, number, number] | undefined;
2022-01-27 01:30:29 +08:00
_uri: string;
2022-02-05 01:55:23 +08:00
_isRendezvous: boolean;
2022-02-06 16:24:31 +08:00
constructor(uri: string, isRendezvous: boolean = true) {
2022-01-19 22:26:23 +08:00
this._eventHandlers = {
message: (_: any) => {},
open: () => {},
close: () => {},
error: () => {},
};
2022-01-27 01:30:29 +08:00
this._uri = uri;
2022-01-19 22:26:23 +08:00
this._status = "";
this._buf = [];
this._websocket = new WebSocket(uri);
this._websocket.onmessage = this._recv_message.bind(this);
this._websocket.binaryType = "arraybuffer";
2022-01-20 01:00:35 +08:00
this._latency = new Date().getTime();
2022-02-05 01:55:23 +08:00
this._isRendezvous = isRendezvous;
2022-01-20 01:00:35 +08:00
}
latency(): number {
return this._latency;
2022-01-19 22:26:23 +08:00
}
2022-01-20 18:02:20 +08:00
setSecretKey(key: Uint8Array) {
this._secretKey = [key, 0, 0];
2022-01-20 15:41:11 +08:00
}
2022-01-30 03:39:54 +08:00
sendMessage(json: message.DeepPartial<message.Message>) {
2022-01-27 01:30:29 +08:00
let data = message.Message.encode(
message.Message.fromPartial(json)
).finish();
2022-01-20 18:02:20 +08:00
let k = this._secretKey;
if (k) {
k[1] += 1;
data = globals.encrypt(data, k[1], k[0]);
}
this._websocket.send(data);
2022-01-19 22:26:23 +08:00
}
2022-01-30 03:39:54 +08:00
sendRendezvous(data: rendezvous.DeepPartial<rendezvous.RendezvousMessage>) {
2022-01-19 22:26:23 +08:00
this._websocket.send(
rendezvous.RendezvousMessage.encode(
2022-01-20 15:41:11 +08:00
rendezvous.RendezvousMessage.fromPartial(data)
2022-01-19 22:26:23 +08:00
).finish()
);
}
parseMessage(data: Uint8Array) {
return message.Message.decode(data);
2022-01-18 02:02:39 +08:00
}
2022-01-17 18:11:14 +08:00
2022-01-19 22:26:23 +08:00
parseRendezvous(data: Uint8Array) {
return rendezvous.RendezvousMessage.decode(data);
2022-01-18 02:02:39 +08:00
}
2022-01-17 18:11:14 +08:00
2022-01-18 02:02:39 +08:00
// Event Handlers
off(evt: Keys) {
2022-01-19 22:26:23 +08:00
this._eventHandlers[evt] = () => {};
2022-01-18 02:02:39 +08:00
}
2022-01-17 18:11:14 +08:00
2022-01-18 02:02:39 +08:00
on(evt: Keys, handler: Function) {
this._eventHandlers[evt] = handler;
}
2022-01-17 18:11:14 +08:00
2022-01-19 22:26:23 +08:00
async open(timeout: number = 12000): Promise<Websock> {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (this._status != "open") {
2022-01-30 19:48:41 +08:00
reject(this._status || "Timeout");
2022-01-19 22:26:23 +08:00
}
}, timeout);
this._websocket.onopen = () => {
2022-01-20 01:00:35 +08:00
this._latency = new Date().getTime() - this._latency;
2022-01-19 22:26:23 +08:00
this._status = "open";
console.debug(">> WebSock.onopen");
if (this._websocket?.protocol) {
console.info(
"Server choose sub-protocol: " + this._websocket.protocol
);
}
2022-01-17 18:11:14 +08:00
2022-01-19 22:26:23 +08:00
this._eventHandlers.open();
2022-01-20 01:00:35 +08:00
console.info("WebSock.onopen");
2022-01-19 22:26:23 +08:00
resolve(this);
};
this._websocket.onclose = (e) => {
2022-01-30 03:39:54 +08:00
if (this._status == "open") {
2022-01-31 13:15:18 +08:00
// e.code 1000 means that the connection was closed normally.
2022-02-06 16:24:31 +08:00
//
2022-01-27 13:24:40 +08:00
}
2022-01-19 22:26:23 +08:00
this._status = e;
2022-02-06 16:24:31 +08:00
console.error("WebSock.onclose: ");
console.error(e);
2022-01-19 22:26:23 +08:00
this._eventHandlers.close(e);
2022-02-06 16:24:31 +08:00
reject("Reset by the peer");
2022-01-19 22:26:23 +08:00
};
2022-01-31 13:15:18 +08:00
this._websocket.onerror = (e: any) => {
2022-01-27 01:30:29 +08:00
if (!this._status) {
2022-03-25 18:56:55 +08:00
reject("Failed to connect to " + (this._isRendezvous ? "rendezvous" : "relay") + " server");
2022-01-27 01:30:29 +08:00
return;
}
2022-01-19 22:26:23 +08:00
this._status = e;
2022-02-06 16:24:31 +08:00
console.error("WebSock.onerror: ")
console.error(e);
2022-01-19 22:26:23 +08:00
this._eventHandlers.error(e);
};
});
}
2022-01-17 18:11:14 +08:00
2022-02-05 01:55:23 +08:00
async next(
timeout = 12000
): Promise<rendezvous.RendezvousMessage | message.Message> {
2022-01-20 01:00:35 +08:00
const func = (
2022-02-05 01:55:23 +08:00
resolve: (value: rendezvous.RendezvousMessage | message.Message) => void,
2022-01-19 22:26:23 +08:00
reject: (reason: any) => void,
tm0: number
) => {
if (this._buf.length) {
resolve(this._buf[0]);
this._buf.splice(0, 1);
} else {
2022-01-20 01:00:35 +08:00
if (this._status != "open") {
2022-01-19 22:26:23 +08:00
reject(this._status);
return;
}
if (new Date().getTime() > tm0 + timeout) {
2022-01-30 19:48:41 +08:00
reject("Timeout");
2022-01-19 22:26:23 +08:00
} else {
setTimeout(() => func(resolve, reject, tm0), 1);
}
2022-01-18 02:02:39 +08:00
}
};
2022-01-19 22:26:23 +08:00
return new Promise((resolve, reject) => {
func(resolve, reject, new Date().getTime());
});
2022-01-18 02:02:39 +08:00
}
2022-01-17 18:11:14 +08:00
2022-01-18 02:02:39 +08:00
close() {
2022-01-30 03:39:54 +08:00
this._status = "";
2022-01-18 02:02:39 +08:00
if (this._websocket) {
if (
this._websocket.readyState === WebSocket.OPEN ||
this._websocket.readyState === WebSocket.CONNECTING
) {
console.info("Closing WebSocket connection");
this._websocket.close();
}
2022-01-17 18:11:14 +08:00
2022-01-19 22:26:23 +08:00
this._websocket.onmessage = () => {};
2022-01-17 18:11:14 +08:00
}
2022-01-18 02:02:39 +08:00
}
2022-01-17 18:11:14 +08:00
2022-01-18 02:02:39 +08:00
_recv_message(e: any) {
if (e.data instanceof window.ArrayBuffer) {
2022-01-20 18:02:20 +08:00
let bytes = new Uint8Array(e.data);
const k = this._secretKey;
if (k) {
k[2] += 1;
bytes = globals.decrypt(bytes, k[2], k[0]);
}
2022-02-06 16:24:31 +08:00
this._buf.push(
this._isRendezvous
? this.parseRendezvous(bytes)
: this.parseMessage(bytes)
);
2022-01-17 18:11:14 +08:00
}
2022-01-19 19:19:29 +08:00
this._eventHandlers.message(e.data);
2022-01-18 02:02:39 +08:00
}
}