Files
BizGaze_Remote/server/chat.js
T

56 lines
2.5 KiB
JavaScript
Raw Normal View History

// Chat presence + real-time delivery. A logged-in user opens a WebSocket and sends
// `chat-hello`; signaling.js registers the socket here. Messages are persisted over HTTP
// (routes.js) and pushed live to the recipient's sockets via pushToUser().
const { chatClients, meetingRooms } = require('./presence');
let _repos = null; const repos = () => (_repos || (_repos = require('./repos'))); // lazy: avoid a require cycle
function register(userId, ws) {
if (!chatClients.has(userId)) chatClients.set(userId, new Set());
chatClients.get(userId).add(ws);
ws._chatUserId = userId;
}
function unregister(ws) {
const id = ws && ws._chatUserId;
if (!id) return;
const set = chatClients.get(id);
if (set) { set.delete(ws); if (!set.size) chatClients.delete(id); }
}
function isOnline(userId) {
const s = chatClients.get(userId);
return !!(s && s.size);
}
function pushToUser(userId, obj) {
const s = chatClients.get(userId);
if (!s) return;
const data = JSON.stringify(obj);
for (const ws of s) { if (ws.readyState === 1) { try { ws.send(data); } catch (_) {} } }
}
// --- Live presence -------------------------------------------------------------------------
// A user's effective status (online / in-a-call / away / …) changes with no HTTP round-trip:
// they connect or disconnect a socket, or join/leave a call. Without pushing that change, OTHER
// users only see it after a full page reload — impossible in the desktop/mobile apps. So whenever
// it changes we broadcast the user's fresh status to everyone else's sockets, and the client
// updates that contact's dot/subtitle in place.
function isInCall(userId) {
for (const [, peers] of meetingRooms) { for (const [, p] of peers) { if (p.ws && p.ws._meetingUserId === userId) return true; } }
return false;
}
function effectiveStatus(userId) {
if (isInCall(userId)) return 'incall'; // derived (overrides the stored status)
try { const u = repos().users.byId(userId); return (u && u.status) || 'active'; } catch (_) { return 'active'; }
}
function broadcastPresence(userId) {
if (!userId) return;
const payload = JSON.stringify({ type: 'presence', userId, online: isOnline(userId), status: effectiveStatus(userId) });
for (const [uid, set] of chatClients) {
if (uid === userId) continue; // no need to tell someone about their own status
for (const ws of set) { if (ws.readyState === 1) { try { ws.send(payload); } catch (_) {} } }
}
}
module.exports = { register, unregister, isOnline, pushToUser, broadcastPresence };