summaryrefslogtreecommitdiffstats
path: root/src/db.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/db.rs')
-rw-r--r--src/db.rs107
1 files changed, 107 insertions, 0 deletions
diff --git a/src/db.rs b/src/db.rs
new file mode 100644
index 0000000..7868e3e
--- /dev/null
+++ b/src/db.rs
@@ -0,0 +1,107 @@
1use rusqlite::Connection;
2use std::path::Path;
3use std::sync::{Arc, Mutex};
4
5#[derive(Clone)]
6pub struct Database {
7 conn: Arc<Mutex<Connection>>,
8}
9
10// Safe because all access to Connection goes through Mutex::lock()
11unsafe impl Sync for Database {}
12
13impl Database {
14 pub fn open(path: &Path) -> Result<Self, rusqlite::Error> {
15 let conn = Connection::open(path)?;
16 conn.execute_batch("PRAGMA journal_mode=WAL; PRAGMA foreign_keys=ON;")?;
17 let db = Self {
18 conn: Arc::new(Mutex::new(conn)),
19 };
20 db.migrate()?;
21 Ok(db)
22 }
23
24 fn migrate(&self) -> Result<(), rusqlite::Error> {
25 let conn = self.conn.lock().unwrap();
26 conn.execute_batch(
27 "
28 CREATE TABLE IF NOT EXISTS accounts (
29 id INTEGER PRIMARY KEY AUTOINCREMENT,
30 username TEXT NOT NULL UNIQUE,
31 password TEXT NOT NULL,
32 is_superuser INTEGER NOT NULL DEFAULT 0,
33 password_change_required INTEGER NOT NULL DEFAULT 0
34 );
35
36 CREATE TABLE IF NOT EXISTS sessions (
37 id TEXT PRIMARY KEY,
38 account_id INTEGER NOT NULL,
39 created_at TEXT NOT NULL DEFAULT (datetime('now')),
40 FOREIGN KEY (account_id) REFERENCES accounts(id) ON DELETE CASCADE
41 );
42
43 CREATE TABLE IF NOT EXISTS instances (
44 id INTEGER PRIMARY KEY AUTOINCREMENT,
45 name TEXT NOT NULL UNIQUE,
46 version TEXT NOT NULL,
47 server_type TEXT NOT NULL CHECK(server_type IN ('VANILLA', 'FORGE', 'FABRIC')),
48 world_source TEXT NOT NULL CHECK(world_source IN ('generate', 'upload')),
49 world_seed TEXT,
50 level_type TEXT NOT NULL DEFAULT 'DEFAULT',
51 has_modpack INTEGER NOT NULL DEFAULT 0,
52 memory_mb INTEGER NOT NULL,
53 difficulty INTEGER NOT NULL DEFAULT 1,
54 gamemode INTEGER NOT NULL DEFAULT 0,
55 max_players INTEGER NOT NULL DEFAULT 20,
56 pvp INTEGER NOT NULL DEFAULT 1,
57 motd TEXT NOT NULL DEFAULT 'A Minecraft Server',
58 rcon_password TEXT NOT NULL,
59 is_active INTEGER NOT NULL DEFAULT 0,
60 container_state TEXT NOT NULL DEFAULT 'stopped',
61 created_at TEXT NOT NULL DEFAULT (datetime('now')),
62 updated_at TEXT NOT NULL DEFAULT (datetime('now'))
63 );
64
65 CREATE TABLE IF NOT EXISTS backups (
66 id INTEGER PRIMARY KEY AUTOINCREMENT,
67 instance_id INTEGER NOT NULL,
68 filename TEXT NOT NULL,
69 created_at TEXT NOT NULL DEFAULT (datetime('now')),
70 FOREIGN KEY (instance_id) REFERENCES instances(id) ON DELETE CASCADE
71 );
72
73 CREATE TABLE IF NOT EXISTS whitelist (
74 instance_id INTEGER NOT NULL,
75 username TEXT NOT NULL,
76 PRIMARY KEY (instance_id, username),
77 FOREIGN KEY (instance_id) REFERENCES instances(id) ON DELETE CASCADE
78 );
79
80 CREATE TABLE IF NOT EXISTS ops (
81 instance_id INTEGER NOT NULL,
82 username TEXT NOT NULL,
83 PRIMARY KEY (instance_id, username),
84 FOREIGN KEY (instance_id) REFERENCES instances(id) ON DELETE CASCADE
85 );
86
87 CREATE TABLE IF NOT EXISTS bans (
88 instance_id INTEGER NOT NULL,
89 username TEXT NOT NULL,
90 ban_type TEXT NOT NULL CHECK(ban_type IN ('user', 'ip')),
91 PRIMARY KEY (instance_id, username),
92 FOREIGN KEY (instance_id) REFERENCES instances(id) ON DELETE CASCADE
93 );
94 ",
95 )?;
96
97 // Migration: add container_state column if missing (for older DBs)
98 let _ = conn.execute_batch(
99 "ALTER TABLE instances ADD COLUMN container_state TEXT NOT NULL DEFAULT 'stopped'",
100 );
101 Ok(())
102 }
103
104 pub fn conn(&self) -> std::sync::MutexGuard<'_, Connection> {
105 self.conn.lock().unwrap()
106 }
107}