added state and auth storage with traits, show last run time on cli

This commit is contained in:
əlemi 2022-03-22 01:54:05 +01:00
parent 32eb53ba2b
commit 9f01ac7d4e
No known key found for this signature in database
GPG key ID: BBCBFE5D7244634E
2 changed files with 97 additions and 3 deletions

View file

@ -8,7 +8,7 @@ use colored::Colorize;
use const_format::concatcp; use const_format::concatcp;
use git_version::git_version; use git_version::git_version;
use regex::Regex; 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 utils::{find_by_regex, parse_human_duration, HumanDisplay};
use remote::RemoteSync; use remote::RemoteSync;
@ -150,6 +150,10 @@ fn main() {
None => { None => {
let all = storage.all(args.old).unwrap(); let all = storage.all(args.old).unwrap();
let mut builder = String::new(); 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 { if args.old {
builder.push_str("Archived memos:\n"); builder.push_str("Archived memos:\n");
} }
@ -164,14 +168,14 @@ fn main() {
if args.notify { if args.notify {
libnotify::init("memo-cli").unwrap(); libnotify::init("memo-cli").unwrap();
let n = libnotify::Notification::new( 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()), Some(builder.as_str()),
None, None,
); );
n.show().unwrap(); n.show().unwrap();
libnotify::uninit(); libnotify::uninit();
} else { } else {
println!("{} | {}", "memo-cli".bold(), Local::now().format("%a %d/%m, %H:%M")); println!("{} | {}", "memo-cli".bold(), timing);
print!("{}", builder); print!("{}", builder);
} }
} }
@ -181,8 +185,11 @@ fn main() {
let res = SQLiteStorage::store("asdasd", "http://127.0.0.1:8443"); let res = SQLiteStorage::store("asdasd", "http://127.0.0.1:8443");
if res.is_ok() { if res.is_ok() {
println!("[^] uploaded local db"); println!("[^] uploaded local db");
storage.set_sync_time(Utc::now()).unwrap();
} else { } else {
println!("[!] could not upload db : {}", res.err().unwrap().to_string()); println!("[!] could not upload db : {}", res.err().unwrap().to_string());
} }
} }
storage.set_run_time(Utc::now()).unwrap();
} }

View file

@ -8,6 +8,11 @@ pub struct Memo {
pub due: Option<DateTime<Utc>>, pub due: Option<DateTime<Utc>>,
} }
pub struct State {
pub last_run: DateTime<Utc>,
pub last_sync: Option<DateTime<Utc>>,
}
impl fmt::Display for Memo { impl fmt::Display for Memo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut due_str = "null".to_string(); let mut due_str = "null".to_string();
@ -32,6 +37,30 @@ pub trait MemoStorage {
fn get(&self, id: u32) -> Result<Memo, Error>; fn get(&self, id: u32) -> Result<Memo, Error>;
} }
pub trait AuthStorage {
fn get_key(&self) -> Result<String, Error>;
fn set_key(&self, key:&str) -> Result<Option<String>, Error>;
}
pub trait StateStorage {
fn set_state(&self, state:State) -> Result<Option<State>, Error>;
fn get_state(&self) -> Result<State, Error>;
fn set_run_time(&self, time:DateTime<Utc>) -> 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<Utc>) -> Result<(), Error> {
let mut state = self.get_state()?;
state.last_sync = Some(time);
self.set_state(state)?;
Ok(())
}
}
// SQLiteStorage // SQLiteStorage
pub struct SQLiteStorage { pub struct SQLiteStorage {
@ -50,9 +79,67 @@ pub fn open_sqlite_storage(path: &str) -> Result<SQLiteStorage, Error> {
);", );",
[], [],
)?; )?;
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 }); return Ok(SQLiteStorage { conn: connection });
} }
impl AuthStorage for SQLiteStorage {
fn get_key(&self) -> Result<String, Error> {
return Ok(self.conn.query_row(
"SELECT * FROM auth", [],
|row| {
return Ok(row.get(0)?);
},
)?);
}
fn set_key(&self, key: &str) -> Result<Option<String>, 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<State, Error> {
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<Option<State>, 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 { impl MemoStorage for SQLiteStorage {
fn all(&self, done: bool) -> Result<Vec<Memo>, Error> { fn all(&self, done: bool) -> Result<Vec<Memo>, Error> {
let mut results = Vec::new(); let mut results = Vec::new();