gonna break stuff now
Container image / image (push) Failing after 51s

This commit is contained in:
legop3
2026-09-24 18:36:24 -04:00
parent 8ca714cf1a
commit 7231809140
30 changed files with 292 additions and 388 deletions
+5 -13
View File
@@ -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),
+6 -1
View File
@@ -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,
+2 -1
View File
@@ -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 };