import {Application, Component, Configurable, Inject} from '@lakutata/core' import Redis, {RedisOptions} from 'ioredis' import {Adapter} from 'socket.io-adapter' import {createAdapter} from '@socket.io/redis-adapter' import {TAdapterConstructor} from '../../types/TAdapterConstructor' export class RegistryAdapterComponent extends Component { @Inject(Application) protected readonly app: Application @Configurable() protected readonly redisOptions: undefined | (() => RedisOptions | undefined) = undefined public adapterConstructor: TAdapterConstructor /** * 初始化函数 * @protected */ protected async initialize(): Promise { const redisOptions: RedisOptions | undefined = this.redisOptions ? this.redisOptions() : undefined this.adapterConstructor = redisOptions ? await this.createRedisAdapter(redisOptions) : await this.createMemoryAdapter() } /** * 初始化Redis客户端 * @param client * @param role * @protected */ protected async initRedisClient(client: Redis, role: string): Promise { return new Promise((resolve, reject) => { let fulfilled: boolean = false client .on('error', clientError => { if (!fulfilled) { fulfilled = true return reject(clientError) } else { this.app.Logger.error(`[${role}]`, 'Redis client error:', clientError.message) } }) .once('ready', () => { if (!fulfilled) { fulfilled = true return resolve(client) } else { this.app.Logger.notice(`[${role}]`, 'Redis client reconnected') } }) }) } /** * 创建Redis适配器 * @param redisOptions * @protected */ protected async createRedisAdapter(redisOptions: RedisOptions): Promise { const pubClient: Redis = await this.initRedisClient(new Redis(redisOptions), 'Publisher') const subClient = await this.initRedisClient(pubClient.duplicate(), 'Subscriber') return createAdapter(pubClient, subClient, { publishOnSpecificResponseChannel: true, key: this.app.getID(), requestsTimeout: 3600000 }) as any } /** * 创建内存适配器 * @protected */ protected async createMemoryAdapter(): Promise { return Adapter } }