fix(lab): сжать и адресовать RAV004 overlay

This commit is contained in:
DCCONSTRUCTIONS
2026-08-30 14:05:32 +03:00
parent 07453142c2
commit 35daf73d5c
5 changed files with 316 additions and 58 deletions
@@ -152,6 +152,7 @@ interface RerunNativeReceiver {
interface LoadedNativePerceptionSource {
receiver: RerunNativeReceiver;
descriptorUrl: string;
sourceUrl: string;
byteLength: number;
}
@@ -596,7 +597,7 @@ export function resolveRecordedPerceptionViewerSourceUrl(
return endpoint.href;
}
/** Verify the immutable URL with a four-byte range request before Rerun opens it. */
/** Resolve the immutable overlay generation before Rerun opens its native URL. */
export async function probeRecordedPerceptionViewerSource(
sourceUrl: string,
{
@@ -608,7 +609,7 @@ export async function probeRecordedPerceptionViewerSource(
signal?: AbortSignal;
fetcher?: typeof globalThis.fetch;
},
): Promise<number> {
): Promise<{ sourceUrl: string; byteLength: number }> {
const base = new URL(origin);
const endpoint = new URL(sourceUrl, base.origin);
const allowedParameters = ["application_id", "generation", "recording_id"];
@@ -626,57 +627,29 @@ export async function probeRecordedPerceptionViewerSource(
throw new Error("Unsafe recorded perception viewer source");
}
const response = await fetcher(endpoint.href, {
method: "GET",
method: "HEAD",
credentials: "same-origin",
headers: {
Accept: "application/vnd.rerun.rrd",
Range: "bytes=0-3",
},
signal,
});
const contentType = response.headers.get("Content-Type")?.split(";", 1)[0].trim();
const contentRange = response.headers.get("Content-Range");
const rangedLength = contentRange?.match(/^bytes 0-3\/(\d+)$/)?.[1];
const declaredLength = Number(
rangedLength ?? response.headers.get("Content-Length"),
);
const declaredLength = Number(response.headers.get("Content-Length"));
const etag = response.headers.get("ETag")?.match(/^"([a-f0-9]{64})"$/)?.[1];
if (
![200, 206].includes(response.status) ||
response.status !== 200 ||
contentType !== "application/vnd.rerun.rrd" ||
response.headers.get("X-Rerun-Format") !== "RRF2" ||
!etag ||
!Number.isSafeInteger(declaredLength) ||
declaredLength < 4 ||
declaredLength > MAX_PERCEPTION_BYTES
) {
throw new Error("Invalid recorded perception viewer response");
}
const prefix = new Uint8Array(4);
let receivedBytes = 0;
const reader = response.body?.getReader();
if (reader) {
while (receivedBytes < prefix.byteLength) {
const { done, value } = await reader.read();
if (done) break;
const count = Math.min(value.byteLength, prefix.byteLength - receivedBytes);
prefix.set(value.subarray(0, count), receivedBytes);
receivedBytes += count;
}
await reader.cancel();
} else {
const payload = new Uint8Array(await response.arrayBuffer());
const count = Math.min(payload.byteLength, prefix.byteLength);
prefix.set(payload.subarray(0, count));
receivedBytes = count;
}
if (
receivedBytes !== prefix.byteLength ||
prefix[0] !== 0x52 ||
prefix[1] !== 0x52 ||
prefix[2] !== 0x46 ||
prefix[3] !== 0x32
) {
throw new Error("Invalid recorded perception viewer RRD");
}
return declaredLength;
endpoint.searchParams.set("overlay_generation", etag);
return { sourceUrl: endpoint.href, byteLength: declaredLength };
}
export function RerunViewport({
@@ -1636,7 +1609,7 @@ export function RerunViewport({
return;
}
const loaded = loadedNativePerceptionSourceRef.current;
if (loaded?.receiver === receiver && loaded.sourceUrl === sourceUrl) {
if (loaded?.receiver === receiver && loaded.descriptorUrl === sourceUrl) {
onPerceptionLoadChange?.({
phase: "ready",
receivedBytes: loaded.byteLength,
@@ -1657,17 +1630,18 @@ export function RerunViewport({
void probeRecordedPerceptionViewerSource(sourceUrl, {
origin: window.location.origin,
signal: abort.signal,
}).then((byteLength) => {
}).then(({ sourceUrl: immutableSourceUrl, byteLength }) => {
if (
abort.signal.aborted ||
perceptionReceiverRef.current !== receiver ||
recordedIdentityRef.current !== identity ||
!receiver.ready()
) return;
receiver.open(sourceUrl);
receiver.open(immutableSourceUrl);
loadedNativePerceptionSourceRef.current = {
receiver,
sourceUrl,
descriptorUrl: sourceUrl,
sourceUrl: immutableSourceUrl,
byteLength,
};
onPerceptionLoadChange?.({