74 lines
2.4 KiB
JavaScript
74 lines
2.4 KiB
JavaScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { createHash } from "node:crypto";
|
|
//#region extensions/feishu/src/dedup-migrations.ts
|
|
const DEDUP_TTL_MS = 1440 * 60 * 1e3;
|
|
const STORE_MAX_ENTRIES = 1e4;
|
|
function safeNamespaceFromFileName(fileName) {
|
|
if (!fileName.endsWith(".json")) return null;
|
|
const namespace = fileName.slice(0, -5).trim();
|
|
return namespace ? namespace : null;
|
|
}
|
|
function readLegacyDedupeData(filePath) {
|
|
try {
|
|
const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
const out = {};
|
|
for (const [messageId, seenAt] of Object.entries(parsed)) if (typeof seenAt === "number" && Number.isFinite(seenAt) && seenAt > 0) out[messageId] = seenAt;
|
|
return out;
|
|
} catch {
|
|
return {};
|
|
}
|
|
}
|
|
function dedupeStoreKey(namespace, messageId) {
|
|
return createHash("sha256").update(`${namespace}\0${messageId}`, "utf8").digest("hex").slice(0, 32);
|
|
}
|
|
function remainingTtlMs(seenAt, now) {
|
|
return Math.max(1, DEDUP_TTL_MS - (now - seenAt));
|
|
}
|
|
function buildMigrationEntries(namespace, sourcePath, now) {
|
|
return Object.entries(readLegacyDedupeData(sourcePath)).flatMap(([messageId, seenAt]) => {
|
|
if (now - seenAt >= DEDUP_TTL_MS) return [];
|
|
return [{
|
|
key: dedupeStoreKey(namespace, messageId),
|
|
value: {
|
|
namespace,
|
|
messageId,
|
|
seenAt
|
|
},
|
|
ttlMs: remainingTtlMs(seenAt, now)
|
|
}];
|
|
});
|
|
}
|
|
const detectFeishuLegacyStateMigrations = ({ stateDir }) => {
|
|
const dedupDir = path.join(stateDir, "feishu", "dedup");
|
|
let entries;
|
|
try {
|
|
entries = fs.readdirSync(dedupDir, { withFileTypes: true });
|
|
} catch {
|
|
return [];
|
|
}
|
|
const now = Date.now();
|
|
return entries.flatMap((entry) => {
|
|
if (!entry.isFile()) return [];
|
|
const namespace = safeNamespaceFromFileName(entry.name);
|
|
if (!namespace) return [];
|
|
const sourcePath = path.join(dedupDir, entry.name);
|
|
if (buildMigrationEntries(namespace, sourcePath, now).length === 0) return [];
|
|
return [{
|
|
kind: "plugin-state-import",
|
|
label: `Feishu ${namespace} dedupe`,
|
|
sourcePath,
|
|
targetPath: `plugin state:dedup.${namespace}`,
|
|
pluginId: "feishu",
|
|
namespace: `dedup.${namespace}`,
|
|
maxEntries: STORE_MAX_ENTRIES,
|
|
scopeKey: "",
|
|
cleanupSource: "rename",
|
|
readEntries: () => buildMigrationEntries(namespace, sourcePath, now)
|
|
}];
|
|
});
|
|
};
|
|
//#endregion
|
|
export { detectFeishuLegacyStateMigrations };
|