UNPKG

slavery-js

Version:

A simple clustering app that allows you to scale an application on multiple thread, containers or machines

273 lines 9.22 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); var Connection_exports = {}; __export(Connection_exports, { default: () => Connection_default }); module.exports = __toCommonJS(Connection_exports); var import_socket = require("socket.io-client"); function isServer(params) { return "host" in params && "port" in params && "id" in params; } function isClient(params) { return "socket" in params && "name" in params; } class Connection { /* * @param Node: Node * @param socket: Socket * @param host: string * @param port: number * @param id: string * @param name: string * */ constructor(params) { /* * this class is manager for the socket instance * it takes either a socket or a host and port to create the socket * if it takes the host and port it will consider that connection is a server * if it takes a socket it will consider that connection is a client * * it manages conenction, the listeners and the available emitters */ __publicField(this, "socket"); __publicField(this, "request_id", 0); // this node information __publicField(this, "name"); __publicField(this, "id"); __publicField(this, "type"); __publicField(this, "host"); __publicField(this, "port"); // is connected or not __publicField(this, "isConnected"); // ot target of the socket __publicField(this, "socketId"); __publicField(this, "targetType"); __publicField(this, "targetName"); __publicField(this, "targetId"); __publicField(this, "targetListeners", []); __publicField(this, "targetHost"); __publicField(this, "targetPort"); // callbacks __publicField(this, "options"); __publicField(this, "send", this.query); this.options = { // callbacks onConnect: params?.options?.onConnect || (() => { }), onDisconnect: params?.options?.onDisconnect || (() => { }), onSetListeners: params?.options?.onSetListeners || (() => { }), // listeners listeners: params?.options?.listeners || [], // timeout timeout: params?.options?.timeout || 5 * 60 * 1e3 // 5 minutes }; if (isClient(params)) { params = params; this.type = "server"; this.name = params.name; this.targetType = "client"; this.socket = params.socket; this.targetId = params.socket.handshake.auth.id; this.isConnected = true; } else if (isServer(params)) { params = params; this.type = "client"; this.targetType = "server"; this.id = params.id; this.socket = (0, import_socket.io)(`ws://${params.host}:${params.port}`, { auth: { id: params.id }, timeout: this.options.timeout || 5 * 60 * 1e3 // default 5 minutes }); this.isConnected = false; } else throw new Error("Connection must have either a socket and a name or a host and port"); this.socketId = this.socket.id; this.initilaizeListeners(); } initilaizeListeners() { this.options.listeners.forEach((l) => { this.socket.removeAllListeners(l.event); this.socket.on(l.event, this.respond(l.event, async (parameters) => { return await l.callback(parameters); })); }); this.socket.on("_listeners", this.respond("_listeners", () => this.getListeners())); this.socket.on("_set_listeners", this.respond("_set_listeners", (listeners) => { this.targetListeners = listeners.map((event) => ({ event, callback: () => { } })); this.options.onSetListeners(this.targetListeners); return "ok"; })); this.socket.on("_name", this.respond("_name", () => this.name)); this.socket.on("_id", () => this.id); this.socket.on("connect", async () => { this.targetName = await this.queryTargetName(); this.targetListeners = await this.queryTargetListeners(); this.isConnected = true; this.options.onConnect(this); }); this.socket.on("reconnect", async (attempt) => { this.targetName = await this.queryTargetName(); this.targetListeners = await this.queryTargetListeners(); this.isConnected = true; this.options.onConnect(this); }); this.socket.on("diconnect", () => { this.isConnected = false; this.options.onDisconnect(this); }); } async connected() { return new Promise((resolve, reject) => { let interval; let timeout; interval = setInterval(() => { if (this.isConnected) { clearInterval(interval); clearTimeout(timeout); resolve(true); } }, 100); timeout = setTimeout(() => { clearInterval(interval); reject(false); }, 1e3 * 60); }); } getType() { return this.type; } on(event, callback) { this.socket.on(event, callback); } emit(event, data) { this.socket.emit(event, data); } getName() { return this.name; } // this is the id of the conenction? getId() { return this.id; } getTargetName() { return this.targetName; } // this is the id of the target client getTargetId() { return this.targetId; } async setListeners(listeners) { listeners.forEach((l) => { this.options.listeners.push(l); this.socket.removeAllListeners(l.event); this.socket.on(l.event, this.respond(l.event, async (parameters) => { return await l.callback(parameters); })); }); if (this.type === "server") { await this.query("_set_listeners", listeners.map((listener) => listener.event)); } } addListeners(listeners) { const eventMap = new Map(this.options.listeners.map((l) => [l.event, l])); listeners.forEach((l) => eventMap.set(l.event, l)); this.options.listeners = Array.from(eventMap.values()); this.setListeners(this.options.listeners); } getTargetListeners() { return this.targetListeners; } onSetListeners(callback) { this.options.onSetListeners = callback; } onConnect(callback) { this.options.onConnect = callback; } onDisconnect(callback) { this.options.onDisconnect = callback; } queryTargetListeners() { return this.query("_listeners"); } queryTargetName() { return this.query("_name"); } async query(event, data, retries = 3, retryDelay = 500) { let attempt = 0; const tryQuery = () => { return new Promise((resolve, reject) => { const request_id = ++this.request_id; if (this.request_id >= Number.MAX_SAFE_INTEGER - 1) this.request_id = 0; const responseEvent = `${event}_${request_id}_response`; const timeoutDuration = this.options.timeout || 5e3; const timeout = setTimeout(() => { this.socket.removeAllListeners(responseEvent); reject(new Error(`Query '${event}' timed out after ${timeoutDuration}ms (attempt ${attempt + 1})`)); }, timeoutDuration); this.socket.once(responseEvent, (response) => { clearTimeout(timeout); resolve(response); }); this.socket.emit(event, { data, request_id }); }); }; while (attempt <= retries) { try { return await tryQuery(); } catch (err) { if (attempt >= retries) { throw new Error(`Query '${event}' failed after ${retries + 1} attempts: ${err}`); } attempt++; await new Promise((r) => setTimeout(r, retryDelay)).catch((e) => { throw new Error(`Error during retry delay: ${e}`); }); } } throw new Error("Unexpected query failure"); } respond(event, callback) { return async (parameters) => { let data = parameters.data; let request_id = parameters.request_id; let response = await callback(data); this.socket.emit(event + `_${request_id}_response`, response); }; } getListeners() { if (this.type === "server") return this.options.listeners; else if (this.type === "client") return this.socket._callbacks; else throw new Error("Connection type not recognized"); } close() { this.socket.disconnect(); } } var Connection_default = Connection; //# sourceMappingURL=Connection.cjs.map