diff --git a/rspack.config.ts b/rspack.config.ts index 91969281c..691277ecb 100644 --- a/rspack.config.ts +++ b/rspack.config.ts @@ -52,6 +52,7 @@ export default { service_worker: `${src}/service_worker.ts`, offscreen: `${src}/offscreen.ts`, sandbox: `${src}/sandbox.ts`, + persistent_frame: `${src}/persistent_frame.ts`, content: `${src}/content.ts`, scripting: `${src}/scripting.ts`, inject: `${src}/inject.ts`, @@ -233,6 +234,13 @@ export default { minify: true, chunks: ["sandbox"], }), + new rspack.HtmlRspackPlugin({ + filename: `${dist}/ext/src/persistent_frame.html`, + template: `${src}/pages/persistent_frame.html`, + inject: "head", + minify: true, + chunks: ["persistent_frame"], + }), new ZipExecutionPlugin(), ].filter(Boolean), experiments: { diff --git a/src/pages/persistent_frame.html b/src/pages/persistent_frame.html new file mode 100644 index 000000000..bb5973e67 --- /dev/null +++ b/src/pages/persistent_frame.html @@ -0,0 +1,11 @@ + + + + + + persistent_frame + + +
+ + diff --git a/src/persistent_frame.ts b/src/persistent_frame.ts new file mode 100644 index 000000000..18d26945e --- /dev/null +++ b/src/persistent_frame.ts @@ -0,0 +1,44 @@ +// persistent_frame.ts +const WAKE_UP_INTERVAL = 2000; +const RUNNER_RATE = 496.75; +let waitState = 0; +let lastNow = 0; +if (typeof frameElement === "object" && frameElement) { + const cNode = document.createComment("0"); + let cVal = 0; + /** + * scheduler 用于 Service Worker 或 Event Page, Chrome 94+, Firefox 142+ + */ + //@ts-ignore + const scheduler_ = typeof scheduler !== "undefined" && typeof scheduler?.postTask === "function" ? scheduler : null; + const runner = (ts: number) => { + waitState = 1; + cVal = cVal > 8 ? 1 : cVal + 1; + cNode.data = `${cVal}`; + const now = ts; + if (now - lastNow > WAKE_UP_INTERVAL) { + lastNow = now; + chrome.storage.session.set({ persistentWakeup: `${now}` }); + document.title = `wakup at ${now}`; // debug + } + }; + window.addEventListener("message", (ev) => { + if (waitState === 2) { + if (typeof ev.data === "object" && ev.data?.myCustomAction === "waked-up") { + if (scheduler_) { + scheduler_.postTask(() => runner(Date.now()), { priority: "background", delay: RUNNER_RATE }); + } else { + runner(ev.timeStamp); + } + } + } + }); + const mutObserver = new MutationObserver(() => { + if (waitState === 1) { + waitState = 2; + window?.postMessage({ myCustomAction: "waked-up" }, "*"); + } + }); + mutObserver.observe(cNode, { characterData: true }); + runner(0); +} diff --git a/src/pkg/utils/persistent.ts b/src/pkg/utils/persistent.ts new file mode 100644 index 000000000..e6066b408 --- /dev/null +++ b/src/pkg/utils/persistent.ts @@ -0,0 +1,13 @@ +export const keepEventPageRunning = () => { + if (typeof frames !== "object") return; + if (typeof document === "undefined") return; + if (typeof document.documentElement === "undefined") return; + if (document.getElementById("persistent_frame")) return; + chrome.storage.session.onChanged.addListener((obj) => { + typeof obj.persistentWakeup !== "undefined"; + }); + const iframe = document.createElement("iframe"); + iframe.id = "persistent_frame"; + iframe.src = chrome.runtime.getURL("/src/persistent_frame.html"); + document.documentElement.appendChild(iframe); +}; diff --git a/src/service_worker.ts b/src/service_worker.ts index 407a27922..3e465b26c 100644 --- a/src/service_worker.ts +++ b/src/service_worker.ts @@ -8,9 +8,11 @@ import { MessageQueue } from "@Packages/message/message_queue"; import { ServiceWorkerMessageSend } from "@Packages/message/window_message"; import migrate, { migrateChromeStorage } from "./app/migrate"; import { cleanInvalidKeys } from "./app/repo/resource"; +import { keepEventPageRunning } from "@App/pkg/utils/persistent"; migrate(); migrateChromeStorage(); +keepEventPageRunning(); const OFFSCREEN_DOCUMENT_PATH = "src/offscreen.html";