Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/app/service/service_worker/gm_api/gm_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import { headerModifierMap, headersReceivedMap } from "./gm_xhr";
import { BgGMXhr } from "@App/pkg/utils/xhr/bg_gm_xhr";
import { mightPrepareSetClipboard, setClipboard } from "../clipboard";
import { nativePageWindowOpen } from "../../offscreen/gm_api";
import { WakeUpCommand, wakeupPingCommand } from "@App/pkg/utils/wakeup-ping";

let generatedUniqueMarkerIDs = "";
let generatedUniqueMarkerIDWhen = "";
Expand Down Expand Up @@ -799,11 +800,27 @@ export default class GMApi {
if (!sender.isType(GetSenderType.CONNECT)) {
throw new Error("GM_xmlhttpRequest ERROR: sender is not MessageConnect");
}

// https://github.com/scriptscat/scriptcat/issues/1343
let wakeupTrigger = true;
wakeupPingCommand(WakeUpCommand.START);
const wakeupStop = () => {
try {
if (wakeupTrigger) {
wakeupTrigger = false;
wakeupPingCommand(WakeUpCommand.STOP);
}
} catch {
// ignored
}
};

const msgConn = sender.getConnect()!;

let isConnDisconnected = false;
msgConn.onDisconnect(() => {
isConnDisconnected = true;
wakeupStop();
});

// 关联自己生成的请求id与chrome.webRequest的请求id
Expand Down Expand Up @@ -854,6 +871,7 @@ export default class GMApi {
useFetch = isFetch || !!redirect || anonymous || isBufferStream;
}
const loadendCleanUp = () => {
wakeupStop();
redirectedUrls.delete(markerID);
nwErrorResults.delete(markerID);
const reqId = scXhrRequests.get(markerID);
Expand Down Expand Up @@ -905,6 +923,7 @@ export default class GMApi {
msgConn.onDisconnect(offscreenCon.disconnect.bind(offscreenCon));
}
} catch (e: any) {
wakeupStop();
const errorMsg = `GM_xmlhttpRequest ERROR: ${e?.message || e || "Unknown Error"}`;
if (!isConnDisconnected) {
msgConn.sendMessage({
Expand Down
2 changes: 2 additions & 0 deletions src/offscreen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import LoggerCore from "./app/logger/core";
import MessageWriter from "./app/logger/message_writer";
import { OffscreenManager } from "./app/service/offscreen";
import { ServiceWorkerClientMessage } from "@Packages/message/window_message";
import { initializeWakeupPing } from "./pkg/utils/wakeup-ping";

function main() {
// 通过postMessage与SW通信,支持结构化克隆(Blob等)
Expand All @@ -15,6 +16,7 @@ function main() {
// 初始化管理器
const manager = new OffscreenManager(swPostMessage);
manager.initManager();
initializeWakeupPing();
}

main();
90 changes: 90 additions & 0 deletions src/pkg/utils/wakeup-ping.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const PING_INTERVAL_MS_1 = 13_225;
const PING_INTERVAL_MS_2 = 17_765;

export const WakeUpCommand = {
START: 0x100,
STOP: 0x200,
} as const;

export type WakeUpCommand = ValueOf<typeof WakeUpCommand>;

/**
* scheduler 用于后台排程:Chrome 94+, Firefox 142+
* @link https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/postTask
*/
const nativeScheduler =
//@ts-ignore
typeof scheduler !== "undefined" && typeof scheduler?.postTask === "function" && scheduler;

// 高效的 BroadcastChannel 通讯:service worker 和 offscreen 共用同一通道
const channel = new BroadcastChannel("custom-ping"); // offscreen -> sw
const channelCommand = new BroadcastChannel("custom-ping-command"); // sw -> offscreen
let startCounter = 0;

// initializeWakeupPing only execute once in offscreen
export const initializeWakeupPing = () => {
if (typeof frameElement === "object" && typeof document === "object" && document) {
let counter = 0;
let isMutationPending = false;

const pingNode = document.createComment("0");

const incrementCounter = () => {
if (startCounter >= 1 && !isMutationPending) {
isMutationPending = true;
counter = counter & 8 ? 1 : counter + 1;
pingNode.data = `${counter}`;
}
};

const pingTask = async () => {
channel.postMessage(true);
incrementCounter();
};

const mutationObserver = new MutationObserver(() => {
if (isMutationPending) {
isMutationPending = false;
const pingIntervalMs = Math.random() * (PING_INTERVAL_MS_2 - PING_INTERVAL_MS_1) + PING_INTERVAL_MS_1;
if (nativeScheduler) {
nativeScheduler.postTask(pingTask, { priority: "background", delay: pingIntervalMs });
} else {
setTimeout(pingTask, pingIntervalMs);
}
}
});
mutationObserver.observe(pingNode, { characterData: true });
// incrementCounter();

channelCommand.onmessage = (e) => {
if (e.data === WakeUpCommand.START) {
startCounter++;
if (startCounter === 1) {
incrementCounter();
}
} else if (e.data === WakeUpCommand.STOP) {
if (startCounter > 0) startCounter--;
}
};
}
};

// initializeWakeupPing only execute once in service worker
export const listenWakeupPing = (onWakeupPing: (...args: any) => any) => {
chrome.storage.session.onChanged.addListener((obj) => {
// 消耗 persistentWakeup
if (typeof obj.persistentWakeup !== "undefined") {
// 执行任意 callback
onWakeupPing();
}
});
channel.onmessage = (e) => {
// 触发 chrome storage onChanged 使 service worker 保持活跃
chrome.storage.session.set({ persistentWakeup: `${e.timeStamp}` });
};
};

// wakeupPingCommand only execute in service worker
export const wakeupPingCommand = (command: WakeUpCommand) => {
channelCommand.postMessage(command);
};
7 changes: 7 additions & 0 deletions src/service_worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ 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 { listenWakeupPing } from "./pkg/utils/wakeup-ping";

migrate();
migrateChromeStorage();
Expand Down Expand Up @@ -59,6 +60,11 @@ async function setupOffscreenDocument() {
}
}

export const onWakeupPing = () => {
//@ts-ignore
self.lastWakeupPing = new Date().toLocaleString("zh"); // 僅在後台DevTools debug用
};

function main() {
cleanInvalidKeys();
// 初始化管理器
Expand All @@ -77,6 +83,7 @@ function main() {
manager.initManager();
// 初始化沙盒环境
setupOffscreenDocument();
listenWakeupPing(onWakeupPing);
}

main();
Loading