6066f43a7d
- Implement monitoring service with heartbeat, lease tasks, resume tasks, and task result handling. - Create monitoring time utilities for business date calculations. - Add unit tests for date window resolution and business day handling. - Define database schema for monitoring-related tables including quotas, daily reports, and task management. - Establish migration scripts for creating and dropping monitoring tables.
162 lines
4.7 KiB
TypeScript
162 lines
4.7 KiB
TypeScript
import { browser } from "wxt/browser";
|
|
import { defineContentScript } from "wxt/utils/define-content-script";
|
|
|
|
import { syncDoubaoMonitoringRuntimeStateFromPage } from "../src/monitoring-adapters/doubao-state";
|
|
|
|
type PublisherRequestMessage = {
|
|
source: "geo-admin";
|
|
type: "geo.publisher.request";
|
|
requestId: string;
|
|
action: "ping" | "detectPlatforms" | "registerInstallation" | "bindAccount" | "publishArticle";
|
|
payload?: unknown;
|
|
};
|
|
|
|
type MonitoringRequestMessage = {
|
|
source: "geo-admin";
|
|
type: "geo.monitoring.request";
|
|
requestId: string;
|
|
action: "ping" | "detectPlatforms" | "syncHeartbeat" | "runCycle" | "kickoffCycle" | "getState";
|
|
};
|
|
|
|
type BackgroundSuccessResponse = {
|
|
ok: true;
|
|
data: unknown;
|
|
};
|
|
|
|
type BackgroundErrorResponse = {
|
|
ok: false;
|
|
error?: string;
|
|
};
|
|
|
|
type RuntimeSyncMessage = {
|
|
type: "geo.monitoring.runtime.sync";
|
|
platform: "doubao";
|
|
};
|
|
|
|
function isExtensionContextInvalidatedError(error: unknown): boolean {
|
|
const message =
|
|
typeof error === "string"
|
|
? error
|
|
: typeof error === "object" && error !== null && "message" in error && typeof error.message === "string"
|
|
? error.message
|
|
: String(error ?? "");
|
|
|
|
const normalized = message.toLowerCase();
|
|
return normalized.includes("extension context invalidated") || normalized.includes("context invalidated");
|
|
}
|
|
|
|
function isBackgroundResponse(value: unknown): value is BackgroundSuccessResponse | BackgroundErrorResponse {
|
|
return typeof value === "object" && value !== null && "ok" in value;
|
|
}
|
|
|
|
function registerDoubaoRuntimeSync(): void {
|
|
const hostname = window.location.hostname;
|
|
if (hostname !== "doubao.com" && hostname !== "www.doubao.com" && !hostname.endsWith(".doubao.com")) {
|
|
return;
|
|
}
|
|
|
|
const sync = () => {
|
|
void syncDoubaoMonitoringRuntimeStateFromPage().catch((error) => {
|
|
if (isExtensionContextInvalidatedError(error)) {
|
|
return;
|
|
}
|
|
console.warn("[geo-monitoring] failed to sync doubao runtime state", error);
|
|
});
|
|
};
|
|
|
|
sync();
|
|
|
|
window.addEventListener("pageshow", sync);
|
|
document.addEventListener("visibilitychange", () => {
|
|
if (!document.hidden) {
|
|
sync();
|
|
}
|
|
});
|
|
window.setInterval(sync, 15000);
|
|
}
|
|
|
|
export default defineContentScript({
|
|
matches: ["http://*/*", "https://*/*"],
|
|
main() {
|
|
registerDoubaoRuntimeSync();
|
|
|
|
browser.runtime.onMessage.addListener((message: RuntimeSyncMessage, _sender, sendResponse) => {
|
|
if (!message || message.type !== "geo.monitoring.runtime.sync" || message.platform !== "doubao") {
|
|
return undefined;
|
|
}
|
|
|
|
void syncDoubaoMonitoringRuntimeStateFromPage()
|
|
.then(() => {
|
|
sendResponse({ ok: true });
|
|
})
|
|
.catch((error) => {
|
|
sendResponse({
|
|
ok: false,
|
|
error: error instanceof Error ? error.message : "monitoring_runtime_sync_failed",
|
|
});
|
|
});
|
|
|
|
return true;
|
|
});
|
|
|
|
window.addEventListener("message", async (event: MessageEvent<PublisherRequestMessage | MonitoringRequestMessage>) => {
|
|
if (
|
|
event.source !== window ||
|
|
!event.data ||
|
|
(event.data.type !== "geo.publisher.request" && event.data.type !== "geo.monitoring.request")
|
|
) {
|
|
return;
|
|
}
|
|
if (event.data.source !== "geo-admin") {
|
|
return;
|
|
}
|
|
|
|
const { requestId, action } = event.data;
|
|
const payload = "payload" in event.data ? event.data.payload : undefined;
|
|
|
|
try {
|
|
const response = await browser.runtime.sendMessage({
|
|
type: event.data.type,
|
|
action,
|
|
payload,
|
|
});
|
|
|
|
const data = isBackgroundResponse(response)
|
|
? (() => {
|
|
if (!response.ok) {
|
|
throw new Error(response.error || "publisher_plugin_unknown_error");
|
|
}
|
|
return response.data;
|
|
})()
|
|
: response;
|
|
|
|
if (typeof data === "undefined") {
|
|
throw new Error("publisher_plugin_empty_response");
|
|
}
|
|
|
|
window.postMessage(
|
|
{
|
|
source: "geo-extension",
|
|
type: event.data.type === "geo.publisher.request" ? "geo.publisher.response" : "geo.monitoring.response",
|
|
requestId,
|
|
success: true,
|
|
data,
|
|
},
|
|
window.location.origin,
|
|
);
|
|
} catch (error) {
|
|
window.postMessage(
|
|
{
|
|
source: "geo-extension",
|
|
type: event.data.type === "geo.publisher.request" ? "geo.publisher.response" : "geo.monitoring.response",
|
|
requestId,
|
|
success: false,
|
|
error: error instanceof Error ? error.message : "publisher_plugin_unknown_error",
|
|
},
|
|
window.location.origin,
|
|
);
|
|
}
|
|
});
|
|
},
|
|
});
|