Защита Bridge и камеры K1 при переподключении

This commit is contained in:
DCCONSTRUCTIONS
2026-08-23 01:25:25 +03:00
parent 0752e5c6bf
commit 71c8b043c9
8 changed files with 737 additions and 87 deletions
@@ -96,6 +96,23 @@ export function livePresentationCloseFence(
return acquisitionId ? JSON.stringify([source.id, acquisitionId]) : null;
}
function acquisitionIdFromLivePresentationCloseFence(fence: string): string | null {
try {
const decoded: unknown = JSON.parse(fence);
if (
!Array.isArray(decoded)
|| decoded.length !== 2
|| typeof decoded[0] !== "string"
|| typeof decoded[1] !== "string"
|| !decoded[0].trim()
|| !decoded[1].trim()
) return null;
return decoded[1].trim();
} catch {
return null;
}
}
export interface LiveDefaultPresentationAdmission {
visibleIds: string[];
removedIds: string[];
@@ -132,9 +149,11 @@ export function admitLiveDefaultPresentations(
/**
* A restored workspace may hide cameras that the device plugin has not selected.
* It must still admit the exact selected delivery in a fresh browser document,
* or a replacement delivery for a camera already presented in this acquisition.
* a replacement delivery for a camera already presented in this acquisition,
* or the first delivery of a later acquisition in the same browser document.
* An explicit close remains a separate acquisition-scoped fence in
* `admitLiveDefaultPresentations` and de-selects the source in the plugin first.
* `admitLiveDefaultPresentations`; whether it may de-select the source remains
* the plugin's current activation-authority decision.
*/
export function restoredLayoutMayAdmitLiveDefault(
sources: readonly ObservationSourceDescriptor[],
@@ -145,7 +164,13 @@ export function restoredLayoutMayAdmitLiveDefault(
if (presentedAcquisitionSources.size === 0) return true;
return selectedSources.some((source) => {
const lineage = livePresentationCloseFence(source);
return Boolean(lineage && presentedAcquisitionSources.has(lineage));
if (!lineage) return false;
if (presentedAcquisitionSources.has(lineage)) return true;
const acquisitionId = source.binding.acquisitionId?.trim();
if (!acquisitionId) return false;
return ![...presentedAcquisitionSources].some(
(presented) => acquisitionIdFromLivePresentationCloseFence(presented) === acquisitionId,
);
});
}