From 3613d0bfdc7e82f09e97acba64d412cb77605f1c Mon Sep 17 00:00:00 2001 From: Leo dev Date: Sat, 13 Sep 2025 12:37:18 +0200 Subject: [PATCH] Added database --- .gitignore | 3 +- Cargo.toml | 1 + cli/Cargo.lock | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ src/database.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 25 +++++++++++---- src/types.rs | 2 +- 6 files changed, 190 insertions(+), 9 deletions(-) create mode 100644 src/database.rs diff --git a/.gitignore b/.gitignore index 598a1f3..b0bc9c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ target/ plugins/ config.json -/Cargo.lock \ No newline at end of file +/Cargo.lock +*.db \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 9dfe812..bd412a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ anyhow = "1.0.99" chrono = "0.4.42" libloading = { version = "0.8.8", optional = true } once_cell = "1.21.3" +rusqlite = "0.37.0" serde = { version = "1.0.219", features = ["serde_derive"] } serde_json = "1.0.143" tungstenite = "0.27.0" diff --git a/cli/Cargo.lock b/cli/Cargo.lock index 64d6923..d83c247 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -23,6 +23,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + [[package]] name = "block-buffer" version = "0.10.4" @@ -121,6 +127,18 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "find-msvc-tools" version = "0.1.1" @@ -133,6 +151,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "generic-array" version = "0.14.7" @@ -155,6 +179,24 @@ dependencies = [ "wasi", ] +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown", +] + [[package]] name = "http" version = "1.3.1" @@ -228,6 +270,16 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "libsqlite3-sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f" +dependencies = [ + "pkg-config", + "vcpkg", +] + [[package]] name = "log" version = "0.4.27" @@ -255,6 +307,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -317,6 +375,20 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rusqlite" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f" +dependencies = [ + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -378,6 +450,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + [[package]] name = "syn" version = "2.0.106" @@ -444,6 +522,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -458,6 +542,7 @@ dependencies = [ "chrono", "libloading", "once_cell", + "rusqlite", "serde", "serde_json", "tungstenite", diff --git a/src/database.rs b/src/database.rs new file mode 100644 index 0000000..9c956f5 --- /dev/null +++ b/src/database.rs @@ -0,0 +1,83 @@ +use crate::ServerConfig; +use rusqlite::{Connection, Result, params}; + +pub struct Database { + pub messages_db: MessagesDb, +} + +impl Database { + pub fn new(config: &ServerConfig) -> Option { + let conn = Connection::open("main.db").ok()?; + let messages_db = MessagesDb(conn); + messages_db.init(config)?; + Some(Self { messages_db }) + } +} + +unsafe impl Send for Database {} +unsafe impl Sync for Database {} + +pub struct MessagesDb(pub Connection); + +impl MessagesDb { + pub fn init(&self, _config: &ServerConfig) -> Option { + self.0 + .execute( + "CREATE TABLE IF NOT EXISTS chat ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + channel_id TEXT NOT NULL, + user_id TEXT NOT NULL, + contents TEXT NOT NULL, + timestamp INTEGER NOT NULL + )", + [], + ) + .ok() + } + + /// Insert a message into the DB + pub fn insert( + &self, + channel_id: &str, + user_id: &str, + contents: &str, + timestamp: i64, + ) -> Result { + self.0.execute( + "INSERT INTO chat (channel_id, user_id, contents, timestamp) + VALUES (?1, ?2, ?3, ?4)", + params![channel_id, user_id, contents, timestamp], + ) + } + + /// Fetch the latest N messages for a channel + pub fn fetch_recent( + &self, + channel_id: &str, + limit: usize, + ) -> Result> { + let mut stmt = self.0.prepare( + "SELECT id, channel_id, user_id, contents, timestamp + FROM chat + WHERE channel_id = ?1 + ORDER BY timestamp DESC + LIMIT ?2", + )?; + + let rows = stmt.query_map(params![channel_id, limit], |row| { + Ok(( + row.get::<_, i64>(0)?, // id + row.get::<_, String>(1)?, // channel_id + row.get::<_, String>(2)?, // user_id + row.get::<_, String>(3)?, // contents + row.get::<_, i64>(4)?, // timestamp + )) + })?; + + let mut results = Vec::new(); + for row in rows { + results.push(row?); + } + Ok(results) + } +} diff --git a/src/lib.rs b/src/lib.rs index 8063e98..4e6620b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ use std::{ }; pub mod client; +pub mod database; #[cfg(feature = "loader")] pub mod loader; pub mod logger; @@ -27,6 +28,7 @@ pub use once_cell; #[derive(serde::Serialize, serde::Deserialize)] pub struct ServerConfig { port: u16, + channels: Vec, } #[allow(dead_code)] @@ -35,11 +37,15 @@ pub struct Server { config: ServerConfig, plugins: Mutex>, clients: Mutex>, + pub db: database::Database, } impl Default for ServerConfig { fn default() -> Self { - Self { port: 7080 } + Self { + port: 7080, + channels: Vec::new(), + } } } @@ -53,16 +59,12 @@ impl Server { logger!(LOGGER "Server"); pub fn new(root: &Path) -> Arc { - Arc::new(Self { - plugins: Mutex::new(Vec::new()), - root: root.to_path_buf(), - config: ServerConfig::default(), - clients: Mutex::new(HashSet::new()), - }) + Self::new_config(root, ServerConfig::default()) } pub fn new_config(root: &Path, config: ServerConfig) -> Arc { Arc::new(Self { + db: database::Database::new(&config).unwrap(), plugins: Mutex::new(Vec::new()), root: root.to_path_buf(), config, @@ -128,6 +130,15 @@ impl Server { contents, } => { Self::LOGGER.info(format!("SendMessage to {channel_id}: {contents}")); + self.wrap_err( + &client, + self.db.messages_db.insert( + &channel_id, + "idk", + &contents, + chrono::Utc::now().timestamp(), + ), + )?; } ClientMessage::EditMessage { diff --git a/src/types.rs b/src/types.rs index 616dc8a..af1bb0d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -77,7 +77,7 @@ pub mod data { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Channel { - pub id: usize, + pub id: String, pub name: String, pub kind: ChannelKind, }