diff --git a/src/main.rs b/src/main.rs index 56a6cf5..f490bb3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ use colored::Colorize; use const_format::concatcp; use git_version::git_version; use regex::Regex; -use storage::{open_sqlite_storage, Memo, MemoStorage, SQLiteStorage}; +use storage::{open_sqlite_storage, Memo, MemoStorage, AuthStorage, StateStorage, SQLiteStorage}; use utils::{find_by_regex, parse_human_duration, HumanDisplay}; use remote::RemoteSync; @@ -150,6 +150,10 @@ fn main() { None => { let all = storage.all(args.old).unwrap(); let mut builder = String::new(); + let timing = if let Some(state) = storage.get_state().ok() { + let now = Local::now(); + format!("last run: {}", state.last_run.with_timezone(&now.timezone()).format("%a %d/%m %H:%M")) + } else { Local::now().format("%a %d/%m, %H:%M").to_string() }; if args.old { builder.push_str("Archived memos:\n"); } @@ -164,14 +168,14 @@ fn main() { if args.notify { libnotify::init("memo-cli").unwrap(); let n = libnotify::Notification::new( - format!("memo-cli | {}", Local::now().format("%a %d/%m, %H:%M")).as_str(), + format!("memo-cli | {}", timing).as_str(), Some(builder.as_str()), None, ); n.show().unwrap(); libnotify::uninit(); } else { - println!("{} | {}", "memo-cli".bold(), Local::now().format("%a %d/%m, %H:%M")); + println!("{} | {}", "memo-cli".bold(), timing); print!("{}", builder); } } @@ -181,8 +185,11 @@ fn main() { let res = SQLiteStorage::store("asdasd", "http://127.0.0.1:8443"); if res.is_ok() { println!("[^] uploaded local db"); + storage.set_sync_time(Utc::now()).unwrap(); } else { println!("[!] could not upload db : {}", res.err().unwrap().to_string()); } } + + storage.set_run_time(Utc::now()).unwrap(); } diff --git a/src/storage.rs b/src/storage.rs index a3f9e67..7c81567 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -8,6 +8,11 @@ pub struct Memo { pub due: Option>, } +pub struct State { + pub last_run: DateTime, + pub last_sync: Option>, +} + impl fmt::Display for Memo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut due_str = "null".to_string(); @@ -32,6 +37,30 @@ pub trait MemoStorage { fn get(&self, id: u32) -> Result; } +pub trait AuthStorage { + fn get_key(&self) -> Result; + fn set_key(&self, key:&str) -> Result, Error>; +} + +pub trait StateStorage { + fn set_state(&self, state:State) -> Result, Error>; + fn get_state(&self) -> Result; + + fn set_run_time(&self, time:DateTime) -> Result<(), Error> { + let mut state = self.get_state().unwrap_or(State{last_run:time, last_sync:None}); // TODO jank way to not fail on 1st use + state.last_run = time; + self.set_state(state)?; + Ok(()) + } + + fn set_sync_time(&self, time:DateTime) -> Result<(), Error> { + let mut state = self.get_state()?; + state.last_sync = Some(time); + self.set_state(state)?; + Ok(()) + } +} + // SQLiteStorage pub struct SQLiteStorage { @@ -50,9 +79,67 @@ pub fn open_sqlite_storage(path: &str) -> Result { );", [], )?; + connection.execute( + "CREATE TABLE IF NOT EXISTS state ( + last_run DATETIME DEFAULT NULL, + last_sync DATETIME DEFAULT NULL + );", + [], + )?; + connection.execute( + "CREATE TABLE IF NOT EXISTS auth ( + key TEXT PRIMARY KEY + );", + [], + )?; return Ok(SQLiteStorage { conn: connection }); } +impl AuthStorage for SQLiteStorage { + fn get_key(&self) -> Result { + return Ok(self.conn.query_row( + "SELECT * FROM auth", [], + |row| { + return Ok(row.get(0)?); + }, + )?); + } + + fn set_key(&self, key: &str) -> Result, Error> { + let old_key = self.get_key().ok(); + self.conn.execute("DELETE FROM auth;", [])?; + self.conn.execute( + "INSERT INTO auth VALUES (?);", + params![key] + )?; + return Ok(old_key); + } +} + +impl StateStorage for SQLiteStorage { + fn get_state(&self) -> Result { + return Ok(self.conn.query_row( + "SELECT * FROM state", [], + |row| { + return Ok(State{ + last_run:row.get(0)?, + last_sync:row.get(1).ok() + }); + }, + )?); + } + + fn set_state(&self, state:State) -> Result, Error> { + let old_state = self.get_state().ok(); + self.conn.execute("DELETE FROM state;", [])?; + self.conn.execute( + "INSERT INTO state (last_run, last_sync) VALUES (?, ?);", + params![state.last_run, state.last_sync] + )?; + return Ok(old_state); + } +} + impl MemoStorage for SQLiteStorage { fn all(&self, done: bool) -> Result, Error> { let mut results = Vec::new();