UNPKG

slavery-js

Version:

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

1 lines 18.3 kB
{"version":3,"sources":["../../src/network/Connection.ts"],"sourcesContent":["import { io } from \"socket.io-client\";\nimport { Socket } from 'socket.io';\nimport log from '../utils/log.js';\nimport type Listener from './types/Listener.js';\n\ntype ConnectionOptions = {\n timeout?: number,\n listeners?: Listener[],\n onConnect?: Function,\n onDisconnect?: Function,\n onSetListeners?: Function\n};\n\ntype ConnectionParametersServer = {\n socket: Socket,\n name: string,\n options?: ConnectionOptions\n};\n\ntype ConnectionParametersClient = {\n host: string,\n port: number,\n id: string,\n options?: ConnectionOptions\n};\n\nfunction isServer(params: ConnectionParametersServer | ConnectionParametersClient): params is ConnectionParametersClient {\n return 'host' in params && 'port' in params && 'id' in params;\n}\n\nfunction isClient(params: ConnectionParametersServer | ConnectionParametersClient): params is ConnectionParametersServer {\n return 'socket' in params && 'name' in params;\n}\n\n\nclass Connection {\n /*\n * this class is manager for the socket instance\n * it takes either a socket or a host and port to create the socket\n * if it takes the host and port it will consider that connection is a server\n * if it takes a socket it will consider that connection is a client\n *\n * it manages conenction, the listeners and the available emitters */\n private socket: Socket | any;\n private request_id: number = 0;\n // this node information\n public name?: string;\n public id?: string;\n public type: 'client' | 'server';\n public host?: string;\n public port?: number;\n // is connected or not\n public isConnected: boolean;\n // ot target of the socket\n public socketId: string;\n public targetType: 'client' | 'server';\n public targetName?: string;\n public targetId?: string;\n public targetListeners: Listener[] = [];\n public targetHost?: string;\n public targetPort?: number;\n // callbacks\n public options: {\n timeout: number,\n listeners: Listener[],\n onConnect: Function,\n onDisconnect: Function,\n onSetListeners: Function\n };\n\n /*\n * @param Node: Node\n * @param socket: Socket\n * @param host: string\n * @param port: number\n * @param id: string\n * @param name: string\n * */\n\n constructor(params : ConnectionParametersServer | ConnectionParametersClient) {\n // options\n this.options = { \n // callbacks\n onConnect: params?.options?.onConnect || (() => {}),\n onDisconnect: params?.options?.onDisconnect || (() => {}),\n onSetListeners: params?.options?.onSetListeners || (() => {}),\n // listeners\n listeners: params?.options?.listeners || [],\n // timeout\n timeout: params?.options?.timeout || 5 * 60 * 1000, // 5 minutes\n };\n // if get a socket to connect to the server\n if (isClient(params)) {\n params = params as unknown as ConnectionParametersServer;\n this.type = 'server';\n this.name = params.name;\n this.targetType = 'client';\n // the socket\n this.socket = params.socket;\n // get the id of client\n this.targetId = params.socket.handshake.auth.id;\n //log('[Connection][server] targetId: ', this.targetId)\n // since we are already getting the socket\n this.isConnected = true;\n // if get a host and port to connect to the server\n } else if (isServer(params)) {\n params = params as unknown as ConnectionParametersClient;\n this.type = 'client';\n this.targetType = 'server';\n // use the id\n this.id = params.id;\n this.socket = io(`ws://${params.host}:${params.port}`, {\n auth: { id: params.id },\n timeout: this.options.timeout || 5 * 60 * 1000, // default 5 minutes\n });\n // since we are not connected yet\n this.isConnected = false;\n } else\n throw new Error('Connection must have either a socket and a name or a host and port');\n // set the socket id\n this.socketId = this.socket.id;\n // initialize the listeners\n this.initilaizeListeners()\n }\n\n private initilaizeListeners(): void {\n /* this function inizializes the default listeners for the socket */\n // set the object listeners\n this.options.listeners.forEach( l => {\n this.socket.removeAllListeners(l.event);\n this.socket.on(l.event, this.respond(l.event, async (parameters:any) => {\n //log(`[${this.id}] [Connection][initilaizeListeners] got event: ${l.event} from ${this.targetName}: `, parameters)\n return await l.callback(parameters);\n }));\n });\n // if target is asking for connections\n this.socket.on(\"_listeners\", this.respond(\"_listeners\", () => this.getListeners()));\n // if the target is sending a their listeners\n this.socket.on(\"_set_listeners\", this.respond(\"_set_listeners\", (listeners: string[]) => {\n //log(`[${this.id}] [Connection][Node] got liteners from ${this.targetName}: `, listeners)\n this.targetListeners =\n listeners.map(event => ({ event, callback: () => {} }));\n this.options.onSetListeners(this.targetListeners);\n return 'ok';\n }));\n // if target is asking for name\n this.socket.on(\"_name\", this.respond(\"_name\", () => this.name));\n // if target is asking for id\n this.socket.on(\"_id\", () => this.id);\n // on connected\n this.socket.on(\"connect\", async () => {\n //log(`[connection][${this.socket.id}] is connected, querying target name and listeners:`)\n // ask for listeners\n this.targetName = await this.queryTargetName();\n this.targetListeners = await this.queryTargetListeners();\n //log(`[connection][${this.socket.id}] target name: ${this.targetName}, target listeners: ${this.targetListeners}`)\n this.isConnected = true;\n this.options.onConnect(this);\n });\n // if it disconnects\n this.socket.on(\"reconnect\", async (attempt: number) => {\n //log(`[connection][${this.socket.id}] is reconnected, attempt: ${attempt}`)\n this.targetName = await this.queryTargetName();\n this.targetListeners = await this.queryTargetListeners();\n this.isConnected = true;\n this.options.onConnect(this);\n });\n // if it disconnects\n this.socket.on(\"diconnect\", () => {\n //log(`[connection][${this.socket.id}] is disconnected`)\n this.isConnected = false;\n this.options.onDisconnect(this);\n });\n }\n\n public async connected(): Promise<boolean> {\n return new Promise((resolve, reject) => {\n let interval: NodeJS.Timeout;\n let timeout: NodeJS.Timeout\n // set interval to check for connection\n interval = setInterval(() => {\n if(this.isConnected) {\n clearInterval(interval);\n clearTimeout(timeout);\n resolve(true);\n }\n }, 100); // 100 ms\n // set timeout to reject if no connection\n timeout = setTimeout(() => {\n clearInterval(interval);\n reject(false);\n }, 1000 * 60 ); // 1 minute\n })\n }\n\n\n public getType(){\n return this.type;\n }\n\n public on(event: string, callback: Function): void {\n this.socket.on(event, callback);\n }\n\n public emit(event: string, data: any): void {\n this.socket.emit(event, data);\n }\n\n public getName(): string | undefined {\n return this.name;\n }\n\n // this is the id of the conenction?\n public getId(): string | undefined {\n return this.id;\n }\n\n public getTargetName(): string | undefined {\n return this.targetName;\n }\n\n // this is the id of the target client\n public getTargetId(): string | undefined {\n return this.targetId;\n }\n\n public async setListeners(listeners: Listener[]): Promise<void> {\n // set the listeners on the socket\n listeners.forEach( l => {\n this.options.listeners.push(l);\n // remove the listener if it exists\n this.socket.removeAllListeners(l.event);\n // add new listener\n this.socket.on(l.event, this.respond(l.event, async (parameters:any) => {\n // run the callback defined in the listner\n return await l.callback(parameters);\n }));\n });\n // update the listeners on the target\n if(this.type === 'server'){\n await this.query('_set_listeners', listeners.map(listener => listener.event));\n }\n }\n\n public addListeners(listeners: Listener[]): void {\n // make sure we are not adding the same listener\n const eventMap = new Map(this.options.listeners.map(l => [l.event, l]));\n // add the listeners\n listeners.forEach( l => eventMap.set(l.event, l) );\n // set the listeners in the connection\n this.options.listeners = Array.from(eventMap.values());\n // set the listeners on the socket\n this.setListeners(this.options.listeners);\n }\n\n public getTargetListeners(): Listener[] {\n return this.targetListeners;\n }\n\n public onSetListeners(callback: Function): void {\n this.options.onSetListeners = callback;\n }\n\n public onConnect(callback: Function): void {\n this.options.onConnect = callback;\n }\n\n public onDisconnect(callback: Function): void {\n this.options.onDisconnect = callback;\n }\n\n private queryTargetListeners(): Promise<Listener[]> {\n // query the target listeners\n return this.query('_listeners');\n }\n\n private queryTargetName(): Promise<string> {\n // query the target name\n return this.query('_name');\n }\n\n public async query(event: string, data?: any, retries = 3, retryDelay = 500): Promise<any> {\n let attempt = 0;\n const tryQuery = (): Promise<any> => {\n return new Promise((resolve, reject) => {\n const request_id = ++this.request_id;\n if (this.request_id >= Number.MAX_SAFE_INTEGER - 1) this.request_id = 0;\n const responseEvent = `${event}_${request_id}_response`;\n const timeoutDuration = this.options.timeout || 5000;\n const timeout = setTimeout(() => {\n this.socket.removeAllListeners(responseEvent);\n reject(new Error(`Query '${event}' timed out after ${timeoutDuration}ms (attempt ${attempt + 1})`));\n }, timeoutDuration);\n this.socket.once(responseEvent, (response: any) => {\n clearTimeout(timeout);\n resolve(response);\n });\n this.socket.emit(event, { data, request_id });\n });\n };\n while (attempt <= retries) {\n try {\n return await tryQuery();\n } catch (err) {\n if (attempt >= retries) {\n throw new Error(`Query '${event}' failed after ${retries + 1} attempts: ${err}`);\n }\n attempt++;\n await new Promise((r) => setTimeout(r, retryDelay)).catch(e => {\n throw new Error(`Error during retry delay: ${e}`);\n });\n }\n }\n // This should never be reached, but TypeScript wants a return or throw here\n throw new Error('Unexpected query failure');\n }\n\n public send = this.query;\n\n private respond(event: string, callback: Function) {\n /* this is a wrapper function to respond to a query */\n return async (parameters: any) => {\n let data = parameters.data;\n let request_id = parameters.request_id;\n let response = await callback(data);\n this.socket.emit(event + `_${request_id}_response`, response);\n }\n }\n\n public getListeners(): any[] {\n if(this.type === 'server')\n return this.options.listeners;\n else if(this.type === 'client')\n return this.socket._callbacks;\n else\n throw new Error('Connection type not recognized');\n }\n\n public close(): void {\n this.socket.disconnect();\n }\n\n}\n\nexport default Connection;\n"],"mappings":"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","names":[]}