UNPKG

@notross/redis-hub

Version:

A minimal connection hub for Redis in Node.js

123 lines 4.39 kB
import { createClient } from 'redis'; import { Logger } from './utils'; const logger = new Logger(); /** * Central hub managing named Redis clients. Each * name gets one shared connection. * * Pub/sub roles or per-namespace/user connections * are just distinct names. */ export class RedisHub { constructor(loggerConfig) { this.defaultClientName = 'default'; this.clients = {}; this.clientOptions = {}; this.defaultOptions = {}; this.error = null; this.status = null; this.connect = this.client.bind(this); this.configureLogger(loggerConfig); } configureLogger(config = { logs: true }) { logger.setup(config); } async getDefaultClient() { return await this.client(this.defaultClientName); } setDefaultOptions(options) { this.defaultOptions = options; } /** * Set the global default Redis options used when no per-client override exists. * @param options RedisClientOptions * @param options.defaultClientName string */ init(options) { const { defaultClientName, ...redisClientOptions } = options; this.setDefaultOptions(redisClientOptions); if (defaultClientName) { this.defaultClientName = defaultClientName; } } getClientById(clientId) { var _a; return (_a = this.clients[clientId]) !== null && _a !== void 0 ? _a : null; } createClient(clientId, options) { options = options !== null && options !== void 0 ? options : this.defaultOptions; if (!options) { throw new Error(`No options provided for '${clientId}' and no default options exist.`); } const client = createClient(options); this.handleClientEvents(client, clientId); this.clients[clientId] = client; this.clientOptions[clientId] = options; return client; } conflictingOptions(clientId, options) { const clientOptions = JSON.stringify(this.clientOptions[clientId]); return JSON.stringify(options) !== clientOptions; } /** * Get or create a named Redis client. Lazy-connects on first call. * @param clientId Logical name (e.g., "publisher", "user-123-subscriber"). * @param options Optional per-client options; only applied on first creation. * @returns Connected Redis client. */ async client(clientId, options) { if (this.clients[clientId]) { if (options && this.conflictingOptions(clientId, options)) { logger.warn(`Options for '${clientId}' were passed again and ignored.`); } return this.clients[clientId]; } const client = this.createClient(clientId, options); await client.connect(); return client; } /** * Disconnects all managed clients and clears internal state. */ async disconnectAll() { await Promise.all(Object.values(this.clients).map((client) => client.destroy())); this.clients = {}; } /** * List all logs; useful if logging is disabled */ logs() { return logger.logs; } handleClientEvents(client, clientId) { // Prevent double-binding: Redis client instances are // new per name so safe to bind unconditionally here. client.on('connect', () => { this.status = `[${clientId}]: client connected.`; logger.log(this.status); this.clients[clientId] = client; }); client.on('ready', () => { this.status = `[${clientId}]: client ready.`; logger.log(this.status); this.clients[clientId] = client; }); client.on('reconnecting', () => { this.status = `[${clientId}]: client reconnecting...`; logger.log(this.status); this.clients[clientId] = client; }); client.on('end', () => { this.status = `[${clientId}]: client closed.`; logger.log(this.status); this.clients[clientId] = client; }); client.on('error', (err) => { this.status = `[${clientId}]: client error:`; this.error = err; logger.error(this.status, this.error); this.clients[clientId] = client; }); } } //# sourceMappingURL=redis-hub.js.map