Download src/redis/presenceClient.ts from Collabos/chatapi: direct link, hf CLI and curl.
- Browser
- Download file 2.71 kB
-
https://huggingface.co/spaces/Collabos/chatapi/resolve/main/src/redis/presenceClient.ts
- Command line
-
hf download hf://spaces/Collabos/chatapi/src/redis/presenceClient.ts
-
curl -L -o presenceClient.ts https://huggingface.co/spaces/Collabos/chatapi/resolve/main/src/redis/presenceClient.ts
2.71 kB
| import Redis from 'ioredis'; | |
| import { CONFIG } from '../config'; | |
| import { logger } from '../utils/logger'; | |
| /** | |
| * Redis Bucket 1 β Presence | |
| * | |
| * Key schema: | |
| * presence:uid:{uid} β socket_id (TTL = PRESENCE_TTL_S) | |
| * status:uid:{uid} β "online" (TTL = PRESENCE_TTL_S) | |
| * | |
| * Separate client instance so Bucket 1 errors never affect Bucket 2. | |
| */ | |
| const presenceClient = new Redis(CONFIG.REDIS_PRESENCE_URL, { | |
| maxRetriesPerRequest: 2, | |
| connectTimeout: 5000, | |
| lazyConnect: false, | |
| enableReadyCheck: true, | |
| // Keep-alive so the HF container connection stays warm | |
| keepAlive: 10000, | |
| }); | |
| presenceClient.on('connect', () => logger.info('Presence Redis connected')); | |
| presenceClient.on('error', (err: Error) => | |
| logger.error('Presence Redis error', { error: err.message }) | |
| ); | |
| presenceClient.on('reconnecting', () => logger.warn('Presence Redis reconnecting')); | |
| export { presenceClient }; | |
| // ββ Key builders βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| const presenceKey = (uid: string) => `presence:uid:${uid}`; | |
| const statusKey = (uid: string) => `status:uid:${uid}`; | |
| // ββ Operations βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| /** Map uid β socketId, mark user online. Called on WS connect. */ | |
| export async function setOnline(uid: string, socketId: string): Promise<void> { | |
| const ttl = CONFIG.PRESENCE_TTL_S; | |
| // MULTI/EXEC keeps it atomic | |
| await presenceClient | |
| .multi() | |
| .set(presenceKey(uid), socketId, 'EX', ttl) | |
| .set(statusKey(uid), 'online', 'EX', ttl) | |
| .exec(); | |
| } | |
| /** Refresh TTL on heartbeat. Does not overwrite the socket id. */ | |
| export async function refreshPresence(uid: string): Promise<void> { | |
| const ttl = CONFIG.PRESENCE_TTL_S; | |
| await presenceClient | |
| .multi() | |
| .expire(presenceKey(uid), ttl) | |
| .expire(statusKey(uid), ttl) | |
| .exec(); | |
| } | |
| /** Remove user from presence. Called on WS close. */ | |
| export async function setOffline(uid: string): Promise<void> { | |
| await presenceClient | |
| .multi() | |
| .del(presenceKey(uid)) | |
| .del(statusKey(uid)) | |
| .exec(); | |
| } | |
| /** Returns the socket id for a uid, or null if offline. */ | |
| export async function getSocketId(uid: string): Promise<string | null> { | |
| return presenceClient.get(presenceKey(uid)); | |
| } | |
| /** Returns true if the user is online. */ | |
| export async function isOnline(uid: string): Promise<boolean> { | |
| const status = await presenceClient.get(statusKey(uid)); | |
| return status === 'online'; | |
| } | |