UNPKG

@underpostnet/underpost

Version:

Underpost Platform — end-to-end CI/CD and application-delivery toolchain CLI. Covers bare metal, Kubernetes, K3s, kubeadm, LXD, container/image orchestration, secrets, databases, cron jobs, monitoring, SSH, runners, PWA + Workbox delivery, and release orc

117 lines (103 loc) 3.58 kB
/** * Mailer WebSocket channel — manages user↔socket bidirectional mapping * for targeted real-time pushes (e.g. email confirmation notifications). * @module ws/core/channels/core.ws.mailer */ import { IoChannel } from '../../IoInterface.js'; /** * @class CoreWsMailerChannel * @classdesc Manages the mailer WebSocket channel with O(1) user↔socket lookup. * Handles register/unregister messages and cleanup on disconnect. */ class CoreWsMailerChannel { /** @type {Object.<string, Object.<string, { model: { user: Object } }>>} Socket data keyed by `[hostKeyContext][socketId]`. */ static #data = {}; /** @type {Object.<string, Object.<string, string>>} Reverse index: `[hostKeyContext][userId]` → socketId. */ static #userIndex = {}; /** @type {IoChannel} */ static #io = new IoChannel({ channel: 'mailer', controller(socket, client, payload, hostKeyContext) { switch (payload.status) { case 'register-user': CoreWsMailerChannel.setUser(hostKeyContext, socket.id, payload.user); break; case 'unregister-user': CoreWsMailerChannel.removeSocket(hostKeyContext, socket.id); break; default: break; } }, disconnect(socket, client, reason, hostKeyContext) { CoreWsMailerChannel.removeSocket(hostKeyContext, socket.id); }, }); /** @returns {Object.<string, import('socket.io').Socket>} Connected sockets map. */ static get client() { return this.#io.client; } /** @returns {string} Channel name. */ static get channel() { return this.#io.channel; } /** * Initializes state for a server instance. * @param {string} hostKeyContext - Unique server context ID (`${host}${path}`). */ static init(hostKeyContext) { this.#data[hostKeyContext] = {}; this.#userIndex[hostKeyContext] = {}; } /** * Registers a socket connection. * @param {import('socket.io').Socket} socket * @param {string} hostKeyContext */ static connection(socket, hostKeyContext) { return this.#io.connection(socket, hostKeyContext); } /** * Handles socket disconnection. * @param {import('socket.io').Socket} socket * @param {string} reason * @param {string} hostKeyContext */ static disconnect(socket, reason, hostKeyContext) { return this.#io.disconnect(socket, reason, hostKeyContext); } /** * Registers a user↔socket mapping. * @param {string} hostKeyContext * @param {string} socketId * @param {Object} user - User data with `_id` property. */ static setUser(hostKeyContext, socketId, user) { this.#data[hostKeyContext][socketId] = { model: { user } }; if (user?._id) { this.#userIndex[hostKeyContext][user._id.toString()] = socketId; } } /** * Removes a socket entry and its reverse user index. * @param {string} hostKeyContext * @param {string} socketId */ static removeSocket(hostKeyContext, socketId) { const entry = this.#data[hostKeyContext]?.[socketId]; if (entry?.model?.user?._id) { delete this.#userIndex[hostKeyContext][entry.model.user._id.toString()]; } delete this.#data[hostKeyContext]?.[socketId]; } /** * Finds the socket ID for a user (O(1) reverse index lookup). * @param {string} hostKeyContext * @param {string} userId - The user `_id`. * @returns {string|undefined} Socket ID, or `undefined` if not connected. */ static getUserWsId(hostKeyContext, userId) { return this.#userIndex[hostKeyContext]?.[userId]; } } export { CoreWsMailerChannel };