UNPKG

@iprokit/service

Version:

Powering distributed systems with simplicity and speed.

303 lines (302 loc) 9.3 kB
/** * @iProKit/Service * Copyright (c) 2019-2025 Rutvik Katuri / iProTechs * SPDX-License-Identifier: Apache-2.0 */ /// <reference types="node" /> import net, { Socket as TcpSocket } from 'net'; import { Mode, Parameters } from './rfi'; import Protocol, { Incoming, Outgoing } from './protocol'; import { Conductor } from './coordinator'; declare const connections: unique symbol; /** * `Server` binds to an IP address and port number, listening for incoming SCP client connections. * Manages registered executions to handle various SCP modes and dispatches I/Os to the appropriate execution handlers. * * @emits `incoming` when a new incoming stream is received. * @emits `clientError` when an error occurs on the client connection. */ export default class Server extends net.Server implements IServer { /** * Unique identifier of the server. */ readonly identifier: string; /** * Executions registered on the server. */ readonly executions: Array<Execution>; /** * Client socket connections. */ private readonly [connections]; /** * Creates an instance of SCP `Server`. * * @param identifier unique identifier of the server. */ constructor(identifier: string); /** * @emits `incoming` when a new incoming stream is received. * @emits `clientError` when an error occurs on the client connection. */ private onConnection; /** * - Subscribe is handled by `subscribe` function. * - Omni is handled by `dispatch` function. */ private onIncoming; /** * Recursively loop through the executions to find and execute its handler. * * @param executionIndex index of the current execution being processed. * @param executions executions to be processed. * @param incoming incoming stream. * @param outgoing outgoing stream. * @param unwind function called once the processed executions unwind. */ private dispatch; /** * Registers a subscription from the client socket connection. * Broadcasts are only sent to subscribed connections. */ private subscribe; broadcast(operation: string, ...args: Array<any>): Promise<string[]>; attach(operation: string, executor: IExecutor): this; reply: <Returned>(operation: string, func: ReplyFunction<Returned>) => this; conductor: (operation: string, func: ConductorFunction) => this; omni: (operation: string, handler: IncomingHandler) => this; close(callback?: (error?: Error) => void): this; } /** * Interface for the SCP `Server`. */ export interface IServer extends IExecutor { /** * Broadcasts the supplied to all subscribed client socket connections. * * Returns identifiers of client sockets to which the broadcast was sent. * Receipt of the broadcast is not guaranteed. * * @param operation operation pattern. * @param args arguments to broadcast. */ broadcast: (operation: string, ...args: Array<any>) => Promise<Array<string>>; /** * Attaches a executor. * * @param operation operation pattern. * @param executor executor to attach. */ attach: (operation: string, executor: IExecutor) => this; } /** * Registers executions that handle SCP I/Os. * Once attached, SCP I/Os are dispatched to the appropriate registered executions. */ export declare class Executor implements IExecutor { /** * Executions registered. */ readonly executions: Array<Execution>; /** * Creates an instance of `Executor`. */ constructor(); reply: <Returned>(operation: string, func: ReplyFunction<Returned>) => this; conductor: (operation: string, func: ConductorFunction) => this; omni: (operation: string, handler: IncomingHandler) => this; /** * Applies properties of `IExecutor` interface to the provided instance, * enabling registration of executions. * * @param instance instance to which the `IExecutor` properties are applied. */ static applyProperties<I extends IExecutor>(instance: I): void; /** * Registers an individual SCP nexus for handling specific SCP mode and operation pattern. * * @param instance executor instance where the nexus will be registered. * @param mode SCP mode of the nexus. * @param operation operation pattern of the nexus. * @param handler handler function of the nexus. */ private static registerNexus; /** * Creates a handler for executing reply function. * * @param func reply function to execute. */ private static replyHandler; /** * Creates a handler for executing conductor function. * * @param func conductor function to execute. */ private static conductorHandler; } /** * Interface for the `Executor`. */ export interface IExecutor { /** * Executions registered. */ executions: Array<Execution>; /** * Registers a execution for handling REPLY I/O. * * Handler function receives a message from a client socket connection and returns a reply. * * @param operation operation pattern. * @param func function to be executed. */ reply: <Returned>(operation: string, func: ReplyFunction<Returned>) => this; /** * Registers a execution for handling CONDUCTOR I/O. * * Handler function receives a message from a client socket connection and coordinates signals. * * @param operation operation pattern. * @param func function to be executed. */ conductor: (operation: string, func: ConductorFunction) => this; /** * Registers a execution for handling OMNI I/O. * * @param operation operation pattern. * @param handler incoming handler function. */ omni: (operation: string, handler: IncomingHandler) => this; } /** * Union of `Segment` and `Nexus`. */ export type Execution = Segment | Nexus; /** * Represents a group of executions. */ export interface Segment { /** * Operation pattern of the segment. */ operation: string; /** * Compiled regular expression to match operation pattern of the segment. */ regExp: RegExp; /** * Executions registered in the segment. */ executions: Array<Nexus>; } /** * Represents a nexus. */ export interface Nexus { /** * SCP mode of the nexus. */ mode: Mode; /** * Operation pattern of the nexus. */ operation: string; /** * Compiled regular expression to match operation pattern of the nexus. */ regExp: RegExp; /** * Incoming handler function of the nexus. */ handler: IncomingHandler; } /** * Incoming handler. */ export type IncomingHandler = (incoming: ServerIncoming, outgoing: ServerOutgoing, proceed: ProceedFunction) => void; /** * Proceed function. */ export type ProceedFunction = () => void; /** * Reply function. */ export type ReplyFunction<Returned> = (...args: Array<any>) => Promise<Returned> | Returned; /** * Conductor function. */ export type ConductorFunction = (conductor: Conductor, ...args: Array<any>) => Promise<void> | void; /** * Represents a client socket connection used by the SCP `Server`. * * @emits `incoming` when a new incoming stream is received. */ export declare class Connection extends Protocol { #private; /** * Unique identifier of the client socket connection. */ identifier: string; /** * `true` if the connection can accept broadcasts, `false` otherwise. */ canBroadcast: boolean; /** * Creates an instance of SCP `Connection`. * * @param socket underlying socket. */ constructor(socket: TcpSocket); /** * Creates a new `Incoming` and `Outgoing` stream. * Invoked recursively on the `close` event of the current outgoing stream to continuously listen for incoming streams. * * @emits `incoming` when a new incoming stream is received. */ private cycleIO; /** * Creates a new `Outgoing` stream. * * @param mode mode of the remote function. * @param operation operation of the remote function. * @param parameters parameters of the remote function. * @param callback callback executed when the outgoing stream is ready. */ createOutgoing(mode: Mode, operation: string, parameters: Parameters, callback: (outgoing: ServerOutgoing) => void): this; /** * Executes one outgoing callback at a time in FIFO manner. * Invoked recursively on the `close` event of the current outgoing stream. */ private executeOutgoing; } /** * Represents an SCP server incoming. */ export declare class ServerIncoming extends Incoming { /** * Underlying SCP stream. */ scp: Connection; /** * Segment portion of the operation pattern. */ segment: string; /** * Nexus portion of the operation pattern. */ nexus: string; /** * `true` if the segment matched, `false` otherwise. */ matched: boolean; } /** * Represents an SCP server outgoing. */ export declare class ServerOutgoing extends Outgoing { /** * Underlying SCP stream. */ scp: Connection; } export {};