84 lines
2.9 KiB
Python
84 lines
2.9 KiB
Python
"""SQLite 数据层:连接短生命周期(每次操作新建),线程安全。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sqlite3
|
|
from pathlib import Path
|
|
|
|
DATA_DIR = Path(__file__).resolve().parent.parent / "data"
|
|
DB_PATH = DATA_DIR / "monitor.db"
|
|
|
|
SCHEMA = """
|
|
CREATE TABLE IF NOT EXISTS platforms (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL UNIQUE,
|
|
currency TEXT NOT NULL DEFAULT 'USD',
|
|
icon TEXT NOT NULL DEFAULT '',
|
|
method TEXT NOT NULL DEFAULT 'GET',
|
|
url TEXT NOT NULL,
|
|
headers TEXT NOT NULL DEFAULT '{}',
|
|
body TEXT NOT NULL DEFAULT '',
|
|
balance_path TEXT NOT NULL,
|
|
interval_seconds INTEGER,
|
|
retry_count INTEGER,
|
|
timeout_seconds INTEGER,
|
|
enabled INTEGER NOT NULL DEFAULT 1,
|
|
note TEXT NOT NULL DEFAULT '',
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime')),
|
|
updated_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime'))
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS accounts (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
platform_id INTEGER NOT NULL REFERENCES platforms(id) ON DELETE CASCADE,
|
|
name TEXT NOT NULL,
|
|
api_key TEXT NOT NULL,
|
|
threshold REAL NOT NULL DEFAULT 0,
|
|
enabled INTEGER NOT NULL DEFAULT 1,
|
|
alert_armed INTEGER NOT NULL DEFAULT 1,
|
|
last_balance REAL,
|
|
last_status TEXT NOT NULL DEFAULT 'pending',
|
|
last_error TEXT NOT NULL DEFAULT '',
|
|
last_check_at TEXT,
|
|
note TEXT NOT NULL DEFAULT '',
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime')),
|
|
updated_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime'))
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS balance_history (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
|
|
balance REAL NOT NULL,
|
|
checked_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime'))
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS alert_log (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
account_id INTEGER NOT NULL,
|
|
type TEXT NOT NULL,
|
|
message TEXT NOT NULL,
|
|
sent_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime'))
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_accounts_platform ON accounts(platform_id);
|
|
CREATE INDEX IF NOT EXISTS idx_history_account ON balance_history(account_id, id);
|
|
CREATE INDEX IF NOT EXISTS idx_alert_account ON alert_log(account_id);
|
|
"""
|
|
|
|
|
|
def get_conn() -> sqlite3.Connection:
|
|
conn = sqlite3.connect(DB_PATH, timeout=30)
|
|
conn.row_factory = sqlite3.Row
|
|
conn.execute("PRAGMA foreign_keys = ON")
|
|
return conn
|
|
|
|
|
|
def init_db() -> None:
|
|
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
with get_conn() as conn:
|
|
conn.executescript(SCHEMA)
|
|
|
|
|
|
def rows_to_dicts(rows: list[sqlite3.Row]) -> list[dict]:
|
|
return [dict(r) for r in rows]
|