UNPKG

@ntlab/identity

Version:

A foundation for identity acquisition and identification

117 lines (106 loc) 4.23 kB
/** * The MIT License (MIT) * * Copyright (c) 2023-2025 Toha <tohenk@yahoo.com> * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ const debug = require('debug')('identity:socket'); class Socket { clients = [] constructor(options) { this.options = options; } handle(cmds, callback) { this.cmds = cmds; this.callback = callback; } send(message, data) { this.clients.forEach(socket => { socket.emit(message, data); }); } onstart() { const io = Socket.factory(this.options); const http = this.options.http; const namespace = `/${this.options.namespace ? this.options.namespace : ''}`; io.of(namespace) .on('connection', socket => { this.handleConnection(socket); }); const addr = http.address(); const url = `${addr.port === 443 ? 'https' : 'http'}://${addr.family === 'IPv6' ? '[' + addr.address + ']' : addr.address}${addr.port !== 80 && addr.port !== 443 ? ':' + addr.port : ''}${namespace}`; this.log('Socket connection ready on %s', url); } handleConnection(socket) { if (this.clients.indexOf(socket) < 0) { this.clients.push(socket); } this.log('%s> connected', socket.id); socket .on('disconnect', () => { this.log('%s> disconnected', socket.id); const idx = this.clients.indexOf(socket); if (idx >= 0) { this.clients.splice(idx, 1); } }); this.cmds.forEach(channel => { socket.on(channel, async data => { this.log('%s> handle message: %s', socket.id, channel); if (typeof this.options.onrequest === 'function') { this.options.onrequest(socket, channel, data); } const res = await this.callback(channel, data); if (res !== undefined) { if (typeof this.options.onresponse === 'function') { this.options.onresponse(socket, channel, data, res, () => { socket.emit(channel, res); }); } else { socket.emit(channel, res); } } }); }); } log(...args) { if (this.parent) { this.parent.log(...args); } else { debug(...args); } } static factory(options) { if (Socket.io === undefined) { const { Server } = require('socket.io'); const http = options.http; if (!http) { throw new Error('HTTP server must be passed in options!'); } const config = options.config || {}; if (!config.cors) { config.cors = {origin: '*'}; } Socket.io = new Server(http, config); } return Socket.io; } } module.exports = Socket;