60 lines
1.8 KiB
TypeScript
60 lines
1.8 KiB
TypeScript
import { Database } from 'bun:sqlite';
|
|
import { mkdir } from 'node:fs/promises';
|
|
import { dirname } from 'node:path';
|
|
import { env } from './env.ts';
|
|
|
|
await mkdir(dirname(env.stateDbPath), { recursive: true });
|
|
const db = new Database(env.stateDbPath, { create: true });
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
user_id TEXT PRIMARY KEY,
|
|
created_at INTEGER NOT NULL,
|
|
provisioned_at INTEGER,
|
|
deleted_at INTEGER
|
|
);
|
|
CREATE TABLE IF NOT EXISTS activity (
|
|
user_id TEXT PRIMARY KEY,
|
|
last_used INTEGER NOT NULL
|
|
);
|
|
`);
|
|
|
|
const now = () => Date.now();
|
|
|
|
export const state = {
|
|
recordCreate: (userId: string): void => {
|
|
db.prepare(
|
|
`INSERT INTO users (user_id, created_at) VALUES (?, ?)
|
|
ON CONFLICT(user_id) DO UPDATE SET deleted_at = NULL`,
|
|
).run(userId, now());
|
|
},
|
|
|
|
markProvisioned: (userId: string): void => {
|
|
db.prepare(`UPDATE users SET provisioned_at = ? WHERE user_id = ?`).run(now(), userId);
|
|
},
|
|
|
|
markDeleted: (userId: string): void => {
|
|
db.prepare(`UPDATE users SET deleted_at = ? WHERE user_id = ?`).run(now(), userId);
|
|
db.prepare(`DELETE FROM activity WHERE user_id = ?`).run(userId);
|
|
},
|
|
|
|
touch: (userId: string): void => {
|
|
db.prepare(
|
|
`INSERT INTO activity (user_id, last_used) VALUES (?, ?)
|
|
ON CONFLICT(user_id) DO UPDATE SET last_used = excluded.last_used`,
|
|
).run(userId, now());
|
|
},
|
|
|
|
// 查找过期:最后使用时间距今 > timeoutMs
|
|
findIdle: (timeoutMs: number): string[] => {
|
|
const cutoff = now() - timeoutMs;
|
|
return db
|
|
.prepare(`SELECT user_id FROM activity WHERE last_used < ?`)
|
|
.all(cutoff)
|
|
.map((r: any) => r.user_id);
|
|
},
|
|
|
|
clearActivity: (userId: string): void => {
|
|
db.prepare(`DELETE FROM activity WHERE user_id = ?`).run(userId);
|
|
},
|
|
};
|