mirror of
https://github.com/joeseesun/wechat-radar.git
synced 2026-09-10 22:38:29 +09:00
Initial open source release
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
import { NextRequest } from 'next/server';
|
||||
import { wxSessions } from '@/lib/wx';
|
||||
import { syncFullHistory } from '@/lib/stats-aggregator';
|
||||
import { normalizeDate, normalizeRangeKey, rangeToWindow, type RangeKey } from '@/lib/range';
|
||||
import { readConfig } from '@/lib/config';
|
||||
import { cache, CK } from '@/lib/cache';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
export const maxDuration = 1800; // 30 min
|
||||
|
||||
interface RescanBody {
|
||||
range?: RangeKey;
|
||||
anchorDate?: string;
|
||||
since?: string;
|
||||
until?: string;
|
||||
full?: boolean; // 一键全量:1 年
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const body = (await req.json().catch(() => ({}))) as RescanBody;
|
||||
|
||||
let since: string;
|
||||
let until: string;
|
||||
let scope: string;
|
||||
|
||||
if (body.full) {
|
||||
const w = rangeToWindow('year');
|
||||
since = w.since;
|
||||
until = w.until;
|
||||
scope = 'full(365d)';
|
||||
} else if (body.since && body.until) {
|
||||
since = body.since;
|
||||
until = body.until;
|
||||
scope = `custom(${since}~${until})`;
|
||||
} else {
|
||||
const range = normalizeRangeKey(body.range, 'month');
|
||||
const w = rangeToWindow(range, normalizeDate(body.anchorDate));
|
||||
since = w.since;
|
||||
until = w.until;
|
||||
scope = range;
|
||||
}
|
||||
|
||||
const sessions = await wxSessions(500);
|
||||
const targets = sessions
|
||||
.filter((s) => s.is_group)
|
||||
.map((s) => ({ chatroomId: s.username, display: s.chat }));
|
||||
|
||||
const cfg = readConfig();
|
||||
const concurrency = cfg.rescanConcurrency ?? 6;
|
||||
|
||||
const stream = new ReadableStream({
|
||||
async start(controller) {
|
||||
const enc = new TextEncoder();
|
||||
const send = (obj: unknown) =>
|
||||
controller.enqueue(enc.encode(`data: ${JSON.stringify(obj)}\n\n`));
|
||||
|
||||
send({ type: 'start', scope, since, until, groups: targets.length });
|
||||
|
||||
try {
|
||||
const result = await syncFullHistory({
|
||||
targets,
|
||||
since,
|
||||
until,
|
||||
concurrency,
|
||||
onProgress: (p) => send(p),
|
||||
});
|
||||
cache.del(CK.sessions());
|
||||
send({
|
||||
type: 'finished',
|
||||
ok: result.ok,
|
||||
failed: result.failed,
|
||||
messages: result.messages,
|
||||
});
|
||||
} catch (e) {
|
||||
send({ type: 'error', error: e instanceof Error ? e.message : 'unknown' });
|
||||
} finally {
|
||||
controller.close();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return new Response(stream, {
|
||||
headers: {
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-cache, no-transform',
|
||||
Connection: 'keep-alive',
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user