mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-11-15 03:02:17 -05:00
@@ -1,4 +1,5 @@
|
||||
// PTZ policy and session facade. Camera IO and participation each own their lifecycle.
|
||||
const { describeQueue } = require('../turnService/queueDisplay');
|
||||
const EventEmitter = require('events');
|
||||
|
||||
const io = require('../../globals/io');
|
||||
@@ -96,6 +97,8 @@ function describeParticipation(socket) {
|
||||
const entered = getOperatingMode(socket) === 'ptz' && Boolean(socket?.data?.ptzEntered);
|
||||
const isOperator = Boolean(socket && participation.state.operatorSocketId === socket.id);
|
||||
const position = socket ? participation.state.queue.indexOf(socket.id) + 1 : 0;
|
||||
const currentId = participation.state.operatorSocketId;
|
||||
const queue = currentId ? [currentId, ...participation.state.queue] : [...participation.state.queue];
|
||||
const ready = enabled && runtime.state.initialized;
|
||||
const canControl = !denialReason && entered && isOperator && ready;
|
||||
return {
|
||||
@@ -115,6 +118,8 @@ function describeParticipation(socket) {
|
||||
},
|
||||
viewMode: socket && canRequestLiveVideo(socket) ? 'live' : 'snapshot',
|
||||
turn: {
|
||||
...describeQueue(queue, currentId),
|
||||
userLabels: Object.fromEntries(queue.map((id) => [id, getSocketLabel(id)])),
|
||||
target: {
|
||||
id: PTZ_CAMERA_ID,
|
||||
name: cameraConfig.name || 'PTZ Camera',
|
||||
@@ -135,11 +140,6 @@ function describeParticipation(socket) {
|
||||
}
|
||||
|
||||
function getPublicState(socket = null) {
|
||||
const socketId = socket?.id || null;
|
||||
const queue = participation.state.queue.map((id) => ({
|
||||
socketId: id,
|
||||
label: getSocketLabel(id),
|
||||
}));
|
||||
return {
|
||||
enabled,
|
||||
id: PTZ_CAMERA_ID,
|
||||
@@ -149,11 +149,6 @@ function getPublicState(socket = null) {
|
||||
initializing: runtime.state.initializing,
|
||||
error: runtime.state.error,
|
||||
streamPath: runtime.state.streamPath,
|
||||
operatorSocketId: participation.state.operatorSocketId,
|
||||
operatorLabel: getSocketLabel(participation.state.operatorSocketId),
|
||||
queue,
|
||||
deadline: participation.state.deadline,
|
||||
blocked: null,
|
||||
status: runtime.state.status,
|
||||
light: runtime.state.light,
|
||||
ir: runtime.state.ir,
|
||||
@@ -162,9 +157,6 @@ function getPublicState(socket = null) {
|
||||
publisher: runtime.state.publisher,
|
||||
reolinkApi: runtime.state.reolinkApi,
|
||||
audio: runtime.getAudioState(),
|
||||
isOperator: Boolean(socketId && participation.state.operatorSocketId === socketId),
|
||||
queuedPosition: socketId ? participation.state.queue.indexOf(socketId) + 1 || null : null,
|
||||
canUse: socket ? canUsePtzFeature(socket) : false,
|
||||
...describeParticipation(socket),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -68,13 +68,13 @@ function getDefaultWebSources(assignment = {}, socket = null) {
|
||||
replay`, follows the camera currently controlled by that socket just as it
|
||||
follows an assigned rover below.
|
||||
|
||||
isOperator is deliberately stricter than PTZ access or queue membership:
|
||||
turn.isActive is deliberately stricter than PTZ access or queue membership:
|
||||
spectators and users waiting for a camera turn must not silently replay a
|
||||
camera they are not currently operating. Keeping this rule here also makes
|
||||
every web replay entry point share the same default instead of teaching the
|
||||
chat-command adapter about PTZ-specific state.
|
||||
*/
|
||||
if (ptzCameraService.getPublicState(socket).isOperator) {
|
||||
if (ptzCameraService.getPublicState(socket).turn.isActive) {
|
||||
const source = ptzCameraService.getReplaySource();
|
||||
if (!source) return [];
|
||||
return [{ type: source.type, id: String(source.id), label: source.label || source.id }];
|
||||
|
||||
@@ -203,6 +203,7 @@ function buildSession(socket) {
|
||||
socketId: socket?.id,
|
||||
turnInfo: turnQueues[rover.id],
|
||||
activeDriverId: activeDrivers[rover.id],
|
||||
users,
|
||||
}),
|
||||
})),
|
||||
odometers: roverManager.getOdometersForSocket(socket),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const { describeQueue } = require('./queueDisplay');
|
||||
const { TURN_DURATION_MS, IDLE_TIMEOUT_MS } = require('./constants');
|
||||
|
||||
const labels = {
|
||||
@@ -16,7 +17,7 @@ const labels = {
|
||||
};
|
||||
|
||||
// Build this from visibility-filtered session data so private rover state stays private.
|
||||
function buildRoverTurn({ rover, mode, socketId, turnInfo, activeDriverId }) {
|
||||
function buildRoverTurn({ rover, mode, socketId, turnInfo, activeDriverId, users }) {
|
||||
const queue = turnInfo?.queue || [];
|
||||
// Direct ownership can arrive before queue details on load/reconnect.
|
||||
const currentDriverId = activeDriverId || turnInfo?.current || null;
|
||||
@@ -26,6 +27,10 @@ function buildRoverTurn({ rover, mode, socketId, turnInfo, activeDriverId }) {
|
||||
const turnsAhead = enabled ? (userIndex - currentIndex + queue.length) % queue.length : null;
|
||||
return {
|
||||
target: { id: rover.id, name: rover.name, color: rover.color, fallback: rover.id },
|
||||
...describeQueue(queue, currentDriverId),
|
||||
userLabels: Object.fromEntries(queue.map((id) => [id,
|
||||
users.find((user) => user.socketId === id)?.nickname || id,
|
||||
])),
|
||||
enabled,
|
||||
isActive: turnsAhead === 0,
|
||||
turnsAhead,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// turn Service
|
||||
// Purpose: Defines the turn 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 { describeQueue } = require('./queueDisplay');
|
||||
const io = require('../../globals/io');
|
||||
const { sendAlert } = require('../alertService');
|
||||
const { MODES, getMode, modeEvents } = require('../modeManager');
|
||||
@@ -431,7 +432,7 @@ function getTurnQueues() {
|
||||
driverQueues.forEach((queue, roverId) => {
|
||||
payload[roverId] = {
|
||||
mode,
|
||||
queue: Array.from(queue.queue),
|
||||
...describeQueue(Array.from(queue.queue), queue.current),
|
||||
current: queue.current,
|
||||
deadline: turnDeadlines.get(roverId) || null,
|
||||
idleDeadline: idleDeadlines.get(roverId) || null,
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// Shared display ordering only; each service still owns its queue policy.
|
||||
function describeQueue(queue, currentId) {
|
||||
const currentIndex = currentId ? queue.indexOf(currentId) : -1;
|
||||
const nextId = queue.length > 1
|
||||
? queue[(currentIndex + 1) % queue.length]
|
||||
: null;
|
||||
return { queue, currentId, nextId };
|
||||
}
|
||||
|
||||
module.exports = { describeQueue };
|
||||
Reference in New Issue
Block a user