fix(webapp): log recording upload failures and restore 6s clips
This commit is contained in:
@@ -34,7 +34,7 @@ const MOTION_DETECTION_PROFILES = {
|
||||
releaseThreshold: 0.05,
|
||||
consecutiveTriggerFrames: 3,
|
||||
cooldownMs: 12000,
|
||||
minimumEventMs: 9000
|
||||
minimumEventMs: 6000
|
||||
},
|
||||
balanced: {
|
||||
profile: 'balanced',
|
||||
@@ -46,7 +46,7 @@ const MOTION_DETECTION_PROFILES = {
|
||||
releaseThreshold: 0.04,
|
||||
consecutiveTriggerFrames: 3,
|
||||
cooldownMs: 9000,
|
||||
minimumEventMs: 8000
|
||||
minimumEventMs: 6000
|
||||
},
|
||||
responsive: {
|
||||
profile: 'responsive',
|
||||
@@ -58,7 +58,7 @@ const MOTION_DETECTION_PROFILES = {
|
||||
releaseThreshold: 0.035,
|
||||
consecutiveTriggerFrames: 2,
|
||||
cooldownMs: 7000,
|
||||
minimumEventMs: 7000
|
||||
minimumEventMs: 6000
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1478,6 +1478,24 @@ const startOfferToClient = async (streamSessionId, requesterDeviceId) => {
|
||||
|
||||
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
const summarizeFetchFailure = async (response) => {
|
||||
if (!response) {
|
||||
return 'no response returned';
|
||||
}
|
||||
|
||||
const parts = [`status ${response.status}`];
|
||||
try {
|
||||
const bodyText = (await response.text()).trim();
|
||||
if (bodyText) {
|
||||
parts.push(bodyText.slice(0, 240));
|
||||
}
|
||||
} catch {
|
||||
// Ignore body parsing failures for diagnostics.
|
||||
}
|
||||
|
||||
return parts.join(' · ');
|
||||
};
|
||||
|
||||
const finalizeRecordingForStream = async (streamSessionId, captureResult) => {
|
||||
const currentDevice = getAppState().device;
|
||||
if (!currentDevice?.id) {
|
||||
@@ -1496,6 +1514,8 @@ const finalizeRecordingForStream = async (streamSessionId, captureResult) => {
|
||||
if (!captureResult?.blob || captureResult.blob.size === 0) {
|
||||
throw new Error('No captured video blob to upload');
|
||||
}
|
||||
|
||||
addActivity('Recording', `Preparing upload for stream ${streamSessionId}`);
|
||||
const compressedBlob = await compressRecordingBlob(captureResult.blob);
|
||||
|
||||
const uploadMeta = await api.request('/videos/upload-url', {
|
||||
@@ -1507,6 +1527,26 @@ const finalizeRecordingForStream = async (streamSessionId, captureResult) => {
|
||||
recordingId: recording.id
|
||||
})
|
||||
});
|
||||
const uploadOrigin = (() => {
|
||||
try {
|
||||
return new URL(uploadMeta.uploadUrl).origin;
|
||||
} catch {
|
||||
return 'invalid upload URL';
|
||||
}
|
||||
})();
|
||||
console.info('[recording.upload] upload URL issued', {
|
||||
recordingId: recording.id,
|
||||
streamSessionId,
|
||||
objectKey: uploadMeta.objectKey,
|
||||
bucket: uploadMeta.bucket,
|
||||
uploadOrigin,
|
||||
blobSize: compressedBlob.size,
|
||||
blobType: compressedBlob.type || 'video/webm'
|
||||
});
|
||||
addActivity(
|
||||
'Recording',
|
||||
`Upload URL ready for ${uploadMeta.objectKey} via ${uploadOrigin}`
|
||||
);
|
||||
|
||||
const uploadResponse = await fetch(uploadMeta.uploadUrl, {
|
||||
method: 'PUT',
|
||||
@@ -1515,9 +1555,19 @@ const finalizeRecordingForStream = async (streamSessionId, captureResult) => {
|
||||
});
|
||||
|
||||
if (!uploadResponse.ok) {
|
||||
throw new Error(`Upload failed with status ${uploadResponse.status}`);
|
||||
throw new Error(`Upload failed: ${await summarizeFetchFailure(uploadResponse)}`);
|
||||
}
|
||||
|
||||
console.info('[recording.upload] object uploaded', {
|
||||
recordingId: recording.id,
|
||||
streamSessionId,
|
||||
objectKey: uploadMeta.objectKey,
|
||||
bucket: uploadMeta.bucket,
|
||||
status: uploadResponse.status,
|
||||
sizeBytes: compressedBlob.size
|
||||
});
|
||||
addActivity('Recording', `Upload completed for ${uploadMeta.objectKey}`);
|
||||
|
||||
await api.events.finalizeRecording(recording.id, {
|
||||
objectKey: uploadMeta.objectKey,
|
||||
bucket: uploadMeta.bucket,
|
||||
@@ -1525,14 +1575,29 @@ const finalizeRecordingForStream = async (streamSessionId, captureResult) => {
|
||||
sizeBytes: compressedBlob.size
|
||||
});
|
||||
|
||||
console.info('[recording.upload] recording finalized', {
|
||||
recordingId: recording.id,
|
||||
streamSessionId,
|
||||
objectKey: uploadMeta.objectKey,
|
||||
durationSeconds: captureResult.durationSeconds,
|
||||
sizeBytes: compressedBlob.size
|
||||
});
|
||||
addActivity('Recording', 'Recording uploaded and finalized');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Recording upload failed, falling back to simulated key', error);
|
||||
console.error('[recording.upload] stream upload failed, falling back to simulated key', {
|
||||
recordingId: recording.id,
|
||||
streamSessionId,
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
addActivity(
|
||||
'Recording',
|
||||
`Upload failed for stream ${streamSessionId}: ${error instanceof Error ? error.message : 'unknown error'}`
|
||||
);
|
||||
const fallbackObjectKey = `sim/${streamSessionId}/${Date.now()}.webm`;
|
||||
await api.events.finalizeRecording(recording.id, {
|
||||
objectKey: fallbackObjectKey,
|
||||
durationSeconds: captureResult?.durationSeconds ?? 15,
|
||||
durationSeconds: captureResult?.durationSeconds ?? 6,
|
||||
sizeBytes: captureResult?.blob?.size ?? 5000000
|
||||
});
|
||||
addActivity('Recording', 'Upload failed; finalized with simulator fallback');
|
||||
@@ -1560,6 +1625,7 @@ const uploadStandaloneMotionRecording = async (captureResult) => {
|
||||
}
|
||||
|
||||
try {
|
||||
addActivity('Recording', 'Preparing standalone motion clip upload');
|
||||
const compressedBlob = await compressRecordingBlob(captureResult.blob);
|
||||
const uploadMeta = await api.request('/videos/upload-url', {
|
||||
method: 'POST',
|
||||
@@ -1570,6 +1636,23 @@ const uploadStandaloneMotionRecording = async (captureResult) => {
|
||||
eventId: lastMotionEventId
|
||||
})
|
||||
});
|
||||
const uploadOrigin = (() => {
|
||||
try {
|
||||
return new URL(uploadMeta.uploadUrl).origin;
|
||||
} catch {
|
||||
return 'invalid upload URL';
|
||||
}
|
||||
})();
|
||||
console.info('[recording.upload] standalone upload URL issued', {
|
||||
eventId: lastMotionEventId,
|
||||
recordingId: uploadMeta.video?.id,
|
||||
objectKey: uploadMeta.objectKey,
|
||||
bucket: uploadMeta.bucket,
|
||||
uploadOrigin,
|
||||
blobSize: compressedBlob.size,
|
||||
blobType: compressedBlob.type || 'video/webm'
|
||||
});
|
||||
addActivity('Recording', `Standalone upload URL ready via ${uploadOrigin}`);
|
||||
|
||||
const uploadResponse = await fetch(uploadMeta.uploadUrl, {
|
||||
method: 'PUT',
|
||||
@@ -1578,9 +1661,19 @@ const uploadStandaloneMotionRecording = async (captureResult) => {
|
||||
});
|
||||
|
||||
if (!uploadResponse.ok) {
|
||||
throw new Error(`Upload failed with status ${uploadResponse.status}`);
|
||||
throw new Error(`Upload failed: ${await summarizeFetchFailure(uploadResponse)}`);
|
||||
}
|
||||
|
||||
console.info('[recording.upload] standalone object uploaded', {
|
||||
eventId: lastMotionEventId,
|
||||
recordingId: uploadMeta.video?.id,
|
||||
objectKey: uploadMeta.objectKey,
|
||||
bucket: uploadMeta.bucket,
|
||||
status: uploadResponse.status,
|
||||
sizeBytes: compressedBlob.size
|
||||
});
|
||||
addActivity('Recording', `Standalone upload completed for ${uploadMeta.objectKey}`);
|
||||
|
||||
await api.events.finalizeRecording(uploadMeta.video.id, {
|
||||
objectKey: uploadMeta.objectKey,
|
||||
bucket: uploadMeta.bucket,
|
||||
@@ -1588,11 +1681,24 @@ const uploadStandaloneMotionRecording = async (captureResult) => {
|
||||
sizeBytes: compressedBlob.size
|
||||
});
|
||||
|
||||
console.info('[recording.upload] standalone recording finalized', {
|
||||
eventId: lastMotionEventId,
|
||||
recordingId: uploadMeta.video?.id,
|
||||
objectKey: uploadMeta.objectKey,
|
||||
durationSeconds: captureResult.durationSeconds,
|
||||
sizeBytes: compressedBlob.size
|
||||
});
|
||||
addActivity('Recording', `Motion clip uploaded (${uploadMeta.objectKey})`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Standalone motion upload failed', error);
|
||||
addActivity('Recording', 'Standalone motion upload failed');
|
||||
console.error('[recording.upload] standalone motion upload failed', {
|
||||
eventId: lastMotionEventId,
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
addActivity(
|
||||
'Recording',
|
||||
`Standalone motion upload failed: ${error instanceof Error ? error.message : 'unknown error'}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user