UNPKG

@akala/json-rpc-ws

Version:

json-rpc websocket transport

132 lines (131 loc) 5.68 kB
import { type Error as ConnectionError, type ErrorTypes } from './errors.js'; import type { EventListener, SerializableObject, SocketAdapter, SocketAdapterAkalaEventMap, SocketAdapterEventMap, Subscription } from '@akala/core'; import { SocketProtocolAdapter } from '@akala/core'; export type PayloadDataType<T> = number | SerializableObject | SerializableObject[] | boolean | boolean[] | number[] | string | string[] | null | undefined | void | { event: string; isBuffer: boolean; data: string | SerializedBuffer; } | T; export type SerializedBuffer = { type: 'Buffer'; data: Uint8Array | number[]; }; export type Payload<T> = SerializablePayload | StreamPayload<T>; export declare class JsonRpcSocketAdapter<TStreamable> extends SocketProtocolAdapter<Payload<TStreamable> | Payload<TStreamable>[]> implements SocketAdapter<Payload<TStreamable>> { constructor(socket: SocketAdapter); } interface CommonPayload { jsonrpc?: '2.0'; id?: string | number; method?: string; error?: ConnectionError; } export interface SerializablePayload extends CommonPayload { params?: PayloadDataType<void>; result?: PayloadDataType<void>; stream?: false; } export interface StreamPayload<T> extends CommonPayload { params?: T; result?: PayloadDataType<T>; stream?: true; } export type Handler<TConnection extends Connection<TStreamable>, TStreamable, ParamType extends PayloadDataType<TStreamable>, ParamCallbackType extends PayloadDataType<TStreamable>> = (this: TConnection, params: ParamType, reply: ReplyCallback<ParamCallbackType>) => void; export type ReplyCallback<ParamType> = (error: ConnectionError, params?: ParamType) => void; export interface Parent<TStreamable, TConnection extends Connection<TStreamable>> { type: string; getHandler: (method: string) => Handler<TConnection, TStreamable, PayloadDataType<TStreamable>, PayloadDataType<TStreamable>>; disconnected: (connection: TConnection) => void; } /** * json-rpc-ws connection * * @constructor * @param {SocketAdapter} socket - socket adapter for this connection * @param {Object} parent - parent that controls this connection */ export declare abstract class Connection<TStreamable> { readonly socket: SocketAdapter<Payload<TStreamable>>; readonly parent: Parent<TStreamable, Connection<TStreamable>>; sub: Subscription; /** * */ constructor(socket: SocketAdapter<Payload<TStreamable>>, parent: Parent<TStreamable, Connection<TStreamable>>); on<K extends keyof SocketAdapterEventMap>(event: K, handler: EventListener<SocketAdapterAkalaEventMap<Payload<TStreamable>>[K]>): Subscription; once<K extends keyof SocketAdapterEventMap>(event: K, handler: EventListener<SocketAdapterAkalaEventMap<Payload<TStreamable>>[K]>): Subscription; readonly id: `${string}-${string}-${string}-${string}-${string}`; protected readonly responseHandlers: { [messageId: string]: ReplyCallback<unknown>; }; /** * Send json payload to the socket connection * * @param {Object} payload - data to be stringified * @private * @todo validate payload * @todo make sure this.connection exists, is connected * @todo if we're not connected look up the response handler from payload.id */ sendRaw(payload: Payload<TStreamable>): void; /** * Validate payload as valid jsonrpc 2.0 * http://www.jsonrpc.org/specification * Reply or delegate as needed * * @param {Object} payload - payload coming in to be validated * @returns {void} */ processPayload(payload: Payload<TStreamable>): void; protected abstract buildStream(id: string | number, result: PayloadDataType<TStreamable>): TStreamable; protected abstract sendStream(id: string | number, result: TStreamable): Promise<void> | void; protected abstract isStream(result: PayloadDataType<TStreamable>): result is TStreamable; /** * Send a result message * * @param {String} id - id for the message * @param {Object} error - error for the message * @param {String|Object|Array|Number} result - result for the message * @public * */ sendResult(id: string | number | undefined, error: ConnectionError | undefined, result?: PayloadDataType<TStreamable>, isStream?: boolean): void; /** * Send a method message * * @param {String} method - method for the message * @param {Array|Object|null} params - params for the message * @param {function} callback - optional callback for a reply from the message * @public */ sendMethod<TParamType extends PayloadDataType<TStreamable>, TReplyType extends PayloadDataType<TStreamable>>(method: string, params?: TParamType, callback?: ReplyCallback<TReplyType>): void; /** * Send an error message * * @param {Object} error - json-rpc error object (See Connection.errors) * @param {String|Number|null} id - Optional id for reply * @param {Any} data - Optional value for data portion of reply * @public */ sendError(error: ErrorTypes, id: number | string | undefined, data?: SerializableObject): void; /** * Called when socket gets 'close' event * * @param {ConnectionError} error - optional error object of close wasn't expected * @private */ close(error?: ConnectionError | 1000 | Error | Event): void; /** * Hang up the current socket */ hangup(): Promise<CloseEvent>; /** * Incoming message handler * * @param {String} data - message from the websocket * @returns {void} * @private */ private message; } export {};