From a371c79151b319a822852870349927fe7bcdc342 Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Wed, 15 Jan 2025 11:20:18 +0100 Subject: [PATCH] spot: more fixes for debugger approach, check settings before enabling network --- spot/entrypoints/background.ts | 66 ++++++++------- spot/tsconfig.json | 5 +- spot/utils/networkDebuggerTracking.ts | 117 ++++++++++++-------------- 3 files changed, 95 insertions(+), 93 deletions(-) diff --git a/spot/entrypoints/background.ts b/spot/entrypoints/background.ts index bb64fdbd1..aed9610ef 100644 --- a/spot/entrypoints/background.ts +++ b/spot/entrypoints/background.ts @@ -8,9 +8,9 @@ import { mergeRequests, SpotNetworkRequest } from "~/utils/networkTrackingUtils" import { safeApiUrl } from '~/utils/smallUtils' import { attachDebuggerToTab, - detachDebuggerFromTab, + stopDebugger, getRequests as getDebuggerRequests, - resetMap + resetMap, } from "~/utils/networkDebuggerTracking"; import { messages } from '~/utils/messages' @@ -299,12 +299,6 @@ export default defineBackground(() => { if (active) { recordingState.activeTabId = active.id; } - if (settings.useDebugger) { - resetMap(); - void attachDebuggerToTab(active.id); - } else { - startTrackingNetwork(); - } void sendToActiveTab({ type: "content:mount", area: request.area, @@ -323,13 +317,6 @@ export default defineBackground(() => { mic: request.mic, audioId: request.selectedAudioDevice, audioPerm: request.permissions ? (request.mic ? 2 : 1) : 0, - }, (tabId) => { - if (settings.useDebugger) { - resetMap(); - void attachDebuggerToTab(tabId); - } else { - startTrackingNetwork(); - } }); } } @@ -349,6 +336,24 @@ export default defineBackground(() => { finalVideoBase64 = ""; const recArea = request.area; finalSpotObj.startTs = Date.now(); + if (settings.networkLogs) { + if (settings.useDebugger) { + resetMap(); + browser.tabs.query({ + active: true, + currentWindow: true, + }).then((tabs) => { + if (tabs.length === 0) { + return console.error("No active tab found"); + } + recordingState.activeTabId = tabs[0].id; + void attachDebuggerToTab(recordingState.activeTabId) + }) + } else { + console.log(settings.useDebugger, 'tab', recordingState.activeTabId) + startTrackingNetwork(); + } + } if (recArea === "tab") { function signalTabRecording() { recordingState = { @@ -632,20 +637,22 @@ export default defineBackground(() => { if (recordingState.recording === REC_STATE.stopped) { return console.error("Calling stopped recording?"); } - let networkRequests; - let mappedNetwork; - if (settings.useDebugger && recordingState.area === "tab") { - void detachDebuggerFromTab(recordingState.activeTabId); - mappedNetwork = getDebuggerRequests(); - } else { - networkRequests = getFinalRequests( - recordingState.activeTabId ?? false, - ); - stopTrackingNetwork(); - mappedNetwork = mergeRequests( - networkRequests, - injectNetworkRequests, - ); + let networkRequests: any = []; + let mappedNetwork: any = []; + if (settings.networkLogs) { + if (settings.useDebugger) { + stopDebugger(); + mappedNetwork = getDebuggerRequests(); + } else { + networkRequests = getFinalRequests( + recordingState.area === 'tab' ? recordingState.activeTabId! : undefined, + ); + stopTrackingNetwork(); + mappedNetwork = mergeRequests( + networkRequests, + injectNetworkRequests, + ); + } } injectNetworkRequests = []; finalSpotObj.network = mappedNetwork; @@ -1099,7 +1106,6 @@ export default defineBackground(() => { stopTabActivationListening(); } if (tabId !== previousTab) { - detachDebuggerFromTab(previousTab) browser.runtime .sendMessage({ type: messages.offscreen.to.checkRecStatus, diff --git a/spot/tsconfig.json b/spot/tsconfig.json index 70a38bef5..ffea6ad3b 100644 --- a/spot/tsconfig.json +++ b/spot/tsconfig.json @@ -11,6 +11,7 @@ "lib": ["es2022", "DOM"], "compilerOptions": { "jsx": "preserve", - "jsxImportSource": "solid-js" - } + "jsxImportSource": "solid-js", + "noImplicitAny": false, + }, } diff --git a/spot/utils/networkDebuggerTracking.ts b/spot/utils/networkDebuggerTracking.ts index be066715b..ad515cd75 100644 --- a/spot/utils/networkDebuggerTracking.ts +++ b/spot/utils/networkDebuggerTracking.ts @@ -1,54 +1,63 @@ -let requestMap = {} +let requestMaps = {}; +const potentialActiveTabs: Array = []; -export function resetMap() { - requestMap = {} +export function resetMap(tabId?: string) { + if (tabId) delete requestMaps[tabId]; + else requestMaps = {}; } export async function attachDebuggerToTab(tabId: string | number) { + if (requestMaps[tabId] && potentialActiveTabs.includes(tabId)) return; await new Promise((resolve, reject) => { chrome.debugger.attach({ tabId }, "1.3", () => { - if (chrome.runtime.lastError) - return reject(chrome.runtime.lastError.message); + if (chrome.runtime.lastError) return reject(chrome.runtime.lastError.message); + if (!requestMaps[tabId]) requestMaps[tabId] = {}; + potentialActiveTabs.push(tabId); chrome.debugger.sendCommand({ tabId }, "Network.enable", {}, resolve); }); chrome.debugger.onEvent.addListener(handleRequestIntercept); }); } -export async function detachDebuggerFromTab(tabId: string) { - return new Promise((resolve, reject) => { - chrome.debugger.detach({ tabId }, resolve); - chrome.debugger.onEvent.removeListener(handleRequestIntercept); - }); + +export function stopDebugger(tabId?: string | number) { + if (tabId) { + chrome.debugger.detach({ tabId }); + const index = potentialActiveTabs.indexOf(tabId); + if (index > -1) potentialActiveTabs.splice(index, 1); + } else { + potentialActiveTabs.forEach((tabId) => { + chrome.debugger.detach({ tabId }); + }); + potentialActiveTabs.length = 0; + } } const getType = (requestType: string) => { - switch (requestType) { - case "Fetch": - case "XHR": + switch (requestType.toLowerCase()) { + case "fetch": + case "xhr": case "xmlhttprequest": return 'xmlhttprequest' default: return requestType } } + function handleRequestIntercept(source, method, params) { - if (!source.tabId) return; // Not our target tab - if (!params.request) return; // No request object - if (params.request.method === "OPTIONS") return; // Ignore preflight requests + if (!source.tabId) return; + const tabId = source.tabId; + if (!requestMaps[tabId]) return; + if (params.request && params.request.method === "OPTIONS") return; + const reqId = `${tabId}_${params.requestId}`; switch (method) { case "Network.requestWillBeSent": - const reqType = params.type ? getType(params.type) : "resource"; - if (reqType !== "xmlhttprequest") { - console.log(params); - } - - requestMap[params.requestId] = { + requestMaps[tabId][reqId] = { encodedBodySize: 0, responseBodySize: 0, duration: 0, method: params.request.method, - type: reqType, + type: params.type ? getType(params.type) : "resource", statusCode: 0, url: params.request.url, body: params.request.postData || "", @@ -57,54 +66,40 @@ function handleRequestIntercept(source, method, params) { requestHeaders: params.request.headers || {}, responseHeaders: {}, timestamp: Date.now(), + time: Date.now(), }; break; - case "Network.responseReceived": - if (!requestMap[params.requestId]) return; - requestMap[params.requestId].statusCode = params.response.status; - requestMap[params.requestId].responseHeaders = - params.response.headers || {}; - // fromDiskCache or fromServiceWorker if available - if (params.response.fromDiskCache) - requestMap[params.requestId].fromCache = true; + if (!requestMaps[tabId][reqId]) return; + requestMaps[tabId][reqId].statusCode = params.response.status; + requestMaps[tabId][reqId].responseHeaders = params.response.headers || {}; + if (params.response.fromDiskCache) requestMaps[tabId][reqId].fromCache = true; break; - case "Network.dataReceived": - if (!requestMap[params.requestId]) return; - requestMap[params.requestId].encodedBodySize += params.dataLength; - // There's no direct content-encoding size from debugger + if (!requestMaps[tabId][reqId]) return; + requestMaps[tabId][reqId].encodedBodySize += params.dataLength; break; - case "Network.loadingFinished": - if (!requestMap[params.requestId]) return; - requestMap[params.requestId].duration = - Date.now() - requestMap[params.requestId].time; - requestMap[params.requestId].responseBodySize = - requestMap[params.requestId].encodedBodySize; - chrome.debugger.sendCommand( - { tabId: source.tabId }, - "Network.getResponseBody", - { requestId: params.requestId }, - (res) => { - if (!res || res.error) { - requestMap[params.requestId].error = res?.error || "Unknown"; - } else { - requestMap[params.requestId].responseBody = res.base64Encoded - ? atob(res.body) - : res.body; - } - }, - ); + if (!requestMaps[tabId][reqId]) return; + requestMaps[tabId][reqId].duration = Date.now() - requestMaps[tabId][reqId].timestamp; + requestMaps[tabId][reqId].responseBodySize = requestMaps[tabId][reqId].encodedBodySize; + chrome.debugger.sendCommand({ tabId }, "Network.getResponseBody", { requestId: params.requestId }, (res) => { + if (!res || res.error) { + requestMaps[tabId][reqId].error = res?.error || "Unknown"; + } else { + requestMaps[tabId][reqId].responseBody = res.base64Encoded ? 'base64 payload' : res.body; + } + }); break; - case "Network.loadingFailed": - if (!requestMap[params.requestId]) return; - requestMap[params.requestId].error = params.errorText || "Unknown"; + if (!requestMaps[tabId][reqId]) return; + requestMaps[tabId][reqId].error = params.errorText || "Unknown"; break; } } -export const getRequests = () => { - return Object.values(requestMap); -}; +export function getRequests(tabId?: string) { + if (tabId) { + return Object.values(requestMaps[tabId] || {}); + } +}