Files
MultiRoombaRover/server/src/services/chatService/socketHooks.js
T
2026-04-29 13:45:19 -04:00

54 lines
2.0 KiB
JavaScript

// Chat Socket Hooks
// Purpose: Registers chat socket handlers and event-bus fan-out listeners.
// Scope: Bridges socket events to chat handlers and publishes chat updates to connected clients.
const io = require('../../globals/io');
const { subscribe } = require('../eventBus');
const { typingBySocket } = require('./state');
const { buildTypingPayload, resolveRoverId, isPrivateClosedRoverId } = require('./contextBuilders');
const { broadcastTyping } = require('./broadcast');
const { playTypingNote, TYPING_START_NOTE } = require('./notifications');
function registerChatSocketHooks({ history, handleIncoming }) {
io.on('connection', (socket) => {
socket.emit('chat:init', history);
socket.on('chat:send', (payload = {}, cb = () => {}) => handleIncoming(payload, socket, cb));
socket.on('chat:typing', (payload = {}) => {
const isTyping = Boolean(payload?.isTyping);
const wasTyping = typingBySocket.get(socket.id);
if (isTyping) {
typingBySocket.set(socket.id, true);
if (!wasTyping) {
const roverId = resolveRoverId(socket?.id);
playTypingNote(roverId, TYPING_START_NOTE, socket?.id);
}
} else {
typingBySocket.delete(socket.id);
}
const roverId = resolveRoverId(socket?.id);
if (isPrivateClosedRoverId(roverId)) return;
broadcastTyping(buildTypingPayload(socket, { roverId, fromDiscord: false, isTyping }));
});
socket.on('disconnect', () => {
if (!typingBySocket.has(socket.id)) return;
typingBySocket.delete(socket.id);
const roverId = resolveRoverId(socket?.id);
if (isPrivateClosedRoverId(roverId)) return;
broadcastTyping(buildTypingPayload(socket, { roverId, fromDiscord: false, isTyping: false }));
});
});
subscribe('chat:message', ({ payload }) => {
if (!payload) return;
io.emit('chat:message', payload);
});
subscribe('chat:typing', ({ payload }) => {
if (!payload) return;
io.emit('chat:typing', payload);
});
}
module.exports = {
registerChatSocketHooks,
};