Add monitoring service and database schema
- 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.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
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";
|
||||
@@ -9,6 +11,13 @@ type PublisherRequestMessage = {
|
||||
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;
|
||||
@@ -19,26 +28,95 @@ type BackgroundErrorResponse = {
|
||||
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() {
|
||||
window.addEventListener("message", async (event: MessageEvent<PublisherRequestMessage>) => {
|
||||
if (event.source !== window || !event.data || event.data.type !== "geo.publisher.request") {
|
||||
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, payload } = event.data;
|
||||
const { requestId, action } = event.data;
|
||||
const payload = "payload" in event.data ? event.data.payload : undefined;
|
||||
|
||||
try {
|
||||
const response = await browser.runtime.sendMessage({
|
||||
type: "geo.publisher.request",
|
||||
type: event.data.type,
|
||||
action,
|
||||
payload,
|
||||
});
|
||||
@@ -59,7 +137,7 @@ export default defineContentScript({
|
||||
window.postMessage(
|
||||
{
|
||||
source: "geo-extension",
|
||||
type: "geo.publisher.response",
|
||||
type: event.data.type === "geo.publisher.request" ? "geo.publisher.response" : "geo.monitoring.response",
|
||||
requestId,
|
||||
success: true,
|
||||
data,
|
||||
@@ -70,7 +148,7 @@ export default defineContentScript({
|
||||
window.postMessage(
|
||||
{
|
||||
source: "geo-extension",
|
||||
type: "geo.publisher.response",
|
||||
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",
|
||||
|
||||
Reference in New Issue
Block a user