browser_control/registry/
schema.rs1use anyhow::{Context, Result};
4
5const SCHEMA: &str = r#"
6CREATE TABLE IF NOT EXISTS browsers (
7 name TEXT PRIMARY KEY,
8 kind TEXT NOT NULL,
9 engine TEXT NOT NULL,
10 pid INTEGER NOT NULL,
11 endpoint TEXT NOT NULL,
12 port INTEGER NOT NULL,
13 profile_dir TEXT NOT NULL,
14 executable TEXT NOT NULL,
15 headless INTEGER NOT NULL,
16 started_at TEXT NOT NULL
17);
18CREATE INDEX IF NOT EXISTS browsers_kind_started ON browsers(kind, started_at DESC);
19
20-- One scratch tab per browser. Used by lock-free ops (eval/fetch with no
21-- explicit tab) so they never touch a user-visible tab. The single-row
22-- shape is deliberate: concurrent CLI calls share the same scratch row
23-- (CDP allows multiple sessions per target), and recovery just rewrites
24-- target_id when the existing scratch is dead.
25CREATE TABLE IF NOT EXISTS scratches (
26 browser_name TEXT PRIMARY KEY,
27 target_id TEXT NOT NULL,
28 last_used_at_epoch_s INTEGER NOT NULL
29);
30
31-- Named tabs, addressed as `<browser>/<name>` across the CLI. `daemon_created`
32-- distinguishes tabs the CLI opened (eligible for sweep / LRU recycle) from
33-- tabs adopted from the user (kept verbatim, never GC'd).
34CREATE TABLE IF NOT EXISTS tabs (
35 browser_name TEXT NOT NULL,
36 name TEXT NOT NULL,
37 target_id TEXT NOT NULL,
38 last_url TEXT NOT NULL,
39 last_used_at_epoch_s INTEGER NOT NULL,
40 daemon_created INTEGER NOT NULL,
41 PRIMARY KEY (browser_name, name)
42);
43CREATE INDEX IF NOT EXISTS tabs_lru ON tabs(browser_name, daemon_created, last_used_at_epoch_s);
44
45-- Firefox BiDi allows one session per browser. This table arbitrates among
46-- concurrent CLI processes: holder_pid is the winning process, released
47-- on Drop (DELETE WHERE browser_name=? AND holder_pid=?). Stale rows from
48-- crashed CLIs are evicted on acquire via pid_alive().
49CREATE TABLE IF NOT EXISTS bidi_locks (
50 browser_name TEXT PRIMARY KEY,
51 holder_pid INTEGER NOT NULL,
52 acquired_at_epoch_s INTEGER NOT NULL
53);
54"#;
55
56pub fn apply(conn: &rusqlite::Connection) -> Result<()> {
58 conn.execute_batch(SCHEMA)
59 .context("applying registry schema")?;
60 Ok(())
61}