UNPKG

chamesu

Version:

This package contains all packages of the chat application.

158 lines (125 loc) 4.73 kB
/* * Copyright (c) 2022. * Author Peter Placzek (tada5hi) * For the full copyright and license information, * view the LICENSE file that was distributed with this source code. */ import {Redis} from "ioredis"; export interface StatusOptions<T> { recordType?: string, redisPrefix: string, redisSuffix?: string, redisGetKey?: (key: T) => string } export interface OnlineIdsResponse { data: Record<string, any>[], meta: { limit?: number, offset?: number total: number } } export class RecordStatus<T extends Record<string, any> | undefined | number | string> { constructor(public readonly redisDatabase : Redis, public readonly options: StatusOptions<T>) { } public async setOffline(id: string | number, key?: T) : Promise<void> { await this.redisDatabase.zrem(this.getRedisKey(key), id); await this.dropMeta(id, key); } public async setOnline(id: string | number, key?: T, meta?: Record<string, any>) : Promise<void> { const seconds = (Date.now() / 1000).toFixed(); await this.redisDatabase.zadd(this.getRedisKey(key), seconds, id); if(typeof meta !== 'undefined') { await this.setMeta(id, meta, key); } } async getOnlineCount(key?: T) { return await this.redisDatabase.zcard(this.getRedisKey(key)); } public async getOnline(key?: T, offset?: number, limit?: number) : Promise<OnlineIdsResponse> { try { let args : (string | number)[] = [ this.getRedisKey(key), '+inf', '-inf', 'WITHSCORES' ]; if(typeof offset !== 'undefined' || typeof limit !== 'undefined') { offset = offset ?? 0; limit = limit ?? 50; args.push(offset); args.push(limit); } // @ts-ignore const set = await this.redisDatabase.zrevrangebyscore(...args); let clients : Record<string, any>[] = []; for(let i=0; i<set.length; i=i+2) { const id: number | string = Number.isNaN(set[i]) ? set[i] : parseInt(set[i]); let client : Record<string, any> = { id: id, meta: { firstSeen: parseInt(set[i+1]) * 1000 } }; if(typeof this.options.recordType !== 'undefined') { client.type = this.options.recordType; } clients.push(client); } return { data: clients, meta: { limit, offset, total: await this.getOnlineCount(key) }}; } catch (e) { console.log(e); return { data: [], meta: { limit, offset, total: 0 } }; } } //-------------------------------------------------------------------- public async setMeta(id: string | number, meta: Record<string,any>, key?: T) { const redisPath : string = this.getRedisMetaKey(id, key); for(let index in meta) { if(!meta.hasOwnProperty(index)) continue; await this.redisDatabase.hset(redisPath, index, meta[index]); } } public async setMetaProperty(id: string | number, metaKey: string, metaValue: any, key?: T) { const redisPath : string = this.getRedisMetaKey(id, key); await this.redisDatabase.hset(redisPath, metaKey, metaValue); } public async dropMeta(id: string | number, key?: T) { const redisPath : string = this.getRedisMetaKey(id, key); await this.redisDatabase.del(redisPath); } //-------------------------------------------------------------------- public getRedisKey(key?: T) : string { let prefix : string = this.options.redisPrefix + '.status'; if(typeof this.options.redisSuffix !== 'undefined') { prefix += '.' + this.options.redisSuffix; } if(typeof key === 'undefined') { return prefix; } if(typeof this.options.redisGetKey !== 'undefined') { return prefix + '.' + this.options.redisGetKey(key); } if(typeof key === 'string' || typeof key === 'number') { return prefix + ':' + key; } return prefix; } public getRedisMetaKey(id: string | number, key?: T) { const redisKey = this.getRedisKey(key); return redisKey + 'meta:' + id; } }