插件
This commit is contained in:
+144
@@ -0,0 +1,144 @@
|
||||
// background.js — Service Worker:推送队列 worker + 本地数据汇聚(双写)
|
||||
// 以 chrome.storage 为本地汇聚权威源(MV3 的 SW 会被休眠,内存变量不可靠);
|
||||
// 同时通过 alarms + IndexedDB 队列把数据推送到后端 ingest 端点。
|
||||
import { addItem, getStats } from './push/queue.js';
|
||||
import { processQueue } from './push/worker.js';
|
||||
import { loadConfig, saveConfig } from './push/config.js';
|
||||
|
||||
// ===== 本地数据汇聚(保留,供插件本地导出)=====
|
||||
const BG_KEY = 'alibaba_bg_details';
|
||||
|
||||
async function loadMeta() {
|
||||
const data = await chrome.storage.local.get(BG_KEY);
|
||||
return data[BG_KEY] || { dedup: true, customerIdMap: {}, detailData: [] };
|
||||
}
|
||||
|
||||
async function saveMeta(meta) {
|
||||
await chrome.storage.local.set({ [BG_KEY]: meta });
|
||||
}
|
||||
|
||||
// ===== 推送配置 + alarms =====
|
||||
const ALARM = 'push-tick';
|
||||
|
||||
async function refresh() {
|
||||
try {
|
||||
const cfg = await loadConfig();
|
||||
if (cfg.enabled) {
|
||||
await chrome.alarms.create(ALARM, { periodInMinutes: 1 });
|
||||
processQueue();
|
||||
} else {
|
||||
await chrome.alarms.clear(ALARM);
|
||||
}
|
||||
} catch (e) {
|
||||
// 配置/alarms 失败不应阻断 SW 启动
|
||||
console.error('[bg] refresh error:', e);
|
||||
}
|
||||
}
|
||||
|
||||
chrome.runtime.onInstalled.addListener(refresh);
|
||||
chrome.runtime.onStartup.addListener(refresh);
|
||||
chrome.alarms.onAlarm.addListener(a => {
|
||||
if (a && a.name === ALARM) processQueue();
|
||||
});
|
||||
|
||||
// ===== 消息处理 =====
|
||||
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
// --- 推送相关 ---
|
||||
if (msg.type === 'enqueue') {
|
||||
(async () => {
|
||||
try {
|
||||
const cfg = await loadConfig();
|
||||
if (!cfg.enabled) { sendResponse({ ok: false, reason: 'disabled' }); return; }
|
||||
const inquiryId = msg.record && msg.record.inquiryId;
|
||||
const id = await addItem({
|
||||
payload: { record: msg.record, messages: msg.messages || [] },
|
||||
inquiryId,
|
||||
});
|
||||
sendResponse({ ok: true, id });
|
||||
processQueue();
|
||||
} catch (e) {
|
||||
sendResponse({ ok: false, error: String((e && e.message) || e) });
|
||||
}
|
||||
})();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (msg.type === 'getPushStats') {
|
||||
(async () => {
|
||||
try { sendResponse({ ok: true, stats: await getStats() }); }
|
||||
catch (e) { sendResponse({ ok: false, error: String((e && e.message) || e) }); }
|
||||
})();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (msg.type === 'getPushConfig') {
|
||||
(async () => {
|
||||
try { sendResponse({ ok: true, config: await loadConfig() }); }
|
||||
catch (e) { sendResponse({ ok: false, error: String((e && e.message) || e) }); }
|
||||
})();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (msg.type === 'setPushConfig') {
|
||||
(async () => {
|
||||
try {
|
||||
await saveConfig(msg.config || {});
|
||||
await refresh();
|
||||
sendResponse({ ok: true });
|
||||
} catch (e) {
|
||||
sendResponse({ ok: false, error: String((e && e.message) || e) });
|
||||
}
|
||||
})();
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- 本地数据汇聚(保留原逻辑,照搬) ---
|
||||
if (msg.type === 'storeDetail') {
|
||||
// 先读后写:SW 休眠唤醒后 DETAIL_STORE 会清空,必须从 storage 恢复再合并
|
||||
(async () => {
|
||||
try {
|
||||
const meta = await loadMeta();
|
||||
// 首条写入时锁定本次抓取的 dedup 策略
|
||||
const isEmpty = Object.keys(meta.customerIdMap).length === 0 && meta.detailData.length === 0;
|
||||
if (isEmpty) meta.dedup = !!msg.dedup;
|
||||
|
||||
if (meta.dedup && msg.customerId) {
|
||||
// 按 customerId 去重,保留 createTime 更新的那条
|
||||
const existing = meta.customerIdMap[msg.customerId];
|
||||
if (!existing || (msg.createTime || '') >= (existing.createTime || '')) {
|
||||
meta.customerIdMap[msg.customerId] = msg.record;
|
||||
}
|
||||
} else {
|
||||
// 无 customerId 或非去重模式:直接追加
|
||||
meta.detailData.push(msg.record);
|
||||
}
|
||||
meta.lastUpdate = Date.now();
|
||||
await saveMeta(meta);
|
||||
sendResponse({ ok: true });
|
||||
} catch (e) {
|
||||
sendResponse({ ok: false, error: String(e && e.message || e) });
|
||||
}
|
||||
})();
|
||||
return true; // 保持消息通道,等待异步 sendResponse
|
||||
}
|
||||
|
||||
if (msg.type === 'clearBgData') {
|
||||
(async () => {
|
||||
await chrome.storage.local.remove(BG_KEY);
|
||||
sendResponse({ ok: true });
|
||||
})();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (msg.type === 'getBgData') {
|
||||
(async () => {
|
||||
const meta = await loadMeta();
|
||||
// 合并两份数据源,避免去重模式下无 customerId 的记录被丢弃
|
||||
const records = meta.dedup
|
||||
? [...Object.values(meta.customerIdMap), ...meta.detailData]
|
||||
: meta.detailData;
|
||||
sendResponse({ records, dedup: meta.dedup });
|
||||
})();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user