66 lines
2.2 KiB
JavaScript
66 lines
2.2 KiB
JavaScript
"use strict";
|
||
/* ================= SQLite(node:sqlite 内置驱动,零依赖) ================= */
|
||
const { DatabaseSync } = require("node:sqlite");
|
||
const path = require("node:path");
|
||
const fs = require("node:fs");
|
||
const { expandHome } = require("./env");
|
||
|
||
/* 数据目录不放源码树:默认 ~/.starraid,可用 DATA_DIR 环境变量 / .env 覆盖 */
|
||
const DATA_DIR = expandHome(process.env.DATA_DIR || path.join(require("node:os").homedir(), ".starraid"));
|
||
fs.mkdirSync(DATA_DIR, { recursive: true });
|
||
|
||
const db = new DatabaseSync(path.join(DATA_DIR, "starraid.db"));
|
||
db.exec("PRAGMA journal_mode=WAL;");
|
||
db.exec("PRAGMA foreign_keys=ON;");
|
||
|
||
db.exec(`
|
||
CREATE TABLE IF NOT EXISTS users(
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
username TEXT NOT NULL UNIQUE COLLATE NOCASE,
|
||
email TEXT NOT NULL UNIQUE COLLATE NOCASE,
|
||
pass_hash TEXT NOT NULL,
|
||
created_at INTEGER NOT NULL
|
||
);
|
||
CREATE TABLE IF NOT EXISTS sessions(
|
||
token TEXT PRIMARY KEY,
|
||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||
created_at INTEGER NOT NULL,
|
||
expires_at INTEGER NOT NULL
|
||
);
|
||
CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_id);
|
||
CREATE TABLE IF NOT EXISTS user_stats(
|
||
user_id INTEGER PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
|
||
boss_kills INTEGER NOT NULL DEFAULT 0,
|
||
endless_high INTEGER NOT NULL DEFAULT 0,
|
||
runs INTEGER NOT NULL DEFAULT 0,
|
||
updated_at INTEGER NOT NULL DEFAULT 0
|
||
);
|
||
CREATE TABLE IF NOT EXISTS codex_unlocks(
|
||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||
entry_key TEXT NOT NULL,
|
||
unlocked_at INTEGER NOT NULL,
|
||
PRIMARY KEY(user_id, entry_key)
|
||
);
|
||
CREATE TABLE IF NOT EXISTS runs(
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||
mode TEXT NOT NULL,
|
||
diff INTEGER NOT NULL,
|
||
score INTEGER NOT NULL,
|
||
wave INTEGER NOT NULL,
|
||
stage INTEGER NOT NULL,
|
||
time_sec INTEGER NOT NULL,
|
||
boss_kills INTEGER NOT NULL,
|
||
win INTEGER NOT NULL,
|
||
created_at INTEGER NOT NULL
|
||
);
|
||
CREATE INDEX IF NOT EXISTS idx_runs_user ON runs(user_id);
|
||
`);
|
||
|
||
/* 定期清理过期 session */
|
||
setInterval(() => {
|
||
try { db.prepare("DELETE FROM sessions WHERE expires_at<?").run(Date.now()); } catch (e) { /* 忽略 */ }
|
||
}, 3600000).unref();
|
||
|
||
module.exports = db;
|