python migration
This commit is contained in:
+181
@@ -0,0 +1,181 @@
|
||||
import json
|
||||
import os
|
||||
import sqlite3
|
||||
import threading
|
||||
from contextlib import contextmanager
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
DB_PATH = os.path.join(BASE_DIR, "dashboard.db")
|
||||
CONFIG_JSON = os.path.join(BASE_DIR, "config.json")
|
||||
|
||||
_conn = sqlite3.connect(DB_PATH, check_same_thread=False)
|
||||
_conn.row_factory = sqlite3.Row
|
||||
_lock = threading.RLock()
|
||||
|
||||
|
||||
@contextmanager
|
||||
def _tx():
|
||||
with _lock:
|
||||
try:
|
||||
yield
|
||||
_conn.commit()
|
||||
except Exception:
|
||||
_conn.rollback()
|
||||
raise
|
||||
|
||||
|
||||
def _init_db():
|
||||
with _tx():
|
||||
_conn.execute("PRAGMA journal_mode=WAL;")
|
||||
_conn.executescript(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS config (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tests (
|
||||
id TEXT PRIMARY KEY,
|
||||
test_id TEXT,
|
||||
parent_dir TEXT,
|
||||
filename TEXT,
|
||||
interference TEXT,
|
||||
device TEXT,
|
||||
rotation TEXT,
|
||||
test_point TEXT,
|
||||
station TEXT,
|
||||
band TEXT,
|
||||
channel TEXT,
|
||||
bandwidth TEXT,
|
||||
rssi TEXT,
|
||||
direction TEXT,
|
||||
completed INTEGER NOT NULL DEFAULT 0,
|
||||
completed_at TEXT,
|
||||
duration_seconds REAL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_tests_test_id ON tests (test_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_tests_device ON tests (device);
|
||||
"""
|
||||
)
|
||||
|
||||
for col_def in [
|
||||
"tput_mbps REAL",
|
||||
"dl_rssi_dbm REAL",
|
||||
"ul_rssi_dbm REAL",
|
||||
"tput_results TEXT",
|
||||
]:
|
||||
try:
|
||||
_conn.execute(f"ALTER TABLE tests ADD COLUMN {col_def}")
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
|
||||
|
||||
def get_config(key):
|
||||
with _lock:
|
||||
row = _conn.execute("SELECT value FROM config WHERE key = ?", (key,)).fetchone()
|
||||
return row["value"] if row else None
|
||||
|
||||
|
||||
def set_config(key, value):
|
||||
with _tx():
|
||||
_conn.execute(
|
||||
"INSERT OR REPLACE INTO config (key, value) VALUES (?, ?)",
|
||||
(key, value),
|
||||
)
|
||||
|
||||
|
||||
def del_config(key):
|
||||
with _tx():
|
||||
_conn.execute("DELETE FROM config WHERE key = ?", (key,))
|
||||
|
||||
|
||||
def upsert_test(test):
|
||||
with _tx():
|
||||
_conn.execute(
|
||||
"""
|
||||
INSERT INTO tests
|
||||
(id, test_id, parent_dir, filename, interference, device, rotation,
|
||||
test_point, station, band, channel, bandwidth, rssi, direction)
|
||||
VALUES
|
||||
(:id, :test_id, :parent_dir, :filename, :interference, :device, :rotation,
|
||||
:test_point, :station, :band, :channel, :bandwidth, :rssi, :direction)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
test_id = excluded.test_id,
|
||||
parent_dir = excluded.parent_dir,
|
||||
filename = excluded.filename,
|
||||
interference = excluded.interference,
|
||||
device = excluded.device,
|
||||
rotation = excluded.rotation,
|
||||
test_point = excluded.test_point,
|
||||
station = excluded.station,
|
||||
band = excluded.band,
|
||||
channel = excluded.channel,
|
||||
bandwidth = excluded.bandwidth,
|
||||
rssi = excluded.rssi,
|
||||
direction = excluded.direction
|
||||
""",
|
||||
test,
|
||||
)
|
||||
|
||||
|
||||
def mark_completed(test_id, device, completed_at, duration_seconds, tput_results=None):
|
||||
json_value = json.dumps(tput_results) if tput_results else None
|
||||
with _tx():
|
||||
_conn.execute(
|
||||
"""
|
||||
UPDATE tests
|
||||
SET completed = 1,
|
||||
completed_at = ?,
|
||||
duration_seconds = ?,
|
||||
tput_results = ?
|
||||
WHERE test_id = ?
|
||||
AND (? IS NULL OR device = ?)
|
||||
""",
|
||||
(completed_at, duration_seconds, json_value, test_id, device, device),
|
||||
)
|
||||
|
||||
|
||||
def get_station_for_test(test_id, device):
|
||||
with _lock:
|
||||
row = _conn.execute(
|
||||
"SELECT station FROM tests WHERE test_id = ? AND device = ? LIMIT 1",
|
||||
(test_id, device),
|
||||
).fetchone()
|
||||
return row["station"] if row else None
|
||||
|
||||
|
||||
def reset_by_file_id_and_device(test_id, device):
|
||||
with _tx():
|
||||
_conn.execute(
|
||||
"""
|
||||
UPDATE tests
|
||||
SET completed = 0,
|
||||
completed_at = NULL,
|
||||
duration_seconds = NULL,
|
||||
tput_results = NULL
|
||||
WHERE test_id = ?
|
||||
AND (? IS NULL OR device = ?)
|
||||
""",
|
||||
(test_id, device, device),
|
||||
)
|
||||
|
||||
|
||||
def clear_tests():
|
||||
with _tx():
|
||||
_conn.execute("DELETE FROM tests")
|
||||
|
||||
|
||||
def get_all_tests():
|
||||
with _lock:
|
||||
rows = _conn.execute("SELECT * FROM tests").fetchall()
|
||||
return [dict(row) for row in rows]
|
||||
|
||||
|
||||
def count_tests():
|
||||
with _lock:
|
||||
row = _conn.execute("SELECT COUNT(*) AS n FROM tests").fetchone()
|
||||
return row["n"]
|
||||
|
||||
|
||||
_init_db()
|
||||
Reference in New Issue
Block a user