48 lines
1.3 KiB
TypeScript
48 lines
1.3 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
|
|
export interface Presence {
|
|
userId: string;
|
|
online: boolean;
|
|
lastSeen: number;
|
|
}
|
|
|
|
/**
|
|
* 在线状态管理:开发期使用内存 Map(可分布式广播)。
|
|
* 后续接入 Redis 时替换为 Redis Hash + Pub/Sub 实现,接口保持一致。
|
|
*/
|
|
@Injectable()
|
|
export class PresenceService {
|
|
private readonly map = new Map<string, Presence>();
|
|
/** userId -> Set<socketId>,同一用户多端登录 */
|
|
private readonly sockets = new Map<string, Set<string>>();
|
|
|
|
markOnline(userId: string, socketId: string) {
|
|
const set = this.sockets.get(userId) ?? new Set<string>();
|
|
set.add(socketId);
|
|
this.sockets.set(userId, set);
|
|
const p: Presence = { userId, online: true, lastSeen: Date.now() };
|
|
this.map.set(userId, p);
|
|
return p;
|
|
}
|
|
|
|
markOffline(userId: string, socketId: string): Presence | null {
|
|
const set = this.sockets.get(userId);
|
|
if (set) {
|
|
set.delete(socketId);
|
|
if (set.size > 0) return this.map.get(userId) ?? null;
|
|
this.sockets.delete(userId);
|
|
}
|
|
const p: Presence = { userId, online: false, lastSeen: Date.now() };
|
|
this.map.set(userId, p);
|
|
return p;
|
|
}
|
|
|
|
get(userId: string): Presence {
|
|
return this.map.get(userId) ?? { userId, online: false, lastSeen: 0 };
|
|
}
|
|
|
|
getAll(): Presence[] {
|
|
return [...this.map.values()];
|
|
}
|
|
}
|