mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
gahew
This commit is contained in:
@@ -17,6 +17,9 @@
|
|||||||
- Split very large service files into smaller focused modules.
|
- Split very large service files into smaller focused modules.
|
||||||
- Keep files concise and single-purpose.
|
- Keep files concise and single-purpose.
|
||||||
- Add clear title comments at top of split files.
|
- Add clear title comments at top of split files.
|
||||||
|
- Every service/module file should start with a descriptive comment header containing:
|
||||||
|
- a title line naming the service/module file
|
||||||
|
- a longer purpose/scope description (not a one-liner)
|
||||||
|
|
||||||
## WebUI frontend
|
## WebUI frontend
|
||||||
- Every component must live in its own folder, even when it remains a single-file implementation.
|
- Every component must live in its own folder, even when it remains a single-file implementation.
|
||||||
@@ -48,17 +51,20 @@
|
|||||||
- [ ] replay services (already partly split; reformat consistently)
|
- [ ] replay services (already partly split; reformat consistently)
|
||||||
- [ ] room camera services (already partly split; reformat consistently)
|
- [ ] room camera services (already partly split; reformat consistently)
|
||||||
- [ ] rover manager service
|
- [ ] rover manager service
|
||||||
- [ ] session service
|
- [x] session service
|
||||||
- [ ] turn service
|
- [x] turn service
|
||||||
- [ ] verification service
|
- [ ] verification service
|
||||||
- [ ] video auth service
|
- [ ] video auth service
|
||||||
- [ ] All remaining services: reorganize to folder structure where needed
|
- [x] All remaining services: reorganize to folder structure where needed
|
||||||
|
|
||||||
### COMPLETED SERVICES
|
### COMPLETED SERVICES
|
||||||
- None yet.
|
- turn service
|
||||||
|
- session service
|
||||||
|
|
||||||
### LARGE CHANGES
|
### LARGE CHANGES
|
||||||
- None yet.
|
- Folderized all files in `server/src/services/` into per-service folders with `index.js` entrypoints and updated internal relative imports for new path depth.
|
||||||
|
- Split `server/src/services/turnService/index.js` by extracting constants, shared state helpers, and side-effect action helpers into `turnService/constants.js`, `turnService/state.js`, and `turnService/actions.js`.
|
||||||
|
- Split `server/src/services/sessionService/index.js` by extracting config/timing constants, sync-throttle state storage, and visibility filter helpers into `sessionService/constants.js`, `sessionService/state.js`, and `sessionService/filters.js`.
|
||||||
|
|
||||||
## WebUI frontend
|
## WebUI frontend
|
||||||
### BIGGEST OFFENDERS
|
### BIGGEST OFFENDERS
|
||||||
|
|||||||
+6
-3
@@ -1,7 +1,10 @@
|
|||||||
|
// admin Log Service
|
||||||
|
// Purpose: Defines the admin Log Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const { v4: uuidv4 } = require('uuid');
|
const { v4: uuidv4 } = require('uuid');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const { getRole, roleEvents } = require('./roleService');
|
const { getRole, roleEvents } = require('../roleService');
|
||||||
const { getSocketIp } = require('../helpers/ipResolver');
|
const { getSocketIp } = require('../../helpers/ipResolver');
|
||||||
|
|
||||||
const ADMIN_ROLES = new Set(['admin', 'lockdown', 'lockdown-admin']);
|
const ADMIN_ROLES = new Set(['admin', 'lockdown', 'lockdown-admin']);
|
||||||
const MAX_HISTORY = 200;
|
const MAX_HISTORY = 200;
|
||||||
+7
-4
@@ -1,9 +1,12 @@
|
|||||||
|
// admin Reason Service
|
||||||
|
// Purpose: Defines the admin Reason Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const logger = require('../globals/logger').child('adminReasonService');
|
const logger = require('../../globals/logger').child('adminReasonService');
|
||||||
const { isAdmin } = require('./roleService');
|
const { isAdmin } = require('../roleService');
|
||||||
const { publishEvent } = require('./eventBus');
|
const { publishEvent } = require('../eventBus');
|
||||||
|
|
||||||
const DATA_DIR = path.join(__dirname, '..', '..', 'data');
|
const DATA_DIR = path.join(__dirname, '..', '..', 'data');
|
||||||
const STORE_PATH = path.join(DATA_DIR, 'admin-reason.json');
|
const STORE_PATH = path.join(DATA_DIR, 'admin-reason.json');
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
const io = require('../globals/io');
|
// alert Service
|
||||||
|
// Purpose: Defines the alert Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
|
const io = require('../../globals/io');
|
||||||
|
|
||||||
function sendAlert({ color, title, message, ts = Date.now() }) {
|
function sendAlert({ color, title, message, ts = Date.now() }) {
|
||||||
const payload = {
|
const payload = {
|
||||||
+8
-5
@@ -1,9 +1,12 @@
|
|||||||
|
// assignment Service
|
||||||
|
// Purpose: Defines the assignment Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const logger = require('../globals/logger').child('assignment');
|
const logger = require('../../globals/logger').child('assignment');
|
||||||
const { MODES, getMode, modeEvents } = require('./modeManager');
|
const { MODES, getMode, modeEvents } = require('../modeManager');
|
||||||
const { roleEvents, getRole, isAdmin, isLockdownAdmin } = require('./roleService');
|
const { roleEvents, getRole, isAdmin, isLockdownAdmin } = require('../roleService');
|
||||||
const roverManager = require('./roverManager');
|
const roverManager = require('../roverManager');
|
||||||
|
|
||||||
const socketRefs = new Map(); // socketId -> socket
|
const socketRefs = new Map(); // socketId -> socket
|
||||||
const assignments = new Map(); // socketId -> roverId
|
const assignments = new Map(); // socketId -> roverId
|
||||||
+10
-7
@@ -1,14 +1,17 @@
|
|||||||
|
// audio Forward Service
|
||||||
|
// Purpose: Defines the audio Forward Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { spawn, spawnSync } = require('child_process');
|
const { spawn, spawnSync } = require('child_process');
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const logger = require('../globals/logger').child('audioForwardService');
|
const logger = require('../../globals/logger').child('audioForwardService');
|
||||||
const { loadConfig } = require('../helpers/configLoader');
|
const { loadConfig } = require('../../helpers/configLoader');
|
||||||
const roverManager = require('./roverManager');
|
const roverManager = require('../roverManager');
|
||||||
const turnService = require('./turnService');
|
const turnService = require('../turnService');
|
||||||
const { isVerified } = require('./verificationService');
|
const { isVerified } = require('../verificationService');
|
||||||
const videoSessions = require('./videoSessions');
|
const videoSessions = require('../videoSessions');
|
||||||
|
|
||||||
const audioForwardEvents = new EventEmitter();
|
const audioForwardEvents = new EventEmitter();
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
+9
-6
@@ -1,12 +1,15 @@
|
|||||||
|
// audio Levels Service
|
||||||
|
// Purpose: Defines the audio Levels Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const logger = require('../globals/logger').child('audioLevelsService');
|
const logger = require('../../globals/logger').child('audioLevelsService');
|
||||||
const { loadConfig } = require('../helpers/configLoader');
|
const { loadConfig } = require('../../helpers/configLoader');
|
||||||
const { isAdmin } = require('./roleService');
|
const { isAdmin } = require('../roleService');
|
||||||
const roverManager = require('./roverManager');
|
const roverManager = require('../roverManager');
|
||||||
const { issueCommand } = require('./commandService');
|
const { issueCommand } = require('../commandService');
|
||||||
|
|
||||||
const audioLevelsEvents = new EventEmitter();
|
const audioLevelsEvents = new EventEmitter();
|
||||||
const DATA_DIR = path.join(__dirname, '..', '..', 'data');
|
const DATA_DIR = path.join(__dirname, '..', '..', 'data');
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
|
// auth Service
|
||||||
|
// Purpose: Defines the auth Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const bcrypt = require('bcrypt');
|
const bcrypt = require('bcrypt');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const logger = require('../globals/logger').child('authService');
|
const logger = require('../../globals/logger').child('authService');
|
||||||
const { loadConfig } = require('../helpers/configLoader');
|
const { loadConfig } = require('../../helpers/configLoader');
|
||||||
const { clearLockdownTimer } = require('./lockdownGuard');
|
const { clearLockdownTimer } = require('../lockdownGuard');
|
||||||
const { getMode, MODES } = require('./modeManager');
|
const { getMode, MODES } = require('../modeManager');
|
||||||
const { setRole } = require('./roleService');
|
const { setRole } = require('../roleService');
|
||||||
|
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
const admins = config.admins || [];
|
const admins = config.admins || [];
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
const logger = require('../globals/logger').child('batteryManager');
|
// battery Manager
|
||||||
const { publishEvent } = require('./eventBus');
|
// Purpose: Defines the battery Manager module and the helpers/state used by this service unit.
|
||||||
const { managerEvents, lockRover, rovers } = require('./roverManager');
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
|
const logger = require('../../globals/logger').child('batteryManager');
|
||||||
|
const { publishEvent } = require('../eventBus');
|
||||||
|
const { managerEvents, lockRover, rovers } = require('../roverManager');
|
||||||
|
|
||||||
const STATES = {
|
const STATES = {
|
||||||
NORMAL: 'normal',
|
NORMAL: 'normal',
|
||||||
+17
-14
@@ -1,24 +1,27 @@
|
|||||||
|
// button Box Service
|
||||||
|
// Purpose: Defines the button Box Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const { app } = require('../globals/http');
|
const { app } = require('../../globals/http');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const logger = require('../globals/logger').child('buttonBoxService');
|
const logger = require('../../globals/logger').child('buttonBoxService');
|
||||||
const { publishEvent } = require('./eventBus');
|
const { publishEvent } = require('../eventBus');
|
||||||
const { getRewardById, listRewards } = require('../rewards');
|
const { getRewardById, listRewards } = require('../../rewards');
|
||||||
const roverManager = require('./roverManager');
|
const roverManager = require('../roverManager');
|
||||||
const { issueCommand } = require('./commandService');
|
const { issueCommand } = require('../commandService');
|
||||||
const { sendAlert } = require('./alertService');
|
const { sendAlert } = require('../alertService');
|
||||||
const { sendExternalTyping, sendExternalMessage, sendSystemMessage } = require('./chatService');
|
const { sendExternalTyping, sendExternalMessage, sendSystemMessage } = require('../chatService');
|
||||||
const { setMode, getMode } = require('./modeManager');
|
const { setMode, getMode } = require('../modeManager');
|
||||||
const { getAdminReason, setAdminReason, clearAdminReason } = require('./adminReasonService');
|
const { getAdminReason, setAdminReason, clearAdminReason } = require('../adminReasonService');
|
||||||
const assignmentService = require('./assignmentService');
|
const assignmentService = require('../assignmentService');
|
||||||
const {
|
const {
|
||||||
getState: getHomeAssistantState,
|
getState: getHomeAssistantState,
|
||||||
setEntityState: setHomeAssistantEntityState,
|
setEntityState: setHomeAssistantEntityState,
|
||||||
setLightsLockedOn: setHomeAssistantLightsLockedOn,
|
setLightsLockedOn: setHomeAssistantLightsLockedOn,
|
||||||
} = require('./homeAssistantService');
|
} = require('../homeAssistantService');
|
||||||
const { getRequestIp, isLocalNetwork, normalizeIp } = require('../helpers/ipResolver');
|
const { getRequestIp, isLocalNetwork, normalizeIp } = require('../../helpers/ipResolver');
|
||||||
|
|
||||||
const DATA_DIR = path.join(__dirname, '..', '..', 'data');
|
const DATA_DIR = path.join(__dirname, '..', '..', 'data');
|
||||||
const STORE_PATH = path.join(DATA_DIR, 'buttonbox-state.json');
|
const STORE_PATH = path.join(DATA_DIR, 'buttonbox-state.json');
|
||||||
@@ -1,15 +1,18 @@
|
|||||||
|
// chat Service
|
||||||
|
// Purpose: Defines the chat Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const { v4: uuidv4 } = require('uuid');
|
const { v4: uuidv4 } = require('uuid');
|
||||||
const { DataSet, RegExpMatcher, englishDataset, englishRecommendedTransformers } = require('obscenity');
|
const { DataSet, RegExpMatcher, englishDataset, englishRecommendedTransformers } = require('obscenity');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const logger = require('../globals/logger').child('chatService');
|
const logger = require('../../globals/logger').child('chatService');
|
||||||
const { publishEvent, subscribe } = require('./eventBus');
|
const { publishEvent, subscribe } = require('../eventBus');
|
||||||
const { getRole } = require('./roleService');
|
const { getRole } = require('../roleService');
|
||||||
const { getMode, MODES } = require('./modeManager');
|
const { getMode, MODES } = require('../modeManager');
|
||||||
const { describeAssignment } = require('./assignmentService');
|
const { describeAssignment } = require('../assignmentService');
|
||||||
const roverManager = require('./roverManager');
|
const roverManager = require('../roverManager');
|
||||||
const { getNickname } = require('./nicknameService');
|
const { getNickname } = require('../nicknameService');
|
||||||
const { issueCommand } = require('./commandService');
|
const { issueCommand } = require('../commandService');
|
||||||
const { getAdminReason } = require('./adminReasonService');
|
const { getAdminReason } = require('../adminReasonService');
|
||||||
|
|
||||||
const RATE_LIMIT_WINDOW_MS = 8000;
|
const RATE_LIMIT_WINDOW_MS = 8000;
|
||||||
const RATE_LIMIT_MAX = 5;
|
const RATE_LIMIT_MAX = 5;
|
||||||
@@ -141,7 +144,7 @@ function buildRoverCtxSnapshot(roverId) {
|
|||||||
if (!record) return null;
|
if (!record) return null;
|
||||||
const sensors = record?.lastSensor?.decoded || {};
|
const sensors = record?.lastSensor?.decoded || {};
|
||||||
const batteryState = record?.batteryState || null;
|
const batteryState = record?.batteryState || null;
|
||||||
const { getActiveDrivers } = require('./turnService');
|
const { getActiveDrivers } = require('../turnService');
|
||||||
const activeDrivers = getActiveDrivers();
|
const activeDrivers = getActiveDrivers();
|
||||||
const driverSocketId = activeDrivers[key] || record?.drivers?.values?.().next?.().value || null;
|
const driverSocketId = activeDrivers[key] || record?.drivers?.values?.().next?.().value || null;
|
||||||
const charging = isChargingFromSensors(sensors);
|
const charging = isChargingFromSensors(sensors);
|
||||||
@@ -430,7 +433,7 @@ function maybeSpeak(socket, message, ttsOptions) {
|
|||||||
const audio = record?.meta?.audio || {};
|
const audio = record?.meta?.audio || {};
|
||||||
const ttsEnabled = Boolean(audio.ttsEnabled);
|
const ttsEnabled = Boolean(audio.ttsEnabled);
|
||||||
if (!ttsEnabled) return;
|
if (!ttsEnabled) return;
|
||||||
const { isQueuedDriver } = require('./turnService');
|
const { isQueuedDriver } = require('../turnService');
|
||||||
if (
|
if (
|
||||||
!roverManager.canDrive(message.roverId, socket) &&
|
!roverManager.canDrive(message.roverId, socket) &&
|
||||||
!isQueuedDriver(message.roverId, socket?.id)
|
!isQueuedDriver(message.roverId, socket?.id)
|
||||||
+10
-7
@@ -1,10 +1,13 @@
|
|||||||
|
// command Service
|
||||||
|
// Purpose: Defines the command Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const { v4: uuidv4 } = require('uuid');
|
const { v4: uuidv4 } = require('uuid');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const roverManager = require('./roverManager');
|
const roverManager = require('../roverManager');
|
||||||
const { isAdmin, isLockdownAdmin } = require('./roleService');
|
const { isAdmin, isLockdownAdmin } = require('../roleService');
|
||||||
const { isDeterred } = require('./verificationService');
|
const { isDeterred } = require('../verificationService');
|
||||||
const logger = require('../globals/logger').child('commandService');
|
const logger = require('../../globals/logger').child('commandService');
|
||||||
const { isNightVisionBlocked } = require('../rewards/definitions/darkness');
|
const { isNightVisionBlocked } = require('../../rewards/definitions/darkness');
|
||||||
|
|
||||||
const pendingCommands = new Map(); // id -> { roverId }
|
const pendingCommands = new Map(); // id -> { roverId }
|
||||||
const lastDriveActivity = new Map(); // roverId -> { ts, socketId, direction, speed, isAdmin }
|
const lastDriveActivity = new Map(); // roverId -> { ts, socketId, direction, speed, isAdmin }
|
||||||
@@ -122,7 +125,7 @@ io.on('connection', (socket) => {
|
|||||||
const id = issueCommand(roverId, { type, ...payload });
|
const id = issueCommand(roverId, { type, ...payload });
|
||||||
logger.info('Queued command', socket.id, roverId, type);
|
logger.info('Queued command', socket.id, roverId, type);
|
||||||
try {
|
try {
|
||||||
const { recordActivity } = require('./turnService');
|
const { recordActivity } = require('../turnService');
|
||||||
recordActivity(roverId, socket.id);
|
recordActivity(roverId, socket.id);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// best effort; ignore activity update errors
|
// best effort; ignore activity update errors
|
||||||
+7
-4
@@ -1,9 +1,12 @@
|
|||||||
|
// community Goal Service
|
||||||
|
// Purpose: Defines the community Goal Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const logger = require('../globals/logger').child('communityGoalService');
|
const logger = require('../../globals/logger').child('communityGoalService');
|
||||||
const { isAdmin } = require('./roleService');
|
const { isAdmin } = require('../roleService');
|
||||||
const { publishEvent } = require('./eventBus');
|
const { publishEvent } = require('../eventBus');
|
||||||
|
|
||||||
const DATA_DIR = path.join(__dirname, '..', '..', 'data');
|
const DATA_DIR = path.join(__dirname, '..', '..', 'data');
|
||||||
const STORE_PATH = path.join(DATA_DIR, 'community-goal.json');
|
const STORE_PATH = path.join(DATA_DIR, 'community-goal.json');
|
||||||
+20
-17
@@ -1,3 +1,6 @@
|
|||||||
|
// discord Bot Service
|
||||||
|
// Purpose: Defines the discord Bot Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const {
|
const {
|
||||||
Client,
|
Client,
|
||||||
GatewayIntentBits,
|
GatewayIntentBits,
|
||||||
@@ -9,21 +12,21 @@ const {
|
|||||||
WebhookClient,
|
WebhookClient,
|
||||||
MessageFlags,
|
MessageFlags,
|
||||||
} = require('discord.js');
|
} = require('discord.js');
|
||||||
const logger = require('../globals/logger').child('discordBot');
|
const logger = require('../../globals/logger').child('discordBot');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const { loadConfig } = require('../helpers/configLoader');
|
const { loadConfig } = require('../../helpers/configLoader');
|
||||||
const { subscribe } = require('./eventBus');
|
const { subscribe } = require('../eventBus');
|
||||||
const roverManager = require('./roverManager');
|
const roverManager = require('../roverManager');
|
||||||
const { getRoster, lockRover, rovers } = roverManager;
|
const { getRoster, lockRover, rovers } = roverManager;
|
||||||
const { MODES, getMode, setMode } = require('./modeManager');
|
const { MODES, getMode, setMode } = require('../modeManager');
|
||||||
const { sendExternalMessage, sendExternalTyping } = require('./chatService');
|
const { sendExternalMessage, sendExternalTyping } = require('../chatService');
|
||||||
const { buildReplayVideo } = require('./replayBuildService');
|
const { buildReplayVideo } = require('../replayBuildService');
|
||||||
const { getReplaySources, getDefaultDiscordSources, validateSources } = require('./replaySourceService');
|
const { getReplaySources, getDefaultDiscordSources, validateSources } = require('../replaySourceService');
|
||||||
const { getActiveDrivers } = require('./turnService');
|
const { getActiveDrivers } = require('../turnService');
|
||||||
const { getNickname } = require('./nicknameService');
|
const { getNickname } = require('../nicknameService');
|
||||||
const { tryTriggerReplay } = require('./replayService');
|
const { tryTriggerReplay } = require('../replayService');
|
||||||
const { getCommunityGoal, setCommunityGoal, clearCommunityGoal } = require('./communityGoalService');
|
const { getCommunityGoal, setCommunityGoal, clearCommunityGoal } = require('../communityGoalService');
|
||||||
const { getAdminReason, setAdminReason, clearAdminReason } = require('./adminReasonService');
|
const { getAdminReason, setAdminReason, clearAdminReason } = require('../adminReasonService');
|
||||||
const {
|
const {
|
||||||
getGuildConfig,
|
getGuildConfig,
|
||||||
listGuildConfigs,
|
listGuildConfigs,
|
||||||
@@ -31,7 +34,7 @@ const {
|
|||||||
setGuildConfig,
|
setGuildConfig,
|
||||||
normalizeMode,
|
normalizeMode,
|
||||||
VALID_MODES,
|
VALID_MODES,
|
||||||
} = require('./discordGuildStore');
|
} = require('../discordGuildStore');
|
||||||
const {
|
const {
|
||||||
attachDmMessage,
|
attachDmMessage,
|
||||||
getRequestByMessageId,
|
getRequestByMessageId,
|
||||||
@@ -42,7 +45,7 @@ const {
|
|||||||
listDeterredUsers,
|
listDeterredUsers,
|
||||||
deterUser,
|
deterUser,
|
||||||
undeterUser,
|
undeterUser,
|
||||||
} = require('./verificationService');
|
} = require('../verificationService');
|
||||||
const {
|
const {
|
||||||
DM_APPROVE_EMOJI: PRIVATE_ACCESS_APPROVE_EMOJI,
|
DM_APPROVE_EMOJI: PRIVATE_ACCESS_APPROVE_EMOJI,
|
||||||
DM_DENY_EMOJI: PRIVATE_ACCESS_DENY_EMOJI,
|
DM_DENY_EMOJI: PRIVATE_ACCESS_DENY_EMOJI,
|
||||||
@@ -50,7 +53,7 @@ const {
|
|||||||
getRequestByMessageId: getPrivateAccessRequestByMessageId,
|
getRequestByMessageId: getPrivateAccessRequestByMessageId,
|
||||||
approveRequest: approvePrivateAccessRequest,
|
approveRequest: approvePrivateAccessRequest,
|
||||||
denyRequest: denyPrivateAccessRequest,
|
denyRequest: denyPrivateAccessRequest,
|
||||||
} = require('./privateRoverAccessRequestService');
|
} = require('../privateRoverAccessRequestService');
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
const discordConfig = config.discord || {};
|
const discordConfig = config.discord || {};
|
||||||
const enabled = Boolean(discordConfig.token);
|
const enabled = Boolean(discordConfig.token);
|
||||||
+4
-1
@@ -1,6 +1,9 @@
|
|||||||
|
// discord Guild Store
|
||||||
|
// Purpose: Defines the discord Guild Store module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const logger = require('../globals/logger').child('discordGuildStore');
|
const logger = require('../../globals/logger').child('discordGuildStore');
|
||||||
|
|
||||||
const DATA_DIR = path.join(__dirname, '..', '..', 'data');
|
const DATA_DIR = path.join(__dirname, '..', '..', 'data');
|
||||||
const STORE_PATH = path.join(DATA_DIR, 'discord-guilds.json');
|
const STORE_PATH = path.join(DATA_DIR, 'discord-guilds.json');
|
||||||
+5
-2
@@ -1,5 +1,8 @@
|
|||||||
const { app } = require('../globals/http');
|
// embed Http Service
|
||||||
const { renderIndexHtml, renderOgImage } = require('./embedService');
|
// Purpose: Defines the embed Http Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
|
const { app } = require('../../globals/http');
|
||||||
|
const { renderIndexHtml, renderOgImage } = require('../embedService');
|
||||||
|
|
||||||
app.get(['/', '/spectate', '/mini'], async (req, res) => {
|
app.get(['/', '/spectate', '/mini'], async (req, res) => {
|
||||||
try {
|
try {
|
||||||
@@ -1,13 +1,16 @@
|
|||||||
|
// embed Service
|
||||||
|
// Purpose: Defines the embed Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fsp = require('fs/promises');
|
const fsp = require('fs/promises');
|
||||||
const sharp = require('sharp');
|
const sharp = require('sharp');
|
||||||
|
|
||||||
const { getMode } = require('./modeManager');
|
const { getMode } = require('../modeManager');
|
||||||
const roverManager = require('./roverManager');
|
const roverManager = require('../roverManager');
|
||||||
const { getActiveDrivers, getTurnQueues } = require('./turnService');
|
const { getActiveDrivers, getTurnQueues } = require('../turnService');
|
||||||
const { getRoomCameras } = require('./roomCameraService');
|
const { getRoomCameras } = require('../roomCameraService');
|
||||||
const { getRoomCameraState } = require('./roomCameraSnapshotService');
|
const { getRoomCameraState } = require('../roomCameraSnapshotService');
|
||||||
const { loadConfig } = require('../helpers/configLoader');
|
const { loadConfig } = require('../../helpers/configLoader');
|
||||||
|
|
||||||
const INDEX_HTML_PATH = path.join(__dirname, '..', '..', 'public', 'index.html');
|
const INDEX_HTML_PATH = path.join(__dirname, '..', '..', 'public', 'index.html');
|
||||||
const BITMAP_PATH = path.join(__dirname, '..', '..', 'public', 'bitmap.png');
|
const BITMAP_PATH = path.join(__dirname, '..', '..', 'public', 'bitmap.png');
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
|
// event Bus
|
||||||
|
// Purpose: Defines the event Bus module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const baseLogger = require('../globals/logger');
|
const baseLogger = require('../../globals/logger');
|
||||||
const logger = baseLogger.child ? baseLogger.child('eventBus') : baseLogger;
|
const logger = baseLogger.child ? baseLogger.child('eventBus') : baseLogger;
|
||||||
|
|
||||||
const eventBus = new EventEmitter();
|
const eventBus = new EventEmitter();
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
|
// health Service
|
||||||
|
// Purpose: Defines the health Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const fsp = require('fs/promises');
|
const fsp = require('fs/promises');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const roverManager = require('./roverManager');
|
const roverManager = require('../roverManager');
|
||||||
const { getRoomCameras } = require('./roomCameraService');
|
const { getRoomCameras } = require('../roomCameraService');
|
||||||
const { getRoomCameraState } = require('./roomCameraSnapshotService');
|
const { getRoomCameraState } = require('../roomCameraSnapshotService');
|
||||||
const { getReplayHealthSnapshot } = require('./replayEngineV2');
|
const { getReplayHealthSnapshot } = require('../replayEngineV2');
|
||||||
|
|
||||||
const ROVER_SNAPSHOT_DIR = process.env.ROVER_SNAPSHOT_DIR || '/var/lib/rover-snapshots';
|
const ROVER_SNAPSHOT_DIR = process.env.ROVER_SNAPSHOT_DIR || '/var/lib/rover-snapshots';
|
||||||
const HEALTH_INTERVAL_MS = 5000;
|
const HEALTH_INTERVAL_MS = 5000;
|
||||||
+12
-9
@@ -1,15 +1,18 @@
|
|||||||
|
// home Assistant Service
|
||||||
|
// Purpose: Defines the home Assistant Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const WebSocket = require('ws');
|
const WebSocket = require('ws');
|
||||||
const { createConnection, subscribeEntities, callService, Auth } = require('home-assistant-js-websocket');
|
const { createConnection, subscribeEntities, callService, Auth } = require('home-assistant-js-websocket');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const logger = require('../globals/logger').child('homeAssistantService');
|
const logger = require('../../globals/logger').child('homeAssistantService');
|
||||||
const { loadConfig } = require('../helpers/configLoader');
|
const { loadConfig } = require('../../helpers/configLoader');
|
||||||
const { getMode, MODES, modeEvents } = require('./modeManager');
|
const { getMode, MODES, modeEvents } = require('../modeManager');
|
||||||
const { isAdmin, isLockdownAdmin } = require('./roleService');
|
const { isAdmin, isLockdownAdmin } = require('../roleService');
|
||||||
const roverManager = require('./roverManager');
|
const roverManager = require('../roverManager');
|
||||||
const { issueCommand } = require('./commandService');
|
const { issueCommand } = require('../commandService');
|
||||||
const { publishEvent } = require('./eventBus');
|
const { publishEvent } = require('../eventBus');
|
||||||
const { getActiveDrivers, turnEvents } = require('./turnService');
|
const { getActiveDrivers, turnEvents } = require('../turnService');
|
||||||
|
|
||||||
// home-assistant-js-websocket expects a global WebSocket in Node.
|
// home-assistant-js-websocket expects a global WebSocket in Node.
|
||||||
if (!global.WebSocket) {
|
if (!global.WebSocket) {
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
const { httpServer } = require('../globals/http');
|
|
||||||
const config = require('../globals/config');
|
|
||||||
const logger = require('../globals/logger').child('httpServer');
|
|
||||||
|
|
||||||
httpServer.listen(config.port, () => {
|
|
||||||
logger.info(`Server listening on :${config.port}`);
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// http Server
|
||||||
|
// Purpose: Defines the http Server module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
|
const { httpServer } = require('../../globals/http');
|
||||||
|
const config = require('../../globals/config');
|
||||||
|
const logger = require('../../globals/logger').child('httpServer');
|
||||||
|
|
||||||
|
httpServer.listen(config.port, () => {
|
||||||
|
logger.info(`Server listening on :${config.port}`);
|
||||||
|
});
|
||||||
+11
-8
@@ -1,12 +1,15 @@
|
|||||||
|
// human Alert Button Service
|
||||||
|
// Purpose: Defines the human Alert Button Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const sharp = require('sharp');
|
const sharp = require('sharp');
|
||||||
const logger = require('../globals/logger').child('humanAlertButton');
|
const logger = require('../../globals/logger').child('humanAlertButton');
|
||||||
const { subscribe, publishEvent } = require('./eventBus');
|
const { subscribe, publishEvent } = require('../eventBus');
|
||||||
const { getMode, MODES, setMode } = require('./modeManager');
|
const { getMode, MODES, setMode } = require('../modeManager');
|
||||||
const { issueCommand } = require('./commandService');
|
const { issueCommand } = require('../commandService');
|
||||||
const roverManager = require('./roverManager');
|
const roverManager = require('../roverManager');
|
||||||
const { toggleLightsLockedOn } = require('./homeAssistantService');
|
const { toggleLightsLockedOn } = require('../homeAssistantService');
|
||||||
const { getRoomCameras } = require('./roomCameraService');
|
const { getRoomCameras } = require('../roomCameraService');
|
||||||
const { getRoomCameraState } = require('./roomCameraSnapshotService');
|
const { getRoomCameraState } = require('../roomCameraSnapshotService');
|
||||||
|
|
||||||
const HA_BUTTON_EVENT_TYPE = 'ha.button.action';
|
const HA_BUTTON_EVENT_TYPE = 'ha.button.action';
|
||||||
const HUMAN_ALERT_ACTION = 'humanAlert';
|
const HUMAN_ALERT_ACTION = 'humanAlert';
|
||||||
+4
-1
@@ -1,6 +1,9 @@
|
|||||||
|
// identity Service
|
||||||
|
// Purpose: Defines the identity Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const { getSocketIp, normalizeIp } = require('../helpers/ipResolver');
|
const { getSocketIp, normalizeIp } = require('../../helpers/ipResolver');
|
||||||
|
|
||||||
const COOKIE_USER_ID_RE = /^cu_[a-f0-9]{32}$/;
|
const COOKIE_USER_ID_RE = /^cu_[a-f0-9]{32}$/;
|
||||||
|
|
||||||
+11
-8
@@ -1,14 +1,17 @@
|
|||||||
|
// llm Commentary Service
|
||||||
|
// Purpose: Defines the llm Commentary Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const fsp = require('fs/promises');
|
const fsp = require('fs/promises');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { Ollama } = require('ollama');
|
const { Ollama } = require('ollama');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const logger = require('../globals/logger').child('llmCommentary');
|
const logger = require('../../globals/logger').child('llmCommentary');
|
||||||
const { loadConfig } = require('../helpers/configLoader');
|
const { loadConfig } = require('../../helpers/configLoader');
|
||||||
const { getRole, roleEvents } = require('./roleService');
|
const { getRole, roleEvents } = require('../roleService');
|
||||||
const roverManager = require('./roverManager');
|
const roverManager = require('../roverManager');
|
||||||
const { getActiveDrivers } = require('./turnService');
|
const { getActiveDrivers } = require('../turnService');
|
||||||
const { getNickname } = require('./nicknameService');
|
const { getNickname } = require('../nicknameService');
|
||||||
const { getRecentMessages, sendSystemMessage } = require('./chatService');
|
const { getRecentMessages, sendSystemMessage } = require('../chatService');
|
||||||
|
|
||||||
const PROMPT_PATH = path.join(__dirname, '..', '..', 'prompts', 'commentary_system.txt');
|
const PROMPT_PATH = path.join(__dirname, '..', '..', 'prompts', 'commentary_system.txt');
|
||||||
const DEFAULT_FREQUENCY_MS = 0;
|
const DEFAULT_FREQUENCY_MS = 0;
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
const io = require('../globals/io');
|
// lockdown Guard
|
||||||
const { MODES, getMode, modeEvents } = require('./modeManager');
|
// Purpose: Defines the lockdown Guard module and the helpers/state used by this service unit.
|
||||||
const { isLockdownAdmin } = require('./roleService');
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
|
const io = require('../../globals/io');
|
||||||
|
const { MODES, getMode, modeEvents } = require('../modeManager');
|
||||||
|
const { isLockdownAdmin } = require('../roleService');
|
||||||
|
|
||||||
function disconnectForLockdown(socket) {
|
function disconnectForLockdown(socket) {
|
||||||
socket.emit('lockdown', { message: 'Server is in lockdown mode' });
|
socket.emit('lockdown', { message: 'Server is in lockdown mode' });
|
||||||
+5
-2
@@ -1,6 +1,9 @@
|
|||||||
|
// log Stream Service
|
||||||
|
// Purpose: Defines the log Stream Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const { v4: uuidv4 } = require('uuid');
|
const { v4: uuidv4 } = require('uuid');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const loggerRoot = require('../globals/logger');
|
const loggerRoot = require('../../globals/logger');
|
||||||
const logger = loggerRoot.child('logStream');
|
const logger = loggerRoot.child('logStream');
|
||||||
|
|
||||||
const MAX_HISTORY = 200;
|
const MAX_HISTORY = 200;
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
|
// mode Manager
|
||||||
|
// Purpose: Defines the mode Manager module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const { sendAlert } = require('./alertService');
|
const { sendAlert } = require('../alertService');
|
||||||
const ALERT_COLOR = '#ff9800';
|
const ALERT_COLOR = '#ff9800';
|
||||||
const { isAdmin, isLockdownAdmin } = require('./roleService');
|
const { isAdmin, isLockdownAdmin } = require('../roleService');
|
||||||
const { publishEvent } = require('./eventBus');
|
const { publishEvent } = require('../eventBus');
|
||||||
|
|
||||||
const MODES = {
|
const MODES = {
|
||||||
OPEN: 'open',
|
OPEN: 'open',
|
||||||
@@ -1,15 +1,18 @@
|
|||||||
|
// neato Service
|
||||||
|
// Purpose: Defines the neato Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const logger = require('../globals/logger').child('neatoService');
|
const logger = require('../../globals/logger').child('neatoService');
|
||||||
const { loadConfig } = require('../helpers/configLoader');
|
const { loadConfig } = require('../../helpers/configLoader');
|
||||||
const { isVerified } = require('./verificationService');
|
const { isVerified } = require('../verificationService');
|
||||||
const {
|
const {
|
||||||
homeAssistantEvents,
|
homeAssistantEvents,
|
||||||
getRawEntitySnapshot,
|
getRawEntitySnapshot,
|
||||||
callHomeAssistantService,
|
callHomeAssistantService,
|
||||||
isConnected: isHomeAssistantConnected,
|
isConnected: isHomeAssistantConnected,
|
||||||
enabled: homeAssistantEnabled,
|
enabled: homeAssistantEnabled,
|
||||||
} = require('./homeAssistantService');
|
} = require('../homeAssistantService');
|
||||||
|
|
||||||
const events = new EventEmitter();
|
const events = new EventEmitter();
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
+5
-2
@@ -1,6 +1,9 @@
|
|||||||
|
// nickname Service
|
||||||
|
// Purpose: Defines the nickname Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const logger = require('../globals/logger').child('nicknameService');
|
const logger = require('../../globals/logger').child('nicknameService');
|
||||||
|
|
||||||
const nicknameEvents = new EventEmitter();
|
const nicknameEvents = new EventEmitter();
|
||||||
|
|
||||||
+11
-8
@@ -1,12 +1,15 @@
|
|||||||
|
// private Rover Access Request Service
|
||||||
|
// Purpose: Defines the private Rover Access Request Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const logger = require('../globals/logger').child('privateRoverAccessRequest');
|
const logger = require('../../globals/logger').child('privateRoverAccessRequest');
|
||||||
const { publishEvent } = require('./eventBus');
|
const { publishEvent } = require('../eventBus');
|
||||||
const roverManager = require('./roverManager');
|
const roverManager = require('../roverManager');
|
||||||
const { getNickname } = require('./nicknameService');
|
const { getNickname } = require('../nicknameService');
|
||||||
const { getRole, isLockdownAdmin } = require('./roleService');
|
const { getRole, isLockdownAdmin } = require('../roleService');
|
||||||
const { getSocketIp, normalizeIp } = require('../helpers/ipResolver');
|
const { getSocketIp, normalizeIp } = require('../../helpers/ipResolver');
|
||||||
|
|
||||||
const requestEvents = new EventEmitter();
|
const requestEvents = new EventEmitter();
|
||||||
const REQUEST_COOLDOWN_MS = 15 * 1000;
|
const REQUEST_COOLDOWN_MS = 15 * 1000;
|
||||||
@@ -200,7 +203,7 @@ function tryAssignClosedPrivateRover(socket, roverId) {
|
|||||||
});
|
});
|
||||||
roverManager.managerEvents.emit('switch', { socketId: socket.id, roverId: String(roverId) });
|
roverManager.managerEvents.emit('switch', { socketId: socket.id, roverId: String(roverId) });
|
||||||
try {
|
try {
|
||||||
const assignmentService = require('./assignmentService');
|
const assignmentService = require('../assignmentService');
|
||||||
assignmentService.moveAssignment(socket, String(roverId), { releasePrevious: false });
|
assignmentService.moveAssignment(socket, String(roverId), { releasePrevious: false });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.warn('Failed to move assignment after private access grant', { socketId: socket.id, error: err.message });
|
logger.warn('Failed to move assignment after private access grant', { socketId: socket.id, error: err.message });
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
const { buildReplayVideo } = require('./replayEngineV2');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
buildReplayVideo,
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// replay Build Service
|
||||||
|
// Purpose: Defines the replay Build Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
|
const { buildReplayVideo } = require('../replayEngineV2');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
buildReplayVideo,
|
||||||
|
};
|
||||||
+10
-7
@@ -1,3 +1,6 @@
|
|||||||
|
// replay Engine V2
|
||||||
|
// Purpose: Defines the replay Engine V2 module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const { spawn, execFile } = require('child_process');
|
const { spawn, execFile } = require('child_process');
|
||||||
const fsp = require('fs/promises');
|
const fsp = require('fs/promises');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
@@ -5,13 +8,13 @@ const os = require('os');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { promisify } = require('util');
|
const { promisify } = require('util');
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const logger = require('../globals/logger').child('replayEngineV2');
|
const logger = require('../../globals/logger').child('replayEngineV2');
|
||||||
const roverManager = require('./roverManager');
|
const roverManager = require('../roverManager');
|
||||||
const { getRoomCameras, roomCameraEvents } = require('./roomCameraService');
|
const { getRoomCameras, roomCameraEvents } = require('../roomCameraService');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const { getActiveDrivers } = require('./turnService');
|
const { getActiveDrivers } = require('../turnService');
|
||||||
const { getNickname } = require('./nicknameService');
|
const { getNickname } = require('../nicknameService');
|
||||||
const { getRecentMessages } = require('./chatService');
|
const { getRecentMessages } = require('../chatService');
|
||||||
const sharp = require('sharp');
|
const sharp = require('sharp');
|
||||||
|
|
||||||
const execFileAsync = promisify(execFile);
|
const execFileAsync = promisify(execFile);
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// replay Service
|
||||||
|
// Purpose: Defines the replay Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
|
|
||||||
const COOLDOWN_MS = 10 * 1000;
|
const COOLDOWN_MS = 10 * 1000;
|
||||||
+12
-9
@@ -1,12 +1,15 @@
|
|||||||
const io = require('../globals/io');
|
// replay Socket Service
|
||||||
const logger = require('../globals/logger').child('replaySocket');
|
// Purpose: Defines the replay Socket Service module and the helpers/state used by this service unit.
|
||||||
const { getMode, MODES } = require('./modeManager');
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const { publishEvent } = require('./eventBus');
|
const io = require('../../globals/io');
|
||||||
const { tryTriggerReplay } = require('./replayService');
|
const logger = require('../../globals/logger').child('replaySocket');
|
||||||
const { validateSources, getDefaultWebSources } = require('./replaySourceService');
|
const { getMode, MODES } = require('../modeManager');
|
||||||
const assignmentService = require('./assignmentService');
|
const { publishEvent } = require('../eventBus');
|
||||||
const { getNickname } = require('./nicknameService');
|
const { tryTriggerReplay } = require('../replayService');
|
||||||
const { loadConfig } = require('../helpers/configLoader');
|
const { validateSources, getDefaultWebSources } = require('../replaySourceService');
|
||||||
|
const assignmentService = require('../assignmentService');
|
||||||
|
const { getNickname } = require('../nicknameService');
|
||||||
|
const { loadConfig } = require('../../helpers/configLoader');
|
||||||
|
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
const discordConfig = config.discord || {};
|
const discordConfig = config.discord || {};
|
||||||
+5
-2
@@ -1,5 +1,8 @@
|
|||||||
const roverManager = require('./roverManager');
|
// replay Source Service
|
||||||
const { getRoomCameras } = require('./roomCameraService');
|
// Purpose: Defines the replay Source Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
|
const roverManager = require('../roverManager');
|
||||||
|
const { getRoomCameras } = require('../roomCameraService');
|
||||||
|
|
||||||
function getReplaySources(socket = null) {
|
function getReplaySources(socket = null) {
|
||||||
const roster = socket ? roverManager.getRosterForSocket(socket) : roverManager.getRoster();
|
const roster = socket ? roverManager.getRosterForSocket(socket) : roverManager.getRoster();
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// role Service
|
||||||
|
// Purpose: Defines the role Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
|
|
||||||
const roleEvents = new EventEmitter();
|
const roleEvents = new EventEmitter();
|
||||||
+5
-2
@@ -1,3 +1,6 @@
|
|||||||
|
// room Camera Replay Service
|
||||||
|
// Purpose: Defines the room Camera Replay Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const { execFile } = require('child_process');
|
const { execFile } = require('child_process');
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const fsp = require('fs/promises');
|
const fsp = require('fs/promises');
|
||||||
@@ -5,8 +8,8 @@ const os = require('os');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { promisify } = require('util');
|
const { promisify } = require('util');
|
||||||
|
|
||||||
const logger = require('../globals/logger').child('roomCameraReplay');
|
const logger = require('../../globals/logger').child('roomCameraReplay');
|
||||||
const { getRoomCamera, getRoomCameras } = require('./roomCameraService');
|
const { getRoomCamera, getRoomCameras } = require('../roomCameraService');
|
||||||
|
|
||||||
const execFileAsync = promisify(execFile);
|
const execFileAsync = promisify(execFile);
|
||||||
|
|
||||||
+5
-2
@@ -1,6 +1,9 @@
|
|||||||
|
// room Camera Service
|
||||||
|
// Purpose: Defines the room Camera Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const logger = require('../globals/logger').child('roomCameraService');
|
const logger = require('../../globals/logger').child('roomCameraService');
|
||||||
const { loadConfig } = require('../helpers/configLoader');
|
const { loadConfig } = require('../../helpers/configLoader');
|
||||||
|
|
||||||
const events = new EventEmitter();
|
const events = new EventEmitter();
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
+5
-2
@@ -1,8 +1,11 @@
|
|||||||
|
// room Camera Snapshot Service
|
||||||
|
// Purpose: Defines the room Camera Snapshot Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
const https = require('https');
|
const https = require('https');
|
||||||
const logger = require('../globals/logger').child('roomCameraSnapshot');
|
const logger = require('../../globals/logger').child('roomCameraSnapshot');
|
||||||
const { getRoomCameras, roomCameraEvents } = require('./roomCameraService');
|
const { getRoomCameras, roomCameraEvents } = require('../roomCameraService');
|
||||||
|
|
||||||
const POLL_INTERVAL_MS = 67;
|
const POLL_INTERVAL_MS = 67;
|
||||||
const FETCH_TIMEOUT_MS = 2000;
|
const FETCH_TIMEOUT_MS = 2000;
|
||||||
+9
-6
@@ -1,9 +1,12 @@
|
|||||||
const io = require('../globals/io');
|
// room Camera Socket Service
|
||||||
const logger = require('../globals/logger').child('roomCameraSocket');
|
// Purpose: Defines the room Camera Socket Service module and the helpers/state used by this service unit.
|
||||||
const { getMode, MODES } = require('./modeManager');
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const { isAdmin, isLockdownAdmin, getRole } = require('./roleService');
|
const io = require('../../globals/io');
|
||||||
const { getRoomCamera, getRoomCameras } = require('./roomCameraService');
|
const logger = require('../../globals/logger').child('roomCameraSocket');
|
||||||
const { roomCameraStreamEvents, getRoomCameraState } = require('./roomCameraSnapshotService');
|
const { getMode, MODES } = require('../modeManager');
|
||||||
|
const { isAdmin, isLockdownAdmin, getRole } = require('../roleService');
|
||||||
|
const { getRoomCamera, getRoomCameras } = require('../roomCameraService');
|
||||||
|
const { roomCameraStreamEvents, getRoomCameraState } = require('../roomCameraSnapshotService');
|
||||||
|
|
||||||
const SUBSCRIBE_LIMIT = 50;
|
const SUBSCRIBE_LIMIT = 50;
|
||||||
const SUBSCRIBE_WINDOW_MS = 10000;
|
const SUBSCRIBE_WINDOW_MS = 10000;
|
||||||
+8
-5
@@ -1,9 +1,12 @@
|
|||||||
const roverWSS = require('../globals/ws');
|
// rover Connection Service
|
||||||
const logger = require('../globals/logger').child('roverConnection');
|
// Purpose: Defines the rover Connection Service module and the helpers/state used by this service unit.
|
||||||
const roverManager = require('./roverManager');
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const { sendAlert } = require('./alertService');
|
const roverWSS = require('../../globals/ws');
|
||||||
|
const logger = require('../../globals/logger').child('roverConnection');
|
||||||
|
const roverManager = require('../roverManager');
|
||||||
|
const { sendAlert } = require('../alertService');
|
||||||
const ALERT_COLOR = '#00bcd4';
|
const ALERT_COLOR = '#00bcd4';
|
||||||
const { handleAck } = require('./commandService');
|
const { handleAck } = require('../commandService');
|
||||||
|
|
||||||
function coerceBool(value) {
|
function coerceBool(value) {
|
||||||
if (typeof value === 'boolean') return value;
|
if (typeof value === 'boolean') return value;
|
||||||
@@ -1,18 +1,21 @@
|
|||||||
|
// rover Manager
|
||||||
|
// Purpose: Defines the rover Manager module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const logger = require('../globals/logger').child('roverManager');
|
const logger = require('../../globals/logger').child('roverManager');
|
||||||
const { sendAlert } = require('./alertService');
|
const { sendAlert } = require('../alertService');
|
||||||
const ALERT_COLOR = '#8bc34a';
|
const ALERT_COLOR = '#8bc34a';
|
||||||
const { parseSensorFrame } = require('../helpers/sensorDecoder');
|
const { parseSensorFrame } = require('../../helpers/sensorDecoder');
|
||||||
const { MODES, getMode } = require('./modeManager');
|
const { MODES, getMode } = require('../modeManager');
|
||||||
const { isAdmin, isLockdownAdmin, roleEvents } = require('./roleService');
|
const { isAdmin, isLockdownAdmin, roleEvents } = require('../roleService');
|
||||||
const { publishEvent } = require('./eventBus');
|
const { publishEvent } = require('../eventBus');
|
||||||
const videoSessions = require('./videoSessions');
|
const videoSessions = require('../videoSessions');
|
||||||
|
|
||||||
const rovers = new Map(); // roverId -> record
|
const rovers = new Map(); // roverId -> record
|
||||||
const socketToRovers = new Map(); // socketId -> Set(roverId)
|
const socketToRovers = new Map(); // socketId -> Set(roverId)
|
||||||
const spectatorSockets = new Set();
|
const spectatorSockets = new Set();
|
||||||
const turnService = require('./turnService');
|
const turnService = require('../turnService');
|
||||||
const managerEvents = new EventEmitter();
|
const managerEvents = new EventEmitter();
|
||||||
const DOCK_GUARD_WINDOW_MS = 2 * 1000;
|
const DOCK_GUARD_WINDOW_MS = 2 * 1000;
|
||||||
const IDLE_UNDOCKED_MS = 2 * 60 * 1000;
|
const IDLE_UNDOCKED_MS = 2 * 60 * 1000;
|
||||||
@@ -186,7 +189,7 @@ function getControlDenialReason(record, socket, options = {}) {
|
|||||||
if (mode === MODES.LOCKDOWN && !isLockdownAdmin(socket)) {
|
if (mode === MODES.LOCKDOWN && !isLockdownAdmin(socket)) {
|
||||||
return 'Server in lockdown';
|
return 'Server in lockdown';
|
||||||
}
|
}
|
||||||
const { isDeterred } = require('./verificationService');
|
const { isDeterred } = require('../verificationService');
|
||||||
if (!isAdmin(socket) && isDeterred(socket)) {
|
if (!isAdmin(socket) && isDeterred(socket)) {
|
||||||
return 'Not authorized';
|
return 'Not authorized';
|
||||||
}
|
}
|
||||||
@@ -205,7 +208,7 @@ function getControlDenialReason(record, socket, options = {}) {
|
|||||||
if (isLockdownAdmin(socket)) {
|
if (isLockdownAdmin(socket)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const { isVerified } = require('./verificationService');
|
const { isVerified } = require('../verificationService');
|
||||||
if (!isVerified(socket)) {
|
if (!isVerified(socket)) {
|
||||||
return 'Private rover requires verification';
|
return 'Private rover requires verification';
|
||||||
}
|
}
|
||||||
@@ -306,7 +309,7 @@ function removeRover(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sendPrivateToggleTTS(roverId, open, reason) {
|
function sendPrivateToggleTTS(roverId, open, reason) {
|
||||||
const { issueCommand } = require('./commandService');
|
const { issueCommand } = require('../commandService');
|
||||||
let text = open ? 'Private rover is now open.' : 'Private rover is now closed.';
|
let text = open ? 'Private rover is now open.' : 'Private rover is now closed.';
|
||||||
if (!open && reason === 'auto_idle') {
|
if (!open && reason === 'auto_idle') {
|
||||||
text = 'Private rover closed due to inactivity.';
|
text = 'Private rover closed due to inactivity.';
|
||||||
@@ -600,7 +603,7 @@ function stopSafetyBackoffTimer(roverId) {
|
|||||||
function triggerSafetyAction(record, mode, options = {}) {
|
function triggerSafetyAction(record, mode, options = {}) {
|
||||||
if (!record) return;
|
if (!record) return;
|
||||||
const roverId = record.id;
|
const roverId = record.id;
|
||||||
const { issueCommand, setDriveCooldown } = require('./commandService');
|
const { issueCommand, setDriveCooldown } = require('../commandService');
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const cooldownMs = clampInt(options.cooldownMs, 100, 10000, DEFAULT_PRIVATE_SAFETY.triggerCooldownMs);
|
const cooldownMs = clampInt(options.cooldownMs, 100, 10000, DEFAULT_PRIVATE_SAFETY.triggerCooldownMs);
|
||||||
const backoffMs = clampInt(options.backoffMs, 50, 5000, 0);
|
const backoffMs = clampInt(options.backoffMs, 50, 5000, 0);
|
||||||
@@ -917,7 +920,7 @@ function attemptDockGuard(roverId) {
|
|||||||
stopDockGuard(roverId);
|
stopDockGuard(roverId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { issueCommand } = require('./commandService');
|
const { issueCommand } = require('../commandService');
|
||||||
try {
|
try {
|
||||||
issueCommand(roverId, { type: 'sensorStream', sensorStream: { enable: true } });
|
issueCommand(roverId, { type: 'sensorStream', sensorStream: { enable: true } });
|
||||||
issueCommand(roverId, { type: 'raw', raw: DOCK_COMMAND_BASE64 });
|
issueCommand(roverId, { type: 'raw', raw: DOCK_COMMAND_BASE64 });
|
||||||
@@ -928,7 +931,7 @@ function attemptDockGuard(roverId) {
|
|||||||
function handleIdleUndock(undockedRecord) {
|
function handleIdleUndock(undockedRecord) {
|
||||||
if (!undockedRecord || undockedRecord.drivers.size > 0) return;
|
if (!undockedRecord || undockedRecord.drivers.size > 0) return;
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const { getRecentDriveActivity, setDriveCooldown, issueCommand } = require('./commandService');
|
const { getRecentDriveActivity, setDriveCooldown, issueCommand } = require('../commandService');
|
||||||
const candidates = getRecentDriveActivity(DOCK_GUARD_WINDOW_MS, { excludeAdmins: true })
|
const candidates = getRecentDriveActivity(DOCK_GUARD_WINDOW_MS, { excludeAdmins: true })
|
||||||
.filter((candidate) => candidate.roverId !== undockedRecord.id);
|
.filter((candidate) => candidate.roverId !== undockedRecord.id);
|
||||||
if (candidates.length === 0) return;
|
if (candidates.length === 0) return;
|
||||||
@@ -965,7 +968,7 @@ function handleIdleUndock(undockedRecord) {
|
|||||||
|
|
||||||
function nudgeRover(roverId, direction = 'backward') {
|
function nudgeRover(roverId, direction = 'backward') {
|
||||||
if (!roverId) return;
|
if (!roverId) return;
|
||||||
const { issueCommand } = require('./commandService');
|
const { issueCommand } = require('../commandService');
|
||||||
clearTimeout(backoffTimers.get(roverId));
|
clearTimeout(backoffTimers.get(roverId));
|
||||||
const speed = direction === 'forward' ? BACKOFF_SPEED : -BACKOFF_SPEED;
|
const speed = direction === 'forward' ? BACKOFF_SPEED : -BACKOFF_SPEED;
|
||||||
try {
|
try {
|
||||||
+5
-2
@@ -1,8 +1,11 @@
|
|||||||
|
// rover Snapshot Service
|
||||||
|
// Purpose: Defines the rover Snapshot Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const fs = require('fs/promises');
|
const fs = require('fs/promises');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const logger = require('../globals/logger').child('roverSnapshot');
|
const logger = require('../../globals/logger').child('roverSnapshot');
|
||||||
const roverManager = require('./roverManager');
|
const roverManager = require('../roverManager');
|
||||||
|
|
||||||
const SNAPSHOT_DIR = process.env.ROVER_SNAPSHOT_DIR || '/var/lib/rover-snapshots';
|
const SNAPSHOT_DIR = process.env.ROVER_SNAPSHOT_DIR || '/var/lib/rover-snapshots';
|
||||||
const POLL_INTERVAL_MS = 300;
|
const POLL_INTERVAL_MS = 300;
|
||||||
+9
-6
@@ -1,9 +1,12 @@
|
|||||||
const io = require('../globals/io');
|
// rover Snapshot Socket Service
|
||||||
const logger = require('../globals/logger').child('roverSnapshotSocket');
|
// Purpose: Defines the rover Snapshot Socket Service module and the helpers/state used by this service unit.
|
||||||
const { getMode, MODES } = require('./modeManager');
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const { isAdmin, isLockdownAdmin, getRole } = require('./roleService');
|
const io = require('../../globals/io');
|
||||||
const roverManager = require('./roverManager');
|
const logger = require('../../globals/logger').child('roverSnapshotSocket');
|
||||||
const { roverSnapshotEvents, getRoverSnapshotState } = require('./roverSnapshotService');
|
const { getMode, MODES } = require('../modeManager');
|
||||||
|
const { isAdmin, isLockdownAdmin, getRole } = require('../roleService');
|
||||||
|
const roverManager = require('../roverManager');
|
||||||
|
const { roverSnapshotEvents, getRoverSnapshotState } = require('../roverSnapshotService');
|
||||||
|
|
||||||
const SUBSCRIBE_LIMIT = 50;
|
const SUBSCRIBE_LIMIT = 50;
|
||||||
const SUBSCRIBE_WINDOW_MS = 10000;
|
const SUBSCRIBE_WINDOW_MS = 10000;
|
||||||
+7
-4
@@ -1,8 +1,11 @@
|
|||||||
|
// server Control Service
|
||||||
|
// Purpose: Defines the server Control Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const { spawn } = require('child_process');
|
const { spawn } = require('child_process');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const logger = require('../globals/logger').child('serverControlService');
|
const logger = require('../../globals/logger').child('serverControlService');
|
||||||
const { isAdmin } = require('./roleService');
|
const { isAdmin } = require('../roleService');
|
||||||
const { sendAlert } = require('./alertService');
|
const { sendAlert } = require('../alertService');
|
||||||
|
|
||||||
const ALERT_COLOR = '#ff5722';
|
const ALERT_COLOR = '#ff5722';
|
||||||
let rebootPending = false;
|
let rebootPending = false;
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// session Service constants
|
||||||
|
// Purpose: Defines timing and static social/config constants used by session synchronization behavior.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating constants from orchestration logic.
|
||||||
|
const { loadConfig } = require('../../helpers/configLoader');
|
||||||
|
|
||||||
|
const config = loadConfig();
|
||||||
|
const discordInvite = config.discord?.invite || null;
|
||||||
|
const kofiLink = config.kofi?.link || null;
|
||||||
|
const serverTimezone = config.timezone || null;
|
||||||
|
const configuredSocials = Array.isArray(config.socials) ? config.socials : null;
|
||||||
|
|
||||||
|
const ACTIVITY_SYNC_COOLDOWN_MS = 3000;
|
||||||
|
const NIGHT_VISION_SYNC_COOLDOWN_MS = 1000;
|
||||||
|
const PERIODIC_SYNC_MS = 20000;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
discordInvite,
|
||||||
|
kofiLink,
|
||||||
|
serverTimezone,
|
||||||
|
configuredSocials,
|
||||||
|
ACTIVITY_SYNC_COOLDOWN_MS,
|
||||||
|
NIGHT_VISION_SYNC_COOLDOWN_MS,
|
||||||
|
PERIODIC_SYNC_MS,
|
||||||
|
};
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// session Service filters
|
||||||
|
// Purpose: Defines visibility-filter helpers for per-socket session payload shaping.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating rover/queue filtering concerns from orchestration.
|
||||||
|
const roverManager = require('../roverManager');
|
||||||
|
|
||||||
|
function filterVisibleRoverId(socket, roverId) {
|
||||||
|
if (!roverId) return null;
|
||||||
|
return roverManager.canSeeRover(roverId, socket) ? roverId : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterActiveDriversForSocket(activeDrivers = {}, socket) {
|
||||||
|
const next = {};
|
||||||
|
Object.entries(activeDrivers || {}).forEach(([roverId, socketId]) => {
|
||||||
|
if (!roverManager.canSeeRover(roverId, socket)) return;
|
||||||
|
next[roverId] = socketId;
|
||||||
|
});
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterTurnQueuesForSocket(turnQueues = {}, socket) {
|
||||||
|
const next = {};
|
||||||
|
Object.entries(turnQueues || {}).forEach(([roverId, info]) => {
|
||||||
|
if (!roverManager.canSeeRover(roverId, socket)) return;
|
||||||
|
next[roverId] = info;
|
||||||
|
});
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
filterVisibleRoverId,
|
||||||
|
filterActiveDriversForSocket,
|
||||||
|
filterTurnQueuesForSocket,
|
||||||
|
};
|
||||||
+62
-79
@@ -1,53 +1,57 @@
|
|||||||
const io = require('../globals/io');
|
// session Service
|
||||||
const logger = require('../globals/logger').child('sessionService');
|
// Purpose: Defines the session Service module and the helpers/state used by this service unit.
|
||||||
const { getRole, roleEvents } = require('./roleService');
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const { getMode, modeEvents } = require('./modeManager');
|
const io = require('../../globals/io');
|
||||||
const roverManager = require('./roverManager');
|
const logger = require('../../globals/logger').child('sessionService');
|
||||||
|
const { getRole, roleEvents } = require('../roleService');
|
||||||
|
const { getMode, modeEvents } = require('../modeManager');
|
||||||
|
const roverManager = require('../roverManager');
|
||||||
const { managerEvents } = roverManager;
|
const { managerEvents } = roverManager;
|
||||||
const assignmentService = require('./assignmentService');
|
const assignmentService = require('../assignmentService');
|
||||||
const { getActiveDrivers, getTurnQueues, turnEvents } = require('./turnService');
|
const { getActiveDrivers, getTurnQueues, turnEvents } = require('../turnService');
|
||||||
const { getRoomCameras, roomCameraEvents } = require('./roomCameraService');
|
const { getRoomCameras, roomCameraEvents } = require('../roomCameraService');
|
||||||
const { getState: getHomeAssistantState, homeAssistantEvents } = require('./homeAssistantService');
|
const { getState: getHomeAssistantState, homeAssistantEvents } = require('../homeAssistantService');
|
||||||
const { getState: getNeatoState, neatoEvents } = require('./neatoService');
|
const { getState: getNeatoState, neatoEvents } = require('../neatoService');
|
||||||
const { getNickname, nicknameEvents } = require('./nicknameService');
|
const { getNickname, nicknameEvents } = require('../nicknameService');
|
||||||
const {
|
const {
|
||||||
getVerificationStateForSocket,
|
getVerificationStateForSocket,
|
||||||
getModerationStateForSocket,
|
getModerationStateForSocket,
|
||||||
getIdentitySummary,
|
getIdentitySummary,
|
||||||
verificationEvents,
|
verificationEvents,
|
||||||
} = require('./verificationService');
|
} = require('../verificationService');
|
||||||
const {
|
const {
|
||||||
getStateForSocket: getPrivateRoverAccessStateForSocket,
|
getStateForSocket: getPrivateRoverAccessStateForSocket,
|
||||||
requestEvents: privateRoverAccessRequestEvents,
|
requestEvents: privateRoverAccessRequestEvents,
|
||||||
} = require('./privateRoverAccessRequestService');
|
} = require('../privateRoverAccessRequestService');
|
||||||
const { getReplayState, replayEvents } = require('./replayService');
|
const { getReplayState, replayEvents } = require('../replayService');
|
||||||
const { getReplaySources } = require('./replaySourceService');
|
const { getReplaySources } = require('../replaySourceService');
|
||||||
const { getHealthSnapshot } = require('./healthService');
|
const { getHealthSnapshot } = require('../healthService');
|
||||||
const { loadConfig } = require('../helpers/configLoader');
|
const { getCommunityGoal } = require('../communityGoalService');
|
||||||
const { getCommunityGoal } = require('./communityGoalService');
|
const { getAdminReason } = require('../adminReasonService');
|
||||||
const { getAdminReason } = require('./adminReasonService');
|
const { subscribe } = require('../eventBus');
|
||||||
const { subscribe } = require('./eventBus');
|
const { getSocketIp, isLocalNetwork } = require('../../helpers/ipResolver');
|
||||||
const { getSocketIp, isLocalNetwork } = require('../helpers/ipResolver');
|
const { getAudioForwardState, audioForwardEvents } = require('../audioForwardService');
|
||||||
const { getAudioForwardState, audioForwardEvents } = require('./audioForwardService');
|
const { getAudioLevels, audioLevelsEvents } = require('../audioLevelsService');
|
||||||
const { getAudioLevels, audioLevelsEvents } = require('./audioLevelsService');
|
const { getButtonBoxState } = require('../buttonBoxService');
|
||||||
const { getButtonBoxState } = require('./buttonBoxService');
|
const {
|
||||||
|
discordInvite,
|
||||||
const config = loadConfig();
|
kofiLink,
|
||||||
const discordInvite = config.discord?.invite || null;
|
serverTimezone,
|
||||||
const kofiLink = config.kofi?.link || null;
|
configuredSocials,
|
||||||
const serverTimezone = config.timezone || null;
|
ACTIVITY_SYNC_COOLDOWN_MS,
|
||||||
const configuredSocials = Array.isArray(config.socials) ? config.socials : null;
|
NIGHT_VISION_SYNC_COOLDOWN_MS,
|
||||||
|
PERIODIC_SYNC_MS,
|
||||||
|
} = require('./constants');
|
||||||
|
const { getState, setState } = require('./state');
|
||||||
|
const {
|
||||||
|
filterVisibleRoverId,
|
||||||
|
filterActiveDriversForSocket,
|
||||||
|
filterTurnQueuesForSocket,
|
||||||
|
} = require('./filters');
|
||||||
logger.info('Discord invite loaded:', discordInvite ? 'present' : 'not configured');
|
logger.info('Discord invite loaded:', discordInvite ? 'present' : 'not configured');
|
||||||
logger.info('Ko-fi link loaded:', kofiLink ? 'present' : 'not configured');
|
logger.info('Ko-fi link loaded:', kofiLink ? 'present' : 'not configured');
|
||||||
logger.info('Socials config loaded:', configuredSocials?.length ? `${configuredSocials.length} entries` : 'not configured');
|
logger.info('Socials config loaded:', configuredSocials?.length ? `${configuredSocials.length} entries` : 'not configured');
|
||||||
|
|
||||||
const ACTIVITY_SYNC_COOLDOWN_MS = 3000;
|
|
||||||
const NIGHT_VISION_SYNC_COOLDOWN_MS = 1000;
|
|
||||||
let lastActivitySync = 0;
|
|
||||||
let pendingActivitySync = null;
|
|
||||||
let lastNightVisionSync = 0;
|
|
||||||
let pendingNightVisionSync = null;
|
|
||||||
|
|
||||||
function buildUserEntry(socket) {
|
function buildUserEntry(socket) {
|
||||||
if (!socket) return null;
|
if (!socket) return null;
|
||||||
const role = getRole(socket);
|
const role = getRole(socket);
|
||||||
@@ -61,29 +65,6 @@ function buildUserEntry(socket) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterVisibleRoverId(socket, roverId) {
|
|
||||||
if (!roverId) return null;
|
|
||||||
return roverManager.canSeeRover(roverId, socket) ? roverId : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function filterActiveDriversForSocket(activeDrivers = {}, socket) {
|
|
||||||
const next = {};
|
|
||||||
Object.entries(activeDrivers || {}).forEach(([roverId, socketId]) => {
|
|
||||||
if (!roverManager.canSeeRover(roverId, socket)) return;
|
|
||||||
next[roverId] = socketId;
|
|
||||||
});
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
function filterTurnQueuesForSocket(turnQueues = {}, socket) {
|
|
||||||
const next = {};
|
|
||||||
Object.entries(turnQueues || {}).forEach(([roverId, info]) => {
|
|
||||||
if (!roverManager.canSeeRover(roverId, socket)) return;
|
|
||||||
next[roverId] = info;
|
|
||||||
});
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildSession(socket) {
|
function buildSession(socket) {
|
||||||
const users = Array.from(io.sockets.sockets.values())
|
const users = Array.from(io.sockets.sockets.values())
|
||||||
.map((sock) => buildUserEntry(sock))
|
.map((sock) => buildUserEntry(sock))
|
||||||
@@ -182,29 +163,30 @@ modeEvents.on('change', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
managerEvents.on('rover', (event = {}) => {
|
managerEvents.on('rover', (event = {}) => {
|
||||||
|
const state = getState();
|
||||||
if (event.action === 'nightVision') {
|
if (event.action === 'nightVision') {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const elapsed = now - lastNightVisionSync;
|
const elapsed = now - state.lastNightVisionSync;
|
||||||
if (elapsed >= NIGHT_VISION_SYNC_COOLDOWN_MS) {
|
if (elapsed >= NIGHT_VISION_SYNC_COOLDOWN_MS) {
|
||||||
lastNightVisionSync = now;
|
setState({ lastNightVisionSync: now });
|
||||||
logger.info('Night vision update; syncing all clients (immediate)');
|
logger.info('Night vision update; syncing all clients (immediate)');
|
||||||
syncAll();
|
syncAll();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!pendingNightVisionSync) {
|
if (!state.pendingNightVisionSync) {
|
||||||
const delay = NIGHT_VISION_SYNC_COOLDOWN_MS - elapsed;
|
const delay = NIGHT_VISION_SYNC_COOLDOWN_MS - elapsed;
|
||||||
pendingNightVisionSync = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
lastNightVisionSync = Date.now();
|
setState({ lastNightVisionSync: Date.now(), pendingNightVisionSync: null });
|
||||||
pendingNightVisionSync = null;
|
|
||||||
logger.info('Night vision update; syncing all clients (delayed)');
|
logger.info('Night vision update; syncing all clients (delayed)');
|
||||||
syncAll();
|
syncAll();
|
||||||
}, delay);
|
}, delay);
|
||||||
|
setState({ pendingNightVisionSync: timer });
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (pendingNightVisionSync) {
|
if (state.pendingNightVisionSync) {
|
||||||
clearTimeout(pendingNightVisionSync);
|
clearTimeout(state.pendingNightVisionSync);
|
||||||
pendingNightVisionSync = null;
|
setState({ pendingNightVisionSync: null });
|
||||||
}
|
}
|
||||||
logger.info('Rover roster change; syncing all clients');
|
logger.info('Rover roster change; syncing all clients');
|
||||||
syncAll();
|
syncAll();
|
||||||
@@ -244,30 +226,31 @@ turnEvents.on('activeDriver', () => {
|
|||||||
syncAll();
|
syncAll();
|
||||||
});
|
});
|
||||||
turnEvents.on('queue', (event = {}) => {
|
turnEvents.on('queue', (event = {}) => {
|
||||||
|
const state = getState();
|
||||||
const { reason } = event;
|
const { reason } = event;
|
||||||
if (reason === 'activity') {
|
if (reason === 'activity') {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const elapsed = now - lastActivitySync;
|
const elapsed = now - state.lastActivitySync;
|
||||||
if (elapsed >= ACTIVITY_SYNC_COOLDOWN_MS) {
|
if (elapsed >= ACTIVITY_SYNC_COOLDOWN_MS) {
|
||||||
lastActivitySync = now;
|
setState({ lastActivitySync: now });
|
||||||
logger.info('Turn activity; syncing all clients (immediate)');
|
logger.info('Turn activity; syncing all clients (immediate)');
|
||||||
syncAll();
|
syncAll();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!pendingActivitySync) {
|
if (!state.pendingActivitySync) {
|
||||||
const delay = ACTIVITY_SYNC_COOLDOWN_MS - elapsed;
|
const delay = ACTIVITY_SYNC_COOLDOWN_MS - elapsed;
|
||||||
pendingActivitySync = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
lastActivitySync = Date.now();
|
setState({ lastActivitySync: Date.now(), pendingActivitySync: null });
|
||||||
pendingActivitySync = null;
|
|
||||||
logger.info('Turn activity; syncing all clients (delayed)');
|
logger.info('Turn activity; syncing all clients (delayed)');
|
||||||
syncAll();
|
syncAll();
|
||||||
}, delay);
|
}, delay);
|
||||||
|
setState({ pendingActivitySync: timer });
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (pendingActivitySync) {
|
if (state.pendingActivitySync) {
|
||||||
clearTimeout(pendingActivitySync);
|
clearTimeout(state.pendingActivitySync);
|
||||||
pendingActivitySync = null;
|
setState({ pendingActivitySync: null });
|
||||||
}
|
}
|
||||||
logger.info('Turn queue change; syncing all clients');
|
logger.info('Turn queue change; syncing all clients');
|
||||||
syncAll();
|
syncAll();
|
||||||
@@ -345,7 +328,7 @@ audioLevelsEvents.on('change', () => {
|
|||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
logger.info('Periodic session sync for all clients');
|
logger.info('Periodic session sync for all clients');
|
||||||
syncAll();
|
syncAll();
|
||||||
}, 20000);
|
}, PERIODIC_SYNC_MS);
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
buildSession,
|
buildSession,
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
// session Service state
|
||||||
|
// Purpose: Stores session sync throttling state and timer references used across event handlers.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while centralizing mutable session-sync state in one module.
|
||||||
|
let lastActivitySync = 0;
|
||||||
|
let pendingActivitySync = null;
|
||||||
|
let lastNightVisionSync = 0;
|
||||||
|
let pendingNightVisionSync = null;
|
||||||
|
|
||||||
|
function getState() {
|
||||||
|
return {
|
||||||
|
lastActivitySync,
|
||||||
|
pendingActivitySync,
|
||||||
|
lastNightVisionSync,
|
||||||
|
pendingNightVisionSync,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function setState(patch = {}) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(patch, 'lastActivitySync')) {
|
||||||
|
lastActivitySync = patch.lastActivitySync;
|
||||||
|
}
|
||||||
|
if (Object.prototype.hasOwnProperty.call(patch, 'pendingActivitySync')) {
|
||||||
|
pendingActivitySync = patch.pendingActivitySync;
|
||||||
|
}
|
||||||
|
if (Object.prototype.hasOwnProperty.call(patch, 'lastNightVisionSync')) {
|
||||||
|
lastNightVisionSync = patch.lastNightVisionSync;
|
||||||
|
}
|
||||||
|
if (Object.prototype.hasOwnProperty.call(patch, 'pendingNightVisionSync')) {
|
||||||
|
pendingNightVisionSync = patch.pendingNightVisionSync;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getState,
|
||||||
|
setState,
|
||||||
|
};
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// actions
|
||||||
|
// Purpose: Defines the actions module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
|
function stopRover(roverId) {
|
||||||
|
try {
|
||||||
|
const { issueCommand } = require('../commandService');
|
||||||
|
issueCommand(roverId, { type: 'drive', driveDirect: { left: 0, right: 0 } });
|
||||||
|
issueCommand(roverId, { type: 'motors', motorPwm: { main: 0, side: 0, vacuum: 0 } });
|
||||||
|
} catch (err) {
|
||||||
|
// best effort; log elsewhere if needed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeDriverCompletely(roverId, socketId) {
|
||||||
|
try {
|
||||||
|
const assignmentService = require('../assignmentService');
|
||||||
|
assignmentService.forceRelease(roverId, socketId);
|
||||||
|
} catch (err) {
|
||||||
|
// best effort; log elsewhere if needed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
stopRover,
|
||||||
|
removeDriverCompletely,
|
||||||
|
};
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// constants
|
||||||
|
// Purpose: Defines the constants module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
|
const ALERT_COLOR = '#ff5722';
|
||||||
|
const TURN_DURATION_MS = 60 * 1000;
|
||||||
|
const IDLE_TIMEOUT_MS = 7 * 1000;
|
||||||
|
const MAX_IDLE_SKIPS = 3;
|
||||||
|
const STALE_REAPER_MS = 5000;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
ALERT_COLOR,
|
||||||
|
TURN_DURATION_MS,
|
||||||
|
IDLE_TIMEOUT_MS,
|
||||||
|
MAX_IDLE_SKIPS,
|
||||||
|
STALE_REAPER_MS,
|
||||||
|
};
|
||||||
@@ -1,21 +1,30 @@
|
|||||||
const EventEmitter = require('events');
|
// turn Service
|
||||||
const io = require('../globals/io');
|
// Purpose: Defines the turn Service module and the helpers/state used by this service unit.
|
||||||
const { sendAlert } = require('./alertService');
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const ALERT_COLOR = '#ff5722';
|
const io = require('../../globals/io');
|
||||||
const { MODES, getMode, modeEvents } = require('./modeManager');
|
const { sendAlert } = require('../alertService');
|
||||||
|
const { MODES, getMode, modeEvents } = require('../modeManager');
|
||||||
const driverQueues = new Map(); // roverId -> { queue: [], current: socketId, timer: Timeout | null }
|
const {
|
||||||
const activeDrivers = new Map();
|
ALERT_COLOR,
|
||||||
const TURN_DURATION_MS = 60 * 1000;
|
TURN_DURATION_MS,
|
||||||
const IDLE_TIMEOUT_MS = 7 * 1000;
|
IDLE_TIMEOUT_MS,
|
||||||
const MAX_IDLE_SKIPS = 3;
|
MAX_IDLE_SKIPS,
|
||||||
const STALE_REAPER_MS = 5000;
|
STALE_REAPER_MS,
|
||||||
const turnEvents = new EventEmitter();
|
} = require('./constants');
|
||||||
const turnDeadlines = new Map(); // roverId -> timestamp when current driver expires
|
const {
|
||||||
const idleDeadlines = new Map(); // roverId -> timestamp when idle skip will happen
|
driverQueues,
|
||||||
const idleTimers = new Map(); // roverId -> Timeout
|
activeDrivers,
|
||||||
const idleSkips = new Map(); // roverId -> Map(socketId -> count)
|
turnEvents,
|
||||||
const idleDisarmed = new Map(); // roverId -> boolean, true once driver has acted this turn
|
turnDeadlines,
|
||||||
|
idleDeadlines,
|
||||||
|
idleTimers,
|
||||||
|
idleSkips,
|
||||||
|
idleDisarmed,
|
||||||
|
ensureQueue,
|
||||||
|
setActiveDriver,
|
||||||
|
getActiveDrivers,
|
||||||
|
} = require('./state');
|
||||||
|
const { stopRover, removeDriverCompletely } = require('./actions');
|
||||||
|
|
||||||
function driverAdded(roverId, socketId, force) {
|
function driverAdded(roverId, socketId, force) {
|
||||||
const queue = ensureQueue(roverId);
|
const queue = ensureQueue(roverId);
|
||||||
@@ -79,13 +88,6 @@ function isQueuedDriver(roverId, socketId) {
|
|||||||
return queue.queue.includes(socketId);
|
return queue.queue.includes(socketId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureQueue(roverId) {
|
|
||||||
if (!driverQueues.has(roverId)) {
|
|
||||||
driverQueues.set(roverId, { queue: [], current: null, timer: null });
|
|
||||||
}
|
|
||||||
return driverQueues.get(roverId);
|
|
||||||
}
|
|
||||||
|
|
||||||
function syncState(roverId) {
|
function syncState(roverId) {
|
||||||
const mode = getMode();
|
const mode = getMode();
|
||||||
const queue = ensureQueue(roverId);
|
const queue = ensureQueue(roverId);
|
||||||
@@ -222,23 +224,6 @@ function advanceTurn(roverId) {
|
|||||||
scheduleIdleTimer(roverId);
|
scheduleIdleTimer(roverId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setActiveDriver(roverId, socketId) {
|
|
||||||
if (!socketId) {
|
|
||||||
activeDrivers.delete(roverId);
|
|
||||||
} else {
|
|
||||||
activeDrivers.set(roverId, socketId);
|
|
||||||
}
|
|
||||||
turnEvents.emit('activeDriver', { roverId, socketId });
|
|
||||||
}
|
|
||||||
|
|
||||||
function getActiveDrivers() {
|
|
||||||
const map = {};
|
|
||||||
activeDrivers.forEach((socketId, roverId) => {
|
|
||||||
map[roverId] = socketId;
|
|
||||||
});
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTurnQueues() {
|
function getTurnQueues() {
|
||||||
const mode = getMode();
|
const mode = getMode();
|
||||||
const payload = {};
|
const payload = {};
|
||||||
@@ -254,25 +239,6 @@ function getTurnQueues() {
|
|||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopRover(roverId) {
|
|
||||||
try {
|
|
||||||
const { issueCommand } = require('./commandService');
|
|
||||||
issueCommand(roverId, { type: 'drive', driveDirect: { left: 0, right: 0 } });
|
|
||||||
issueCommand(roverId, { type: 'motors', motorPwm: { main: 0, side: 0, vacuum: 0 } });
|
|
||||||
} catch (err) {
|
|
||||||
// best effort; log elsewhere if needed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeDriverCompletely(roverId, socketId) {
|
|
||||||
try {
|
|
||||||
const assignmentService = require('./assignmentService');
|
|
||||||
assignmentService.forceRelease(roverId, socketId);
|
|
||||||
} catch (err) {
|
|
||||||
// best effort; log elsewhere if needed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function recordActivity(roverId, socketId) {
|
function recordActivity(roverId, socketId) {
|
||||||
const queue = driverQueues.get(roverId);
|
const queue = driverQueues.get(roverId);
|
||||||
if (!queue || queue.current !== socketId) return;
|
if (!queue || queue.current !== socketId) return;
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// state
|
||||||
|
// Purpose: Defines the state module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
|
const EventEmitter = require('events');
|
||||||
|
|
||||||
|
const driverQueues = new Map();
|
||||||
|
const activeDrivers = new Map();
|
||||||
|
const turnEvents = new EventEmitter();
|
||||||
|
const turnDeadlines = new Map();
|
||||||
|
const idleDeadlines = new Map();
|
||||||
|
const idleTimers = new Map();
|
||||||
|
const idleSkips = new Map();
|
||||||
|
const idleDisarmed = new Map();
|
||||||
|
|
||||||
|
function ensureQueue(roverId) {
|
||||||
|
if (!driverQueues.has(roverId)) {
|
||||||
|
driverQueues.set(roverId, { queue: [], current: null, timer: null });
|
||||||
|
}
|
||||||
|
return driverQueues.get(roverId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setActiveDriver(roverId, socketId) {
|
||||||
|
if (!socketId) {
|
||||||
|
activeDrivers.delete(roverId);
|
||||||
|
} else {
|
||||||
|
activeDrivers.set(roverId, socketId);
|
||||||
|
}
|
||||||
|
turnEvents.emit('activeDriver', { roverId, socketId });
|
||||||
|
}
|
||||||
|
|
||||||
|
function getActiveDrivers() {
|
||||||
|
const map = {};
|
||||||
|
activeDrivers.forEach((socketId, roverId) => {
|
||||||
|
map[roverId] = socketId;
|
||||||
|
});
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
driverQueues,
|
||||||
|
activeDrivers,
|
||||||
|
turnEvents,
|
||||||
|
turnDeadlines,
|
||||||
|
idleDeadlines,
|
||||||
|
idleTimers,
|
||||||
|
idleSkips,
|
||||||
|
idleDisarmed,
|
||||||
|
ensureQueue,
|
||||||
|
setActiveDriver,
|
||||||
|
getActiveDrivers,
|
||||||
|
};
|
||||||
+10
-7
@@ -1,13 +1,16 @@
|
|||||||
|
// verification Service
|
||||||
|
// Purpose: Defines the verification Service module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const net = require('net');
|
const net = require('net');
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
const logger = require('../globals/logger').child('verificationService');
|
const logger = require('../../globals/logger').child('verificationService');
|
||||||
const { publishEvent } = require('./eventBus');
|
const { publishEvent } = require('../eventBus');
|
||||||
const { normalizeIp } = require('../helpers/ipResolver');
|
const { normalizeIp } = require('../../helpers/ipResolver');
|
||||||
const { getNickname, setNickname } = require('./nicknameService');
|
const { getNickname, setNickname } = require('../nicknameService');
|
||||||
const { getRole, roleEvents } = require('./roleService');
|
const { getRole, roleEvents } = require('../roleService');
|
||||||
const {
|
const {
|
||||||
sanitizeNickname,
|
sanitizeNickname,
|
||||||
normalizeCookieUserId,
|
normalizeCookieUserId,
|
||||||
@@ -15,7 +18,7 @@ const {
|
|||||||
generateCookieUserId,
|
generateCookieUserId,
|
||||||
getKnownIp,
|
getKnownIp,
|
||||||
createJsonStore,
|
createJsonStore,
|
||||||
} = require('./identityService');
|
} = require('../identityService');
|
||||||
|
|
||||||
const DATA_DIR = path.join(__dirname, '..', '..', 'data');
|
const DATA_DIR = path.join(__dirname, '..', '..', 'data');
|
||||||
const STORE_PATH = path.join(DATA_DIR, 'verified-users.json');
|
const STORE_PATH = path.join(DATA_DIR, 'verified-users.json');
|
||||||
+15
-12
@@ -1,15 +1,18 @@
|
|||||||
const { app } = require('../globals/http');
|
// video Auth Service
|
||||||
const io = require('../globals/io');
|
// Purpose: Defines the video Auth Service module and the helpers/state used by this service unit.
|
||||||
const logger = require('../globals/logger').child('videoAuth');
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const videoSessions = require('./videoSessions');
|
const { app } = require('../../globals/http');
|
||||||
const { getMode, MODES } = require('./modeManager');
|
const io = require('../../globals/io');
|
||||||
const { isAdmin, isLockdownAdmin, getRole } = require('./roleService');
|
const logger = require('../../globals/logger').child('videoAuth');
|
||||||
const { isVerified } = require('./verificationService');
|
const videoSessions = require('../videoSessions');
|
||||||
const turnService = require('./turnService');
|
const { getMode, MODES } = require('../modeManager');
|
||||||
const roverManager = require('./roverManager');
|
const { isAdmin, isLockdownAdmin, getRole } = require('../roleService');
|
||||||
const { loadConfig } = require('../helpers/configLoader');
|
const { isVerified } = require('../verificationService');
|
||||||
const { getRequestIp, getSocketIp, isLocalNetwork } = require('../helpers/ipResolver');
|
const turnService = require('../turnService');
|
||||||
const { logAdminEvent } = require('./adminLogService');
|
const roverManager = require('../roverManager');
|
||||||
|
const { loadConfig } = require('../../helpers/configLoader');
|
||||||
|
const { getRequestIp, getSocketIp, isLocalNetwork } = require('../../helpers/ipResolver');
|
||||||
|
const { logAdminEvent } = require('../adminLogService');
|
||||||
|
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
const mediaConfig = config.media || {};
|
const mediaConfig = config.media || {};
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
|
// video Sessions
|
||||||
|
// Purpose: Defines the video Sessions module and the helpers/state used by this service unit.
|
||||||
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const { v4: uuidv4 } = require('uuid');
|
const { v4: uuidv4 } = require('uuid');
|
||||||
const io = require('../globals/io');
|
const io = require('../../globals/io');
|
||||||
|
|
||||||
const sessions = new Map(); // sessionId -> { socketId, sourceType, sourceId }
|
const sessions = new Map(); // sessionId -> { socketId, sourceType, sourceId }
|
||||||
const socketSessions = new Map(); // socketId -> Set(sessionId)
|
const socketSessions = new Map(); // socketId -> Set(sessionId)
|
||||||
+11
-8
@@ -1,11 +1,14 @@
|
|||||||
const io = require('../globals/io');
|
// video Socket Service
|
||||||
const logger = require('../globals/logger').child('videoSocket');
|
// Purpose: Defines the video Socket Service module and the helpers/state used by this service unit.
|
||||||
const { getMode, MODES } = require('./modeManager');
|
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
|
||||||
const { isAdmin, isLockdownAdmin, getRole } = require('./roleService');
|
const io = require('../../globals/io');
|
||||||
const videoSessions = require('./videoSessions');
|
const logger = require('../../globals/logger').child('videoSocket');
|
||||||
const roverManager = require('./roverManager');
|
const { getMode, MODES } = require('../modeManager');
|
||||||
const { loadConfig } = require('../helpers/configLoader');
|
const { isAdmin, isLockdownAdmin, getRole } = require('../roleService');
|
||||||
const { getSocketIp, isLocalNetwork } = require('../helpers/ipResolver');
|
const videoSessions = require('../videoSessions');
|
||||||
|
const roverManager = require('../roverManager');
|
||||||
|
const { loadConfig } = require('../../helpers/configLoader');
|
||||||
|
const { getSocketIp, isLocalNetwork } = require('../../helpers/ipResolver');
|
||||||
|
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
const mediaConfig = config.media || {};
|
const mediaConfig = config.media || {};
|
||||||
Reference in New Issue
Block a user