@iprokit/service
Version:
Powering distributed systems with simplicity and speed.
303 lines (302 loc) • 9.3 kB
TypeScript
/**
* @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 {};