This commit is contained in:
legop3
2026-07-12 01:58:46 -04:00
parent 76318e6b36
commit 2cef95e6e3
11 changed files with 63 additions and 32 deletions
@@ -42,6 +42,12 @@ function resolveRoverName(roverId) {
function isPrivateClosedRoverId(roverId) {
if (!roverId) return false;
/*
PTZ uses the existing rover badge fields so chat rows can reuse RoverLabel,
but it is not a private rover. Let PTZ-badged messages broadcast normally
instead of falling into the closed-private rover path for unknown ids.
*/
if (String(roverId) === ptzCameraService.PTZ_CAMERA_ID) return false;
return roverManager.canReplayRoverId(roverId) !== true;
}
@@ -664,7 +664,6 @@ function revokeOperator(reason = 'release') {
function activateOperator(socket) {
revokeOperator('handoff');
removeFromQueue(socket.id);
releaseRoverOwnershipForPtz(socket);
state.operatorSocketId = socket.id;
state.deadline = Date.now() + getTurnDurationMs();
turnTimer = setTimeout(handleTurnDeadline, getTurnDurationMs());
@@ -731,6 +730,15 @@ async function claim(socket) {
socket.emit('ptzCamera:dockRequired', payload);
throw new Error(leave.message);
}
/*
Joining PTZ is the point where rover ownership must end, even when another
user is currently operating the camera and this socket only enters the
waiting queue. PTZ queue membership is still a camera session: the user is
waiting for a camera turn, not continuing as a rover driver until their turn
arrives. Releasing here also keeps chat badges, assignment UI, and command
routing from presenting a "rover plus camera queue" hybrid state.
*/
releaseRoverOwnershipForPtz(socket);
if (state.operatorSocketId) {
if (!state.queue.includes(socket.id)) state.queue.push(socket.id);
emitChange('queue-join');