From 60a3f7bf15c43182dfc5797fce27b603c104db02 Mon Sep 17 00:00:00 2001 From: Jakob Stendahl Date: Mon, 24 Jan 2022 14:18:47 +0100 Subject: Initial commit --- src/database.rs | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 src/database.rs (limited to 'src/database.rs') diff --git a/src/database.rs b/src/database.rs new file mode 100644 index 0000000..d43b7d7 --- /dev/null +++ b/src/database.rs @@ -0,0 +1,153 @@ +use std::process; +use std::env; +use log::{info, warn, error}; +use mysql::*; +use mysql::prelude::*; + +#[derive(Debug, PartialEq, Eq)] +pub struct FeedConf { + pub id: u32, + pub url: String, + pub last_fetch: Option, + pub title: String, + pub message: String, + pub push_url: String, + pub push_token: String +} + +/** + * Create Opts struct from env vars. + */ +fn build_opts() -> Opts { + let db_host = env::var("DB_HOST").expect("$DB_HOST is not set"); + let db_base = env::var("DB_BASE").expect("$DB_BASE is not set"); + let db_user = env::var("DB_USER").expect("$DB_USER is not set"); + let db_pass = env::var("DB_PASS").expect("$DB_PASS is not set"); + return Opts::from(OptsBuilder::new() + .ip_or_hostname(Some(db_host)) + .user(Some(db_user)) + .pass(Some(db_pass)) + .db_name(Some(db_base))); +} + +pub fn new_conn() -> Conn { + let conn_res = Conn::new(build_opts()); + if let Err(ref x) = conn_res { + error!("Could not connect to database ({:#?})...", x); + process::exit(1); + } + return conn_res.unwrap(); +} + +/** + * Check wether the table `rss-watcher-feeds` exists. + */ +fn table_exists(conn: &mut Conn) -> bool { + let db_base = env::var("DB_BASE").expect("$DB_BASE is not set"); + let q = conn.prep("SELECT table_name \ + FROM INFORMATION_SCHEMA.TABLES \ + WHERE TABLE_SCHEMA=:schema \ + AND TABLE_NAME='rss-watcher-feeds'").unwrap(); + let res: Option = conn.exec_first( + &q, params! {"schema" => db_base}).unwrap(); + if let None = res { return false; } + return true; +} + +/** + * This will create the `rss-watcher-feeds` table. + */ +fn table_create(conn: &mut Conn) { + let db_base = env::var("DB_BASE").expect("$DB_BASE is not set"); + info!("Creating table `{}`.`rss-watcher-feeds`", db_base); + let mut tx = conn.start_transaction(TxOpts::default()).unwrap(); + let mut q = "CREATE TABLE `rss-watcher-feeds` ( \ + `id` int NOT NULL AUTO_INCREMENT, \ + `url` VARCHAR(255) NOT NULL, \ + `last_fetch` int, \ + `title` VARCHAR(255) NOT NULL DEFAULT '{{title}}', \ + `message` VARCHAR(255) NOT NULL DEFAULT '{{summary}}', \ + `push_url` VARCHAR(255) NOT NULL, \ + `push_token` VARCHAR(255) NOT NULL, \ + PRIMARY KEY (`id`) + )"; + if let Err(x) = tx.query_drop(q) { + error!("Could not create table! ({:#?}", x); + process::exit(1); + } + q = "INSERT INTO `rss-watcher-feeds` (id, + url, + last_fetch, + title, + message, + push_url, + push_token) + VALUES (0,'version',1,'','','','')"; + if let Err(x) = tx.query_drop(q) { + error!("Could not insert versioning row! ({:#?}", x); + process::exit(1); + } + if let Err(x) = tx.commit() { + error!("Could not create table! ({:#?}", x); + process::exit(1); + } + +} + +/** + * Bootstrap the database, this will make sure tables exists, + * create them if not and run migrations if nececarry. + */ +pub fn bootstrap() { + info!("Bootstrapping database"); + let conn_res = Conn::new(build_opts()); + if let Err(ref x) = conn_res { + error!("Could not connect to database ({:#?})...", x); + process::exit(1); + } + let mut conn = conn_res.unwrap(); + info!("Connected to database"); + + if !table_exists(&mut conn) { + table_create(&mut conn); + } + + info!("Database should now be bootstrapped"); + info!("We are assuming that the table has the correct columns"); + info!("If not, we are going to get sql errors"); +} + +/** + * This will fetch all feeds from the database and return them as a Vector. + */ +pub fn get_feeds(conn: &mut Conn) -> Vec { + let q = "SELECT `id`, \ + `url`, \ + `last_fetch`, \ + `title`, \ + `message`, \ + `push_url`, \ + `push_token` \ + FROM `rss-watcher-feeds` \ + WHERE id > 1"; + let res = conn.query_map(q, + |(id,url,last_fetch,title,message,push_url,push_token)| { + FeedConf{id,url,last_fetch,title,message,push_url,push_token} + },).unwrap(); + return res; +} + +/** + * Method that updates the last fetch time timestamp in the database + */ +pub fn update_last_fetch(feed_id: u32, last_fetch: i64, conn: &mut Conn) { + let mut tx = conn.start_transaction(TxOpts::default()).unwrap(); + let q = "UPDATE `rss-watcher-feeds` SET last_fetch=? WHERE id=?"; + if let Err(x) = tx.exec_drop(q, (last_fetch,feed_id,)) { + warn!("Could not update last fetch time...! ({:#?}", x); + } + if let Err(x) = tx.commit() { + warn!("Could not commit update! ({:#?}", x); + } + +} -- cgit v1.2.3