From 45970d227153c07a0f2e0c4c8fe18d93cb935364 Mon Sep 17 00:00:00 2001 From: koehr Date: Sat, 17 Apr 2021 21:41:47 +0200 Subject: [PATCH] start to implement URL expiry --- Cargo.lock | 56 +++++++++++++++++++++++++++++++++++++++++++++++------ Cargo.toml | 1 + src/db.rs | 27 +++++++++++++++++++------- src/main.rs | 5 +++++ 4 files changed, 76 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df8170d..03eee2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,7 +79,7 @@ dependencies = [ "serde_urlencoded", "sha-1", "slab", - "time", + "time 0.2.24", ] [[package]] @@ -245,7 +245,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "socket2", - "time", + "time 0.2.24", "tinyvec", "url", ] @@ -473,6 +473,19 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time 0.1.44", + "winapi 0.3.9", +] + [[package]] name = "const_fn" version = "0.4.5" @@ -486,7 +499,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784ad0fbab4f3e9cef09f20e0aea6000ae08d2cb98ac4c0abc53df18803d702f" dependencies = [ "percent-encoding", - "time", + "time 0.2.24", "version_check", ] @@ -794,7 +807,7 @@ checksum = "4060f4657be78b8e766215b02b18a2e862d83745545de804638e2b545e81aee6" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi 0.10.1+wasi-snapshot-preview1", + "wasi 0.10.0+wasi-snapshot-preview1", ] [[package]] @@ -982,6 +995,7 @@ name = "k0r" version = "0.1.0" dependencies = [ "actix-web", + "chrono", "exitcode", "failure", "failure_derive", @@ -1191,6 +1205,25 @@ dependencies = [ "version_check", ] +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.13.0" @@ -1791,6 +1824,17 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi 0.3.9", +] + [[package]] name = "time" version = "0.2.24" @@ -2035,9 +2079,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.10.1+wasi-snapshot-preview1" +version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" diff --git a/Cargo.toml b/Cargo.toml index 19f3ca9..ffad35f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ failure_derive = "0.1.1" exitcode = "1.1.2" human-panic = "1.0.3" text_io = "0.1.8" +chrono = "0.4.19" [build-dependencies] ructe = { version = "0.13", features = ["mime03"] } diff --git a/src/db.rs b/src/db.rs index e10ea1e..f9a17d4 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,4 +1,5 @@ use actix_web::{web, Error as AWError}; +use chrono::Utc; use failure::Error; use failure_derive::Fail; use futures::{Future, TryFutureExt}; @@ -27,7 +28,7 @@ pub enum DBError { pub enum DBValue { String(String), Number(i64), - // Bool(bool), + Bool(bool), None, } @@ -40,11 +41,13 @@ pub struct UrlPostData { pub url: String, pub title: Option, pub description: Option, + pub expiry: Option, pub key: String, } /// Possible database queries, used with db::query pub enum Queries { + ForceSync, NeedsInit, CountUsers, InitDB, @@ -95,6 +98,7 @@ URLs|title URLs|url URLs|user_id URLs|visits +URLs|expiry Users|api_key Users|is_admin Users|rate_limit @@ -111,6 +115,11 @@ Users|rowid", } } +fn sync_database(conn: Connection) -> Result { + conn.execute("PRAGMA wal_checkpoint(TRUNCATE);", NO_PARAMS)?; + Ok(DBValue::Bool(true)) +} + /// Initializes a new SQlite database with the default schema. fn init_database(conn: Connection) -> Result { conn.execute_batch( @@ -129,8 +138,9 @@ fn init_database(conn: Connection) -> Result { visits INTEGER DEFAULT 0, title TEXT, description TEXT, - created_at DATETIME, - user_id INTEGER NOT NULL, + expiry DATETIME, + created_at DATETIME, + user_id INTEGER NOT NULL, FOREIGN KEY(user_id) REFERENCES Users(rowid) ); COMMIT;", @@ -147,7 +157,7 @@ fn count_users(conn: Connection) -> Result { conn.query_row("SELECT COUNT(rowid) FROM USERS", NO_PARAMS, |row| { row.get(0) }) - .map(|v| DBValue::Number(v)) + .map(DBValue::Number) .map_err(|src| { let msg = "Could not check users.".to_owned(); Error::from(DBError::SqliteError { msg, src }) @@ -174,10 +184,11 @@ fn create_user(conn: Connection, rate_limit: i64, is_admin: bool) -> Result { /// short_code is simply the base36 version of the table id fn get_url(conn: Connection, short_code: &str) -> Result { let row_id = ShortCode::from_code(short_code)?.n; + let now = Utc::now().timestamp(); conn.query_row( - "SELECT url FROM URLs WHERE rowid = ?", - &[row_id as i64], + "SELECT url FROM URLs WHERE rowid = ? and expiry > ?", + &[row_id as i64, now], |row| row.get(0), ) .map(DBValue::String) @@ -195,7 +206,7 @@ fn store_url(conn: Connection, data: &UrlPostData) -> Result { |row| row.get(0), )?; let _ = conn.execute_named( - "INSERT INTO URLs VALUES(:url, 0, :title, :description, DATETIME('now'), :user_id)", + "INSERT INTO URLs VALUES(:url, 0, :title, :description, DATETIME('now'), DATETIME(?), :user_id)", &[ (":url", &data.url), (":title", data.title.as_ref().unwrap_or(&String::from(""))), @@ -203,6 +214,7 @@ fn store_url(conn: Connection, data: &UrlPostData) -> Result { ":description", data.description.as_ref().unwrap_or(&String::from("")), ), + (":expiry", data.expiry.as_ref().unwrap_or(&i64::MAX)), (":user_id", &(user_id.to_string())), ], )?; @@ -219,6 +231,7 @@ pub fn query( ) -> impl Future> { let pool = pool.clone(); web::block(move || match query { + Queries::ForceSync => sync_database(pool.get()?), Queries::NeedsInit => check_database_schema(pool.get()?), Queries::CountUsers => count_users(pool.get()?), Queries::InitDB => init_database(pool.get()?), diff --git a/src/main.rs b/src/main.rs index 97e77d0..f0cd263 100644 --- a/src/main.rs +++ b/src/main.rs @@ -166,6 +166,11 @@ async fn init_db_pool(path_str: String) -> db::Pool { Err(err) => panic!("Failed to create super user! {}", err), } + match db::query(&db_pool, db::Queries::ForceSync).await { + Ok(_) => { /* all is good */ } + Err(err) => panic!("Failed to sync database! {}", err) + } + db_pool } -- 2.45.2