brain backup 2026-09-14
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import { mkdir, open, readFile, writeFile } from 'node:fs/promises';
|
||||
import { dirname } from 'node:path';
|
||||
|
||||
export type BridgeState = {
|
||||
cursors: Record<string, string>;
|
||||
processedMessages: Record<string, { repliedNodeId: string; at: string }>;
|
||||
};
|
||||
|
||||
const EMPTY_STATE: BridgeState = { cursors: {}, processedMessages: {} };
|
||||
|
||||
export class StateStore {
|
||||
private state: BridgeState = structuredClone(EMPTY_STATE);
|
||||
constructor(private readonly path: string) {}
|
||||
|
||||
async load(): Promise<void> {
|
||||
await mkdir(dirname(this.path), { recursive: true, mode: 0o700 });
|
||||
try {
|
||||
const text = await readFile(this.path, 'utf8');
|
||||
this.state = { ...structuredClone(EMPTY_STATE), ...JSON.parse(text) };
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
|
||||
await this.save();
|
||||
}
|
||||
}
|
||||
|
||||
getCursor(key: string): string {
|
||||
return this.state.cursors[key] ?? '0';
|
||||
}
|
||||
|
||||
async setCursor(key: string, cursor: string): Promise<void> {
|
||||
this.state.cursors[key] = cursor;
|
||||
await this.save();
|
||||
}
|
||||
|
||||
hasProcessed(messageId: string): boolean {
|
||||
return Boolean(this.state.processedMessages[messageId]);
|
||||
}
|
||||
|
||||
async markProcessed(messageId: string, repliedNodeId: string): Promise<void> {
|
||||
this.state.processedMessages[messageId] = { repliedNodeId, at: new Date().toISOString() };
|
||||
await this.save();
|
||||
}
|
||||
|
||||
private async save(): Promise<void> {
|
||||
const handle = await open(this.path, 'w', 0o600);
|
||||
try {
|
||||
await handle.writeFile(`${JSON.stringify(this.state, null, 2)}\n`, 'utf8');
|
||||
await handle.chmod(0o600);
|
||||
} finally {
|
||||
await handle.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user