diff --git a/src/background/index.ts b/src/background/index.ts index 20b987b..7053737 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -9,12 +9,11 @@ import JSZip from 'jszip'; const logger = new Logger('Main'); -// Константы -const VIDEO_BUFFER_DURATION_MS = 30 * 1000; // 30 секунд - // Состояние +// videoBuffer is a placeholder array on the SW side; Plan 04 wires it to +// fetch from the offscreen recorder over the 'video-keepalive' port. +// Until then it stays empty (the offscreen owns the real buffer per D-16). let videoBuffer: VideoChunk[] = []; -let firstChunkSaved = false; // Флаг что первый чанк уже сохранен let isRecording = false; let offscreenCreated = false; let lastScreenshotTime = 0; @@ -22,57 +21,9 @@ let cachedScreenshot: Blob | null = null; // userEvents хранится только в content script // Для архивации получаем его оттуда -// Кольцевой буфер видео -function addVideoChunkFromBlob(blob: Blob) { - logger.log(`Processing video chunk from Blob, size: ${blob.size} bytes, type: ${blob.type}`); - - const chunk: VideoChunk = { - data: blob, - timestamp: Date.now(), - isFirst: !firstChunkSaved // Первый чанк помечаем как isFirst - }; - - if (!firstChunkSaved) { - firstChunkSaved = true; - logger.log(`This is the FIRST video chunk (WebM header), size: ${blob.size} bytes`); - } - - videoBuffer.push(chunk); - logger.log(`Added video chunk, buffer size: ${videoBuffer.length}, chunk size: ${blob.size} bytes, isFirst: ${chunk.isFirst}`); - - // Удаляем старые чанки - cleanupVideoBuffer(); -} - -function cleanupVideoBuffer() { - const now = Date.now(); - const beforeCount = videoBuffer.length; - - logger.log(`Cleaning up buffer, current size: ${beforeCount}`); - - // Всегда сохраняем первый чанк (WebM заголовок, помечен как isFirst) - // Остальные чанки фильтруем по времени (старше 30 секунд удаляем) - videoBuffer = videoBuffer.filter(chunk => { - // Всегда оставляем первый чанк (заголовок) - if (chunk.isFirst) { - return true; - } - // Остальные - только если моложе 30 секунд - const age = now - chunk.timestamp; - const keep = age < VIDEO_BUFFER_DURATION_MS; - if (!keep) { - logger.log(`Removing chunk, age: ${age}ms, limit: ${VIDEO_BUFFER_DURATION_MS}ms`); - } - return keep; - }); - - const removed = beforeCount - videoBuffer.length; - if (removed > 0) { - logger.log(`Removed ${removed} old video chunks, buffer: ${videoBuffer.length}`); - } else { - logger.log(`No chunks removed, buffer: ${videoBuffer.length}`); - } -} +// addVideoChunkFromBlob / cleanupVideoBuffer / VIDEO_BUFFER_DURATION_MS +// removed in plan 01-03: the ring buffer now lives in src/offscreen/recorder.ts +// (D-16). Plan 05 collapses the remaining SW shell further. // Создание offscreen документа async function ensureOffscreen() { @@ -454,23 +405,13 @@ chrome.runtime.onMessage.addListener((message: Message, _sender, sendResponse) = }); return true; - case 'VIDEO_CHUNK': - const videoData = (message as any).data; - const videoTimestamp = (message as any).timestamp; - if (videoData && videoData.size > 0) { - logger.log(`Received video chunk from offscreen, size: ${videoData.size} bytes, timestamp: ${videoTimestamp}`); - addVideoChunkFromBlob(videoData); - } else { - logger.warn('Received empty or invalid video chunk'); - } - return false; - - case 'VIDEO_CHUNK_SAVED': - const chunkId = (message as any).chunkId; - const size = (message as any).size; - logger.log(`Video chunk ${chunkId} saved, size: ${size} bytes, loading from IndexedDB...`); - loadChunkFromIndexedDB(chunkId); - return false; + // VIDEO_CHUNK and VIDEO_CHUNK_SAVED handlers removed in plan 01-03: + // - the offscreen recorder now owns the buffer (D-16); + // - chunks no longer travel via chrome.runtime.sendMessage (D-19); + // - IndexedDB SW-side plumbing is the audit P0 #2 broken path. + // loadChunkFromIndexedDB / openIndexedDB also removed inline (they + // were only reachable from the deleted VIDEO_CHUNK_SAVED branch). + // Plan 05 collapses the remaining SW dead code further. default: logger.warn('Unknown message type:', message.type); @@ -478,47 +419,6 @@ chrome.runtime.onMessage.addListener((message: Message, _sender, sendResponse) = } }); -// IndexedDB для загрузки видеочанков -async function loadChunkFromIndexedDB(chunkId: number) { - try { - const db = await openIndexedDB(); - const transaction = db.transaction(['chunks'], 'readonly'); - const store = transaction.objectStore('chunks'); - const request = store.get(chunkId); - - request.onsuccess = () => { - const record = request.result; - if (record) { - logger.log(`Loaded chunk ${chunkId} from IndexedDB, size: ${record.data.size} bytes`); - addVideoChunkFromBlob(record.data); - } else { - logger.error(`Chunk ${chunkId} not found in IndexedDB`); - } - }; - - request.onerror = () => { - logger.error(`Error loading chunk ${chunkId} from IndexedDB:`, request.error); - }; - } catch (error) { - logger.error(`Failed to open IndexedDB:`, error); - } -} - -async function openIndexedDB(): Promise { - return new Promise((resolve, reject) => { - const request = indexedDB.open('VideoRecorderDB', 1); - - request.onerror = () => reject(request.error); - request.onsuccess = () => resolve(request.result); - request.onupgradeneeded = (event) => { - const db = (event.target as IDBOpenDBRequest).result; - if (!db.objectStoreNames.contains('chunks')) { - db.createObjectStore('chunks', { keyPath: 'id' }); - } - }; - }); -} - // Инициализация function initialize() { logger.log('Service Worker initializing'); diff --git a/src/shared/types.ts b/src/shared/types.ts index 212d905..b6f0ec8 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -13,8 +13,6 @@ export type MessageType = | 'START_RECORDING' | 'STOP_RECORDING' | 'RECORDING_ERROR' - | 'VIDEO_CHUNK' - | 'VIDEO_CHUNK_SAVED' | 'OFFSCREEN_READY'; export interface Message { @@ -23,6 +21,17 @@ export interface Message { tabId?: number; } +// Типы сообщений в long-lived port (offscreen ↔ SW; D-17 / Plan 04) +export type PortMessageType = + | 'PING' + | 'REQUEST_BUFFER' + | 'BUFFER'; + +export interface PortMessage { + type: PortMessageType; + chunks?: VideoChunk[]; +} + // Видеобуфер export interface VideoChunk { data: Blob;