File size: 3,690 Bytes
c481f8a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | const getActiveTab = () =>
new Promise((resolve) => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => resolve(tabs && tabs[0] ? tabs[0] : null));
});
const storageGet = (keys) =>
new Promise((resolve) => {
chrome.storage.local.get(keys, (items) => resolve(items || {}));
});
const storageSet = (items) =>
new Promise((resolve) => {
chrome.storage.local.set(items, () => resolve());
});
const sendToTab = (tabId, message) =>
new Promise((resolve, reject) => {
chrome.tabs.sendMessage(tabId, message, (resp) => {
const err = chrome.runtime.lastError;
if (err) {
reject(new Error(err.message));
return;
}
resolve(resp);
});
});
const badge = async (text) => {
try {
await chrome.action.setBadgeBackgroundColor({ color: "#2D7D46" });
await chrome.action.setBadgeText({ text: text || "" });
} catch (e) {}
};
const badgeError = async (text) => {
try {
await chrome.action.setBadgeBackgroundColor({ color: "#B42318" });
await chrome.action.setBadgeText({ text: text || "" });
} catch (e) {}
};
const normalizeBaseUrl = (url) => {
const u = String(url || "").trim();
if (!u) return "";
return u.endsWith("/") ? u.slice(0, -1) : u;
};
const extractTaskId = (text) => {
const t = String(text || "").trim();
if (!t) return "";
const m = t.match(/[0-9a-fA-F]{32}/);
return m ? m[0] : t;
};
const getOrPromptServiceUrl = async (tabId) => {
const items = await storageGet(["service_url"]);
const existing = normalizeBaseUrl(items.service_url);
if (existing) return existing;
const resp = await sendToTab(tabId, {
type: "PROMPT",
text: "Spider_XHS 服务地址(例如 http://localhost:8000)",
defaultValue: "http://localhost:8000",
});
const v = normalizeBaseUrl(resp && resp.value);
if (v) await storageSet({ service_url: v });
return v;
};
const getTaskId = async (tabId) => {
let clip = "";
try {
const resp = await sendToTab(tabId, { type: "READ_CLIPBOARD" });
clip = extractTaskId(resp && resp.text);
} catch (e) {}
if (clip) return clip;
const resp = await sendToTab(tabId, { type: "PROMPT", text: "task_id", defaultValue: "" });
return extractTaskId(resp && resp.value);
};
const collectPage = async (tabId) => {
const resp = await sendToTab(tabId, { type: "COLLECT_PAGE" });
return resp || {};
};
chrome.action.onClicked.addListener(async () => {
await badge("...");
try {
const tab = await getActiveTab();
const tabId = tab && tab.id;
if (!tabId) {
await badgeError("NO");
return;
}
const serviceUrl = await getOrPromptServiceUrl(tabId);
if (!serviceUrl) {
await badgeError("URL");
return;
}
const taskId = await getTaskId(tabId);
if (!taskId) {
await badgeError("ID");
return;
}
const page = await collectPage(tabId);
const url = String(page.url || "").trim();
const html = String(page.html || "");
const body = {
task_id: taskId,
raw: { url, html },
normalized: { url, kind: "page" },
meta: { source_engine: "extension_rpa", source_type: "page", source_ref: url, ingested_at: new Date().toISOString(), ok: true },
};
const endpoint = `${serviceUrl}/api/v1/import/extension`;
const resp = await fetch(endpoint, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
if (resp.ok) {
await badge("OK");
} else {
await badgeError(String(resp.status || "ERR"));
}
} catch (e) {
await badgeError("ERR");
} finally {
setTimeout(() => badge(""), 2000);
}
});
|