import assert from "assert"; import { mkdir } from "fs/promises"; import { Socket } from "net"; import { dirname } from "path"; import { Microservice } from "@autoplex/microservice"; import { IIpcRequest, IPC } from "./schema"; import AbstractIpcService from "./AbstractIpcService"; type IpcServer = IPC["server"]; export abstract class IpcServerService extends AbstractIpcService { /** * The IPC server instance */ private __server!: IpcServer|null; // Service Implementation ---------------------------------------------------------------------- /** * Install the event handlers for receiving on the IPC socket * * Example: this.addMessageHandler("some_event", this.onSomeEvent) */ protected installMessageHandlers() { // no-op } // Service Management -------------------------------------------------------------------------- /** * Boot the IPC service */ public bootIpc(ipc: IPC) { return new Promise(async (resolve) => { // Create the socket directory if it doesn't exist await mkdir(dirname(this.SOCKET_PATH), { recursive: true }); // Serve the IPC server ipc.serve(this.SOCKET_PATH, () => { this.__server = ipc.server; this.installMessageHandlers(); resolve(); }); ipc.server.start(); }); } /** * Add a message/request handler for the server */ protected addMessageHandler(method: string, handle: (...args: any[]) => Promise) { assert(this.__server !== null, "Attempted to add events to null server"); this.__server.on(method, async (request: IIpcRequest, socket: Socket) => { let handlerPromise = handle.apply(this, [request.data]); if (request.id === null) { handlerPromise.catch(error => this.log("Error:", method, error, request)); return; } const responseMethod = `method_response_${request.id}`; try { this.__server!.emit(socket, responseMethod, { data: await handlerPromise }); } catch(error) { this.log(this.log("Error:", method, error, request)); this.__server!.emit(socket, responseMethod, { error }); } }); } /** * Shutdown the IPC service */ public async shutdownIpc(ipc: IPC|null) { this.__server?.stop(); this.__server = null; for (let socket of Object.values(ipc?.of ?? [])) { socket.destroy(); } } // Methods ------------------------------------------------------------------------------------- /** * Broadcast a message to all connected clients */ public broadcast(method: string, data?: any) { if (this.__server === null) { return; } this.__server.emit(method, data); } }