UNPKG

ziron-server

Version:
203 lines (202 loc) 8.71 kB
import ServerOptions from "./ServerOptions"; import { OriginsChecker } from "./OriginsChecker"; import AuthEngine from "./AuthEngine"; import Socket from "./Socket"; import EventEmitter from "emitix"; import ChannelExchange from "./ChannelExchange"; import InternalBroker from "./broker/InternalBroker"; import { HttpResponse } from "./http/EnhanceHttpResponse"; import UpgradeRequest from "./http/UpgradeRequest"; import { BatchOption, ComplexTypesOption } from "ziron-engine"; import { SkipGroupMemberOption } from "./Options"; import { HttpRequest } from "./http/EnhanceHttpRequest"; type LocalEvents<S extends Socket> = { 'error': [Error]; 'warning': [Error]; 'badSocketAuthToken': [S, Error, string]; 'disconnection': [S, number, any]; }; type UpgradeMiddleware = (req: UpgradeRequest) => Promise<void> | void; type SocketMiddleware<S extends Socket> = (socket: S) => Promise<void> | void; type AuthenticateMiddleware<S extends Socket> = (socket: S, authToken: object, signedAuthToken: string) => Promise<void> | void; type SubscribeMiddleware<S extends Socket> = (socket: S, channel: string) => Promise<void> | void; type PublishInMiddleware<S extends Socket> = (socket: S, channel: string, data: any) => Promise<void> | void; /** * @description * The Ziron server. * Mostly everything is related to web socket protocol on the server instance. * But an HTTP/HTTPS server is created to catch upgrade requests and to create a health endpoint. * All other HTTP requests will be answered with 426 (Upgrade Required), * but it is possible to provide a custom HTTP request handler. */ export default class Server<E extends { [key: string]: any[]; } = {}, ES extends Socket = Socket> { private readonly _compressionOptions; readonly originsChecker: OriginsChecker; readonly auth: AuthEngine; get id(): string; get port(): number; get path(): string; get tls(): boolean; private _authTokenExpireCheckerTicker; private _pingTicker; private _listenToken?; private _startListenPromise?; private readonly _groupTransport; protected emitter: (EventEmitter<LocalEvents<ES>> & EventEmitter<E>); readonly once: (EventEmitter<LocalEvents<ES>> & EventEmitter<E>)['once']; readonly on: (EventEmitter<LocalEvents<ES>> & EventEmitter<E>)['on']; readonly off: (EventEmitter<LocalEvents<ES>> & EventEmitter<E>)['off']; /** * @description * The connected web socket clients count. */ readonly clientCount: number; /** * @description * The connected web socket clients. */ readonly clients: Record<string, ES>; /** * @description * This is a counter of WebSocket messages. * You can reset this counter with the resetWsMessageCount method. */ readonly wsMessageCount: number; /** * @description * This is a counter of received invoke messages. * You can reset this counter with the resetInvokeMessageCount method. */ readonly invokeMessageCount: number; /** * @description * This is a counter of received transmit messages. * You can reset this counter with the resetTransmitMessageCount method. */ readonly transmitMessageCount: number; /** * @description * This is a counter of HTTP messages. * You can reset this counter with the resetHttpMessageCount method. */ readonly httpMessageCount: number; /** * @description * Specify a socket constructor extension. * This extension will be called in the socket constructor and * can be used to add properties to the Socket instance. * Use this extension only when you know what you are doing. * It is also recommended specifying this new Socket type at the * generic ES (extended socket) parameter of the Server class. * This approach is implemented rather than a custom Socket class to prevent * a larger proto chain and for the ability to add external variables into the constructor easily. */ socketConstructorExtension: (socket: Socket) => void; /** * @description * The connection handler will be called when a new socket is connected. * The handler can be used to register receivers or procedures on the socket. * The returned value will be transmitted to the client. * Promises are considered, and the connection is only ready when the promise is resolved. */ connectionHandler: (socket: ES) => Promise<any> | any; /** * @description * Set this property to handle HTTP requests. * Notice that firstly Ziron checks the origin and catches and processes health endpoint requests. * The handler will be called when the request is not answered after the Ziron pipeline. * If the response is still available after the Ziron pipeline and * the handler call Ziron responds with a 426 (Upgrade Required) response. */ httpRequestHandler?: (req: HttpRequest, res: HttpResponse) => Promise<any> | any; /** * @description * Specify a custom health check. * This health check is used to process the value for the health endpoint. * This endpoint could be used for docker health checks. */ healthCheck: () => Promise<boolean> | boolean; upgradeMiddleware: UpgradeMiddleware | undefined; socketMiddleware: SocketMiddleware<ES> | undefined; authenticateMiddleware: AuthenticateMiddleware<ES> | undefined; subscribeMiddleware: SubscribeMiddleware<ES> | undefined; publishInMiddleware: PublishInMiddleware<ES> | undefined; protected readonly internalBroker: InternalBroker; readonly channels: ChannelExchange; /** * @description * Boolean that indicates if the server should reject web socket handshakes. */ refuseConnections: boolean; ignoreFurtherTransmits: boolean; ignoreFurtherInvokes: boolean; constructor(options?: ServerOptions); private _createGroupTransport; private _createTransportOptions; private _loadCompressionOptions; private _setUpSocketChLimit; private _setUpApp; private _startPingInterval; private _startAuthExpireCheck; private static _abortUpgrade; private _handleUpgrade; private _handleWsOpen; private _handleWsMessage; private static _handleWsDrain; private static _handleWsClose; private _setupHttpRequestHandling; private _processHttpHealthCheckRequest; /** * @description * Sends a transmit to a group. * Instead of channels, groups can only be accessed and controlled from the server-side and * messages are not shared across multiple server instances. * Groups don't have their own special protocol and can be used to send a standard * transmit optimized to multiple sockets of a group. * Additionally, the group transmits support batching when not using the skipMember option. * When using the skipMember option, the batch option will be ignored. * Internally prepareMultiTransmit is used to create the transmit packet, * so binary data is supported. * @param group * @param receiver * @param data * @param options */ transmitToGroup(group: string, receiver: string, data?: any, options?: ComplexTypesOption & BatchOption & SkipGroupMemberOption): void; /** * @description * Returns the member count of a specific group from this server instance. * Instead of channels, groups can only be accessed and controlled from the server-side and * messages are not shared across multiple server instances. * Groups don't have their own special protocol and can be used to send a standard * transmit optimized to multiple sockets of a group. * Additionally, the group transmits support batching when not using the skipMember option. * Internally prepareMultiTransmit is used to create the transmit packet, * so binary data is supported. * @param group */ getGroupMemberCount(group: string): number; listen(): Promise<void>; getInternalSubscriptions(): string[]; resetWsMessageCount(): void; resetInvokeMessageCount(): void; resetTransmitMessageCount(): void; resetHttpMessageCount(): void; /** * @description * Resets all counts (wsMessageCount,invokeMessageCount,transmitMessageCount and httpMessageCount). */ resetCounts(): void; stopListen(): void; isListening(): boolean; /** * Terminates the server. * After termination, you should not use this instance anymore * or anything else from the server. * [Use this method only when you know what you do.] */ terminate(): void; } export {};