@loopeco/socketio
Version:
A enhanced LoopBack's WebSocket server based on socket.io
85 lines (69 loc) • 2.68 kB
text/typescript
import {Context, ControllerClass} from '@loopback/core';
import {HttpServerOptions} from '@loopback/http-server';
import {Socket} from 'socket.io';
import {ExtendedError} from 'socket.io/dist/namespace';
import {getMiddlewareContext, MiddlewareContext} from '@loopback/express';
import {DefaultEventsMap, EventsMap} from 'socket.io/dist/typed-events';
import {Request} from 'express';
import {SocketIoBindings} from './keys';
import {expressInit} from './express';
export type SocketIoOptions = HttpServerOptions;
export interface SocketIoSequence {
handle(methodName: string, args: unknown[], done: Function): Promise<void>;
}
export type SocketIoDoneFunction = (response: unknown) => Promise<void>;
export type SocketIoInvokeMethod = (
context: Context,
controller: ControllerClass,
methodName: string,
args: unknown[],
) => unknown;
export type SocketIoSendMethod = (done: Function, result: unknown) => unknown;
export type SocketIoRejectMethod = (done: Function, error: Error) => unknown;
export interface SocketIoNextFunction {
(err?: ExtendedError): void;
}
export interface SocketIoConnectionHandler<
ListenEvents extends EventsMap = DefaultEventsMap,
EmitEvents extends EventsMap = ListenEvents,
ServerSideEvents extends EventsMap = DefaultEventsMap,
> {
(socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>, next: SocketIoNextFunction): void;
}
export interface SocketIoHandlerContext {
socket: Socket;
}
/**
* A per-connection Context to combine an IoC container with handler
* context (socket, etc.).
*/
export class SocketIoConnectionContext extends MiddlewareContext implements SocketIoHandlerContext {
/**
* Constructor for `SocketContext`
* @param socket - SocketIO socket object
* @param parent - Parent context
* @param name - Name of the middleware context
*/
constructor(public readonly socket: Socket, parent?: Context, name?: string) {
super(...expressInit(socket), parent, name);
this.setupBindings();
}
protected setupBindings() {
this.bind(SocketIoBindings.SOCKET).to(this.socket);
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isConnectionContext(ctx: any): ctx is SocketIoConnectionContext {
return !!ctx && typeof ctx.bind === 'function' && !!ctx.socket;
}
export function getConnectionContext<T extends SocketIoConnectionContext = SocketIoConnectionContext>(
socket: Socket,
): T | undefined {
return getMiddlewareContext<T>(socket.request as Request);
}
export function getSocket(context: Context) {
if (isConnectionContext(context)) {
return context.socket;
}
return context.getSync(SocketIoBindings.SOCKET);
}