diff options
-rw-r--r-- | Cargo.lock | 31 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/main.rs | 76 |
3 files changed, 103 insertions, 5 deletions
diff --git a/Cargo.lock b/Cargo.lock index 0588ad8..175aac8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -928,6 +928,36 @@ dependencies = [ ] [[package]] +name = "sqlite" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12e072cb5fb89b3fe5e9c9584676348feb503f9fb3ae829d9868171bc5372d48" +dependencies = [ + "libc", + "sqlite3-sys", +] + +[[package]] +name = "sqlite3-src" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1815a7a02c996eb8e5c64f61fcb6fd9b12e593ce265c512c5853b2513635691" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "sqlite3-sys" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d47c99824fc55360ba00caf28de0b8a0458369b832e016a64c13af0ad9fbb9ee" +dependencies = [ + "libc", + "sqlite3-src", +] + +[[package]] name = "syn" version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1217,6 +1247,7 @@ dependencies = [ "reqwest", "serde", "serde_json", + "sqlite", "tokio", "tokio-macros", "tracing", diff --git a/Cargo.toml b/Cargo.toml index 43bc0e4..32d2dcb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ futures-util = { version = "0.3.25", features = ["tokio-io"] } reqwest = { version = "0.11.13", features = ["serde_json", "json"] } serde = { version = "1.0.151", features = ["serde_derive"] } serde_json = "1.0.91" +sqlite = "0.30.3" tokio = { version = "1.23.0", features = ["full"] } tokio-macros = "1.8.2" tracing = "0.1.37" diff --git a/src/main.rs b/src/main.rs index b735100..c2d2be3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,30 @@ mod mattermost; +use std::path::Path; + use anyhow::anyhow; use tokio::{self}; -use tracing::debug; +use tracing::{debug, warn}; -struct Vav {} +struct Vav { + db_connection: Option<sqlite::ConnectionWithFullMutex> +} +impl Vav{ + fn new<T:AsRef<Path>>(path:Option<T>) -> Self { + let ret = Self{ + db_connection:path.and_then(|path|sqlite::Connection::open_with_full_mutex(path).ok()), + }; + if let Some(connection) = &ret.db_connection{ + let create_table_res=connection.execute("CREATE TABLE keyval (key text NOT NULL PRIMARY KEY, value text NOT NULL)"); + if let Err(err) = create_table_res{ + warn!("Error while creating db {err}"); + } + } + ret + } +} +const INSERT_STATEMENT:&str = "INSERT INTO keyval (key,value) VALUES (?,?)"; +const SELECT_ONE:&str = "SELECT key,value FROM keyval where key=?"; +const SELECT_ALL:&str = "SELECT key,value FROM keyval"; #[async_trait::async_trait] impl mattermost::Handler for Vav { async fn handle( @@ -21,9 +42,53 @@ impl mattermost::Handler for Vav { if !message.starts_with('!') { return Ok(()); } - let message = message.strip_prefix('!').unwrap(); + let message=message.strip_prefix('!').unwrap(); + let (message,rest) = message.split_once(' ').unwrap_or((message,"")); match message{ - "adres" => client.reply_to(posted.post, "Uniwersytet Wrocławski Instytut Informatyki; pl. Frederyka Joliot-Curie 15; 50-383 Wrocław".to_owned()).await?, + "store" =>{ + let message = rest; + let (name,value) =message.split_once(' ').ok_or(anyhow::anyhow!("missing value in command store"))?; + if let Some(connection) = &self.db_connection{ + let mut statement = connection.prepare(INSERT_STATEMENT)?; + statement.bind((1,name))?; + statement.bind((2,value))?; + if let Err(err) = statement.next(){ + warn!("Error while writing to db {err}"); + } + } + + } + "lookup" =>{ + let name = rest; + let response =if let Some(connection) = &self.db_connection{ + let mut statement = connection.prepare(SELECT_ONE)?; + statement.bind((1,name))?; + match statement.next(){ + Ok(sqlite::State::Done) => { + "no entry under that name".to_owned() + }, + Ok(sqlite::State::Row) => { + statement.read::<String,_>(1)? + }, + Err(err) => { + warn!("Error while writing to db {err}"); + return Err(err.into())}, + } + } else {"uggh, no db".to_owned()}; + client.reply_to(posted.post,response).await?; + } + "list" =>{ + let response =if let Some(connection) = &self.db_connection{ + let mut statement = connection.prepare(SELECT_ALL)?; + let mut res =vec!["Stored keys:".to_owned()]; + while let Ok(result) = statement.next(){ + if result == sqlite::State::Done{ break;} + res.push(statement.read::<String,_>(0)?) + } + res.join("\n") + } else {"uggh, no db".to_owned()}; + client.reply_to(posted.post,response).await?; + } _ => return Err(anyhow!("Unrecognized command {message}")), } Ok(()) @@ -35,9 +100,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { tracing_subscriber::fmt::init(); let login = std::env::var("USER_MAIL")?; let password = std::env::var("USER_PASSWORD")?; + let db = std::env::var("SQLITE_PATH").ok(); let auth = mattermost::AuthData { login, password }; let mut client = mattermost::Client::new(auth, "https://mattermost.continuum.ii.uni.wroc.pl"); client.update_bearer_token().await?; - client.handle_websocket_stream(Vav {}).await?; + client.handle_websocket_stream(Vav::new(db)).await?; Ok(()) } |