socio
Version:
A WebSocket Real-Time Communication (RTC) API framework.
60 lines (59 loc) • 2.37 kB
JavaScript
import { LogHandler, E } from "./logging.js";
import { WebSocket as nodeWebSocket } from "ws";
import { yaml_parse, yaml_stringify, ClientMessageKind } from './utils.js';
export class AdminClient extends LogHandler {
#ws;
#client_id = '';
#client_secret = '';
static #key = 1;
#is_ready = false;
#queries = {};
constructor({ url = '', client_secret = '', logging = { verbose: false, hard_crash: false } }) {
super({ prefix: 'SocioAdmin', ...logging });
if (client_secret.length < 16)
throw new E('client_secret length must be at least 16 char for safety. Got ', client_secret.length);
this.#client_secret = client_secret;
this.#ws = new nodeWebSocket(url);
this.#ws.on('error', this.HandleError);
this.#ws.on('message', this.#Message.bind(this));
}
#Message(d, isBinary) {
const { kind, data } = yaml_parse(d);
switch (kind) {
case ClientMessageKind.CON: {
this.#client_id = data;
if (this.#is_ready !== false && typeof this.#is_ready === "function")
this.#is_ready(true);
if (this.verbose)
this.done(`Connected.`, this.#client_id);
this.#is_ready = true;
break;
}
case ClientMessageKind.RES: {
this.HandleInfo('recv:', kind, data);
this.#HandleBasicPromiseMessage(data);
break;
}
default: throw new E(`Unrecognized message kind!`, kind, data);
}
}
get #GenKey() {
AdminClient.#key += 1;
return AdminClient.#key;
}
#HandleBasicPromiseMessage(data) {
if (data.id in this.#queries)
this.#queries[data.id](data?.result || null);
delete this.#queries[data.id];
}
Run(function_name, ...args) {
const id = this.#GenKey;
const prom = new Promise((res) => {
this.#queries[id] = res;
});
this.#ws.send(yaml_stringify({ kind: 'ADMIN', data: { id: id, client_secret: this.#client_secret, function: function_name, args: args } }));
return prom;
}
ready() { return this.#is_ready === true ? (new Promise(res => res(true))) : (new Promise(res => this.#is_ready = res)); }
Close() { this.#ws.close(); }
}