diff --git a/docker-compose.yml b/docker-compose.yml index 2c2b42e..74dd8db 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,10 +7,12 @@ services: environment: - HOST_BROWSE_ROOT=${HOST_BROWSE_ROOT} - HOST_MOUNT_ROOT=/host + - DASHBOARD_DB_PATH=/app/data/dashboard.db volumes: - type: bind source: ./server target: /app + - db_data:/app/data - type: bind source: ${HOST_BROWSE_ROOT} target: /host @@ -37,3 +39,6 @@ services: - frontend restart: unless-stopped +volumes: + db_data: + diff --git a/server/app.py b/server/app.py index cdbe015..14cd59e 100644 --- a/server/app.py +++ b/server/app.py @@ -147,6 +147,8 @@ def _create_default_user_if_missing(username, password, role): def _ensure_default_users(): + if count_users() > 0: + print("[server] Users already exist, skipping default account seeding.") if count_users() == 0: print("[server] No users found. Seeding default accounts...") diff --git a/server/data/dashboard.db b/server/data/dashboard.db new file mode 100644 index 0000000..659e622 Binary files /dev/null and b/server/data/dashboard.db differ diff --git a/server/data/dashboard.db-shm b/server/data/dashboard.db-shm new file mode 100644 index 0000000..3917a73 Binary files /dev/null and b/server/data/dashboard.db-shm differ diff --git a/server/data/dashboard.db-wal b/server/data/dashboard.db-wal new file mode 100644 index 0000000..df9ffcd Binary files /dev/null and b/server/data/dashboard.db-wal differ diff --git a/server/db_py.py b/server/db_py.py index fc8065e..d5bca76 100644 --- a/server/db_py.py +++ b/server/db_py.py @@ -6,9 +6,15 @@ import threading from contextlib import contextmanager BASE_DIR = os.path.dirname(os.path.abspath(__file__)) -DB_PATH = os.path.join(BASE_DIR, "dashboard.db") +_DEFAULT_DB_PATH = os.path.join(BASE_DIR, "data", "dashboard.db") +if os.path.exists("/.dockerenv"): + _DEFAULT_DB_PATH = "/app/data/dashboard.db" + +DB_PATH = os.getenv("DASHBOARD_DB_PATH", _DEFAULT_DB_PATH) CONFIG_JSON = os.path.join(BASE_DIR, "config.json") +os.makedirs(os.path.dirname(DB_PATH), exist_ok=True) + _conn = sqlite3.connect(DB_PATH, check_same_thread=False) _conn.row_factory = sqlite3.Row _lock = threading.RLock() @@ -27,7 +33,12 @@ def _tx(): def _init_db(): with _tx(): - _conn.execute("PRAGMA journal_mode=WAL;") + try: + _conn.execute("PRAGMA journal_mode=WAL;") + except sqlite3.OperationalError as exc: + # Fallback for filesystems where WAL is unavailable. + print(f"[db] WAL unavailable ({exc}); falling back to DELETE journal mode") + _conn.execute("PRAGMA journal_mode=DELETE;") _conn.executescript( """ CREATE TABLE IF NOT EXISTS config ( diff --git a/server/watcher.py b/server/watcher.py new file mode 100644 index 0000000..5c7137d --- /dev/null +++ b/server/watcher.py @@ -0,0 +1,29 @@ +import os +import sys +import time +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler + +class TestResultsHandler(FileSystemEventHandler): + def __init__(self, callback): + super().__init__() + self.callback = callback + + def on_created(self, event): + if event.is_directory: + print(f"[watcher] Detected new test result directory: {event.src_path}") + self.callback(event.src_path) + + +def start_watching_results_dir(results_dir, callback): + event_handler = TestResultsHandler(callback) + observer = Observer() + observer.schedule(event_handler, results_dir, recursive=False) + observer.start() + print(f"[watcher] Started watching for new test results in: {results_dir}") + try: + while True: + time.sleep(1) + except KeyboardInterrupt: + observer.stop() + observer.join() \ No newline at end of file