mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
update idleservice so that its based on users not drivers
This commit is contained in:
@@ -1,33 +1,63 @@
|
|||||||
// Idle Service
|
// Idle Service
|
||||||
// Purpose: Triggers a modular idle action pipeline after a sustained no-driver period.
|
// Purpose: Triggers a modular idle action pipeline after a sustained no-operator-online period.
|
||||||
// Scope: Observes driver activity events and coordinates timer-based idle automation execution.
|
// Scope: Observes user/admin socket presence and coordinates timer-based idle automation execution.
|
||||||
const logger = require('../../globals/logger').child('idleService');
|
const logger = require('../../globals/logger').child('idleService');
|
||||||
const { getActiveDrivers, turnEvents } = require('../turnService');
|
const io = require('../../globals/io');
|
||||||
const roverManager = require('../roverManager');
|
const { getRole, roleEvents } = require('../roleService');
|
||||||
const { getRecentDriveActivity } = require('../commandService');
|
|
||||||
const { IDLE_TIMEOUT_MS } = require('./constants');
|
const { IDLE_TIMEOUT_MS } = require('./constants');
|
||||||
const { runtime } = require('./state');
|
const { runtime } = require('./state');
|
||||||
const { runIdleActions } = require('./actions');
|
const { runIdleActions } = require('./actions');
|
||||||
|
|
||||||
function getActivitySnapshot() {
|
function getActivitySnapshot() {
|
||||||
const active = getActiveDrivers();
|
let onlineUsers = 0;
|
||||||
const turnCount = active && typeof active === 'object' ? Object.keys(active).length : 0;
|
let onlineAdmins = 0;
|
||||||
const activeByTurn = turnCount;
|
let onlineSpectators = 0;
|
||||||
|
let onlineIgnored = 0;
|
||||||
|
|
||||||
let liveCount = 0;
|
io.sockets.sockets.forEach((socket) => {
|
||||||
roverManager.rovers.forEach((record) => {
|
const role = getRole(socket);
|
||||||
if (record?.drivers?.size > 0) liveCount += 1;
|
|
||||||
|
/*
|
||||||
|
Idle automation is about whether a real operator is present, not whether
|
||||||
|
a browser tab is merely watching. Spectators can leave the room lights,
|
||||||
|
PTZ emitters, and rovers in their automated idle state because they are
|
||||||
|
intentionally read-only and cannot be the person still using the setup.
|
||||||
|
*/
|
||||||
|
if (role === 'spectator') {
|
||||||
|
onlineSpectators += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Lockdown admins are counted with regular admins because both represent a
|
||||||
|
person with operator-level access who may be supervising the room without
|
||||||
|
actively driving a rover. Plain users also count even before they request
|
||||||
|
control, which is the behavior this service now needs.
|
||||||
|
*/
|
||||||
|
if (role === 'admin' || role === 'lockdown') {
|
||||||
|
onlineAdmins += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (role === 'user') {
|
||||||
|
onlineUsers += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Unknown future roles should not accidentally keep automation disabled.
|
||||||
|
If a new role should count as an operator, it should be added explicitly
|
||||||
|
above so this policy remains easy to audit.
|
||||||
|
*/
|
||||||
|
onlineIgnored += 1;
|
||||||
});
|
});
|
||||||
const activeByRoverDrivers = liveCount;
|
|
||||||
|
|
||||||
const recentDriveEvents = getRecentDriveActivity(IDLE_TIMEOUT_MS, { excludeAdmins: false });
|
const totalActive = onlineUsers + onlineAdmins;
|
||||||
const activeByRecentDrive = recentDriveEvents.length;
|
|
||||||
|
|
||||||
const totalActive = Math.max(activeByTurn, activeByRoverDrivers, activeByRecentDrive);
|
|
||||||
return {
|
return {
|
||||||
activeByTurn,
|
onlineUsers,
|
||||||
activeByRoverDrivers,
|
onlineAdmins,
|
||||||
activeByRecentDrive,
|
onlineSpectators,
|
||||||
|
onlineIgnored,
|
||||||
totalActive,
|
totalActive,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -53,7 +83,7 @@ function scheduleIdleTimer() {
|
|||||||
runtime.deadlineAt = null;
|
runtime.deadlineAt = null;
|
||||||
const activity = getActivitySnapshot();
|
const activity = getActivitySnapshot();
|
||||||
if (activity.totalActive > 0) {
|
if (activity.totalActive > 0) {
|
||||||
logger.info('Idle automation skipped; active control detected', activity);
|
logger.info('Idle automation skipped; user or admin online', activity);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
runtime.lastTriggeredAt = Date.now();
|
runtime.lastTriggeredAt = Date.now();
|
||||||
@@ -77,8 +107,18 @@ function refreshIdleState() {
|
|||||||
scheduleIdleTimer();
|
scheduleIdleTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
turnEvents.on('activeDriver', refreshIdleState);
|
io.on('connection', (socket) => {
|
||||||
turnEvents.on('queue', refreshIdleState);
|
/*
|
||||||
|
A user/admin can be online without ever touching rover controls, so socket
|
||||||
|
presence has to be a first-class idle signal. The disconnect hook is just as
|
||||||
|
important: it is what starts the idle timeout after the last non-spectator
|
||||||
|
leaves, even if no driving event happens around that departure.
|
||||||
|
*/
|
||||||
|
refreshIdleState();
|
||||||
|
socket.on('disconnect', refreshIdleState);
|
||||||
|
});
|
||||||
|
|
||||||
|
roleEvents.on('change', refreshIdleState);
|
||||||
|
|
||||||
refreshIdleState();
|
refreshIdleState();
|
||||||
|
|
||||||
|
|||||||
@@ -347,7 +347,7 @@ function startPublisher() {
|
|||||||
'-tune',
|
'-tune',
|
||||||
'zerolatency',
|
'zerolatency',
|
||||||
'-threads',
|
'-threads',
|
||||||
'2',
|
'8',
|
||||||
'-x264-params',
|
'-x264-params',
|
||||||
'sliced-threads=1:sync-lookahead=0:rc-lookahead=0:keyint=20:min-keyint=20:scenecut=0',
|
'sliced-threads=1:sync-lookahead=0:rc-lookahead=0:keyint=20:min-keyint=20:scenecut=0',
|
||||||
'-bf',
|
'-bf',
|
||||||
|
|||||||
Reference in New Issue
Block a user