Initial commit
This commit is contained in:
commit
6aa9bf85f3
10 changed files with 660 additions and 0 deletions
76
app/state.py
Normal file
76
app/state.py
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
"""SQLite-backed tracking of active + historical streams.
|
||||
|
||||
Backed by a file on the shared `appdata` PV (mounted at STATE_DB_PATH), so
|
||||
state survives pod restarts/redeploys. "Active" streams are just history
|
||||
rows with end IS NULL — no separate table needed, which also gives free
|
||||
crash recovery (if the pod dies mid-stream, the row is simply still open).
|
||||
"""
|
||||
import os
|
||||
import sqlite3
|
||||
import threading
|
||||
from datetime import datetime, timezone
|
||||
|
||||
|
||||
def _now_iso():
|
||||
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
|
||||
SCHEMA = """
|
||||
CREATE TABLE IF NOT EXISTS streams (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
path TEXT NOT NULL,
|
||||
source_type TEXT,
|
||||
start TEXT NOT NULL,
|
||||
end TEXT
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_streams_active ON streams (path) WHERE end IS NULL;
|
||||
"""
|
||||
|
||||
|
||||
class StreamState:
|
||||
def __init__(self, db_path, history_limit=50):
|
||||
self._db_path = db_path
|
||||
self._history_limit = history_limit
|
||||
self._lock = threading.Lock()
|
||||
os.makedirs(os.path.dirname(db_path) or ".", exist_ok=True)
|
||||
with self._connect() as conn:
|
||||
conn.executescript(SCHEMA)
|
||||
|
||||
def _connect(self):
|
||||
conn = sqlite3.connect(self._db_path)
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
|
||||
def on_ready(self, path, source_type=None):
|
||||
with self._lock, self._connect() as conn:
|
||||
conn.execute(
|
||||
"INSERT INTO streams (path, source_type, start, end) VALUES (?, ?, ?, NULL)",
|
||||
(path, source_type, _now_iso()),
|
||||
)
|
||||
|
||||
def on_not_ready(self, path):
|
||||
with self._lock, self._connect() as conn:
|
||||
row = conn.execute(
|
||||
"SELECT id FROM streams WHERE path = ? AND end IS NULL ORDER BY id DESC LIMIT 1",
|
||||
(path,),
|
||||
).fetchone()
|
||||
if row:
|
||||
conn.execute(
|
||||
"UPDATE streams SET end = ? WHERE id = ?",
|
||||
(_now_iso(), row["id"]),
|
||||
)
|
||||
|
||||
def active(self):
|
||||
with self._connect() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT path, source_type, start FROM streams WHERE end IS NULL ORDER BY id DESC"
|
||||
).fetchall()
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
def history(self):
|
||||
with self._connect() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT path, source_type, start, end FROM streams ORDER BY id DESC LIMIT ?",
|
||||
(self._history_limit,),
|
||||
).fetchall()
|
||||
return [dict(r) for r in rows]
|
||||
Loading…
Add table
Add a link
Reference in a new issue