Files

53 lines
2.1 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { appendFileSync, existsSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { DatabaseSync } from "node:sqlite";
import type { ChildProcess } from "node:child_process";
import { sleep } from "./study.ts";
// 账本里没有时间戳,墙钟时间由检验自己记:研究进程跑着的时候每隔一会儿看一眼账本,
// 新出现的每条记录记下"第一次看到它的时刻",写成 timeline.jsonl(每行 {seq, kind, at},at 是毫秒)。
// 只读打开账本、只查序号和种类,不经 Ledger.records()(那会每次重读、重查全部内容)。
// 时刻比真实写入晚最多一个间隔,用来算阶段级的墙钟足够。
const POLL_MS = 1000;
export interface TimelineRow {
seq: number;
kind: string;
at: number;
}
/** 已经记下的最大序号;文件还没有就是 0。接着跑时往同一个文件后面追加。 */
function lastSeq(file: string): number {
if (!existsSync(file)) return 0;
return readTimeline(file).reduce((m, r) => Math.max(m, r.seq), 0);
}
/** 研究进程退出前一直记;进程退出后再看最后一眼。调用前要先等 waitForLedger(表建好了才能读)。 */
export async function watchTimeline(studyDir: string, child: ChildProcess, file: string): Promise<void> {
let seen = lastSeq(file);
const look = () => {
const db = new DatabaseSync(join(studyDir, "ledger.sqlite"), { readOnly: true });
try {
const rows = db.prepare("SELECT seq, kind FROM records WHERE seq > ? ORDER BY seq").all(seen) as Array<{ seq: number; kind: string }>;
const at = Date.now();
for (const r of rows) appendFileSync(file, `${JSON.stringify({ seq: r.seq, kind: r.kind, at })}\n`);
if (rows.length > 0) seen = rows.at(-1)!.seq;
} finally {
db.close();
}
};
while (child.exitCode === null && child.signalCode === null) {
look();
await sleep(POLL_MS);
}
look();
}
export function readTimeline(file: string): TimelineRow[] {
return readFileSync(file, "utf8")
.split("\n")
.filter((l) => l !== "")
.map((l) => JSON.parse(l) as TimelineRow);
}