diff options
-rw-r--r-- | store/src/backend/mod.rs | 109 | ||||
-rw-r--r-- | store/src/lib.rs | 106 | ||||
-rw-r--r-- | store/src/macros.rs | 8 | ||||
-rw-r--r-- | tool/Cargo.toml | 1 | ||||
-rw-r--r-- | tool/src/main.rs | 12 |
5 files changed, 155 insertions, 81 deletions
diff --git a/store/src/backend/mod.rs b/store/src/backend/mod.rs index 067c6d5c..bbb1aade 100644 --- a/store/src/backend/mod.rs +++ b/store/src/backend/mod.rs @@ -500,13 +500,23 @@ impl node::binding::Server for BindingServer { mut results: node::binding::RegisterEncryptionResults) -> Promise<(), capnp::Error> { bind_results!(results); + let now = Timestamp::now(); let key = sry!(self.key_id()); + sry!(self.c - .execute("UPDATE bindings SET encryption_count = encryption_count + 1 WHERE id = ?1", - &[&self.id])); + .execute("UPDATE bindings + SET encryption_count = encryption_count + 1, + encryption_first = coalesce(encryption_first, ?2), + encryption_last = ?2 + WHERE id = ?1", + &[&self.id, &now])); sry!(self.c - .execute("UPDATE keys SET encryption_count = encryption_count + 1 WHERE id = ?1", - &[&key])); + .execute("UPDATE keys + SET encryption_count = encryption_count + 1, + encryption_first = coalesce(encryption_first, ?2), + encryption_last = ?2 + WHERE id = ?1", + &[&key, &now])); sry!(self.query_stats( pry!(results.get().get_result()).init_ok())); Promise::ok(()) @@ -517,13 +527,23 @@ impl node::binding::Server for BindingServer { mut results: node::binding::RegisterVerificationResults) -> Promise<(), capnp::Error> { bind_results!(results); + let now = Timestamp::now(); let key = sry!(self.key_id()); + sry!(self.c - .execute("UPDATE bindings SET verification_count = verification_count + 1 WHERE id = ?1", - &[&self.id])); + .execute("UPDATE bindings + SET verification_count = verification_count + 1, + verification_first = coalesce(verification_first, ?2), + verification_last = ?2 + WHERE id = ?1", + &[&self.id, &now])); sry!(self.c - .execute("UPDATE keys SET verification_count = verification_count + 1 WHERE id = ?1", - &[&key])); + .execute("UPDATE keys + SET verification_count = verification_count + 1, + verification_first = coalesce(verification_first, ?2), + verification_last = ?2 + WHERE id = ?1", + &[&key, &now])); sry!(self.query_stats( pry!(results.get().get_result()).init_ok())); Promise::ok(()) @@ -834,22 +854,49 @@ trait Query { } fn query_stats(&mut self, mut stats: node::stats::Builder) -> Result<()> { - let created = self.query("created")?; - let updated = self.query("updated")?; - let encryption_count = self.query("encryption_count")?; - let encryption_first = self.query("encryption_first")?; - let encryption_last = self.query("encryption_last")?; - let verification_count = self.query("verification_count")?; - let verification_first = self.query("verification_first")?; - let verification_last = self.query("verification_last")?; + let ( + created, updated, + encryption_count, encryption_first, encryption_last, + verification_count, verification_first, verification_last, + ): (i64, Option<i64>, + i64, Option<i64>, Option<i64>, + i64, Option<i64>, Option<i64>) + = self.connection().query_row( + &format!("SELECT + created, + updated, + encryption_count, + encryption_first, + encryption_last, + verification_count, + verification_first, + verification_last + FROM {0} + WHERE id = ?1", Self::table_name()), + &[&self.id()], |row| (row.get(0), row.get(1), + row.get(2), row.get(3), row.get(4), + row.get(5), row.get(6), row.get(7)))?; + macro_rules! set_some { + ( $object: ident) => { + macro_rules! set { + ($setter: ident, $value: expr ) => {{ + if let Some(value) = $value { + $object.$setter(value); + } + }} + } + } + } + + set_some!(stats); stats.set_created(created); - stats.set_updated(updated); + set!(set_updated, updated); stats.set_encryption_count(encryption_count); - stats.set_encryption_first(encryption_first); - stats.set_encryption_last(encryption_last); + set!(set_encryption_first, encryption_first); + set!(set_encryption_last, encryption_last); stats.set_verification_count(verification_count); - stats.set_verification_first(verification_first); - stats.set_verification_last(verification_last); + set!(set_verification_first, verification_first); + set!(set_verification_last, verification_last); Ok(()) } } @@ -1075,14 +1122,14 @@ CREATE TABLE bindings ( key INTEGER NOT NULL, created INTEGER NOT NULL, - updated DEFAULT 0, + updated INTEGER NULL, encryption_count DEFAULT 0, - encryption_first DEFAULT 0, - encryption_last DEFAULT 0, + encryption_first INTEGER NULL, + encryption_last INTEGER NULL, verification_count DEFAULT 0, - verification_first DEFAULT 0, - verification_last DEFAULT 0, + verification_first INTEGER NULL, + verification_last INTEGER NULL, UNIQUE(store, label), FOREIGN KEY (store) REFERENCES stores(id) ON DELETE CASCADE, @@ -1094,15 +1141,15 @@ CREATE TABLE keys ( key BLOB, created INTEGER NOT NULL, - updated DEFAULT 0, + updated INTEGER NULL, update_at INTEGER NOT NULL, encryption_count DEFAULT 0, - encryption_first DEFAULT 0, - encryption_last DEFAULT 0, + encryption_first INTEGER NULL, + encryption_last INTEGER NULL, verification_count DEFAULT 0, - verification_first DEFAULT 0, - verification_last DEFAULT 0, + verification_first INTEGER NULL, + verification_last INTEGER NULL, UNIQUE (fingerprint)); diff --git a/store/src/lib.rs b/store/src/lib.rs index 2225bf06..bdd45929 100644 --- a/store/src/lib.rs +++ b/store/src/lib.rs @@ -37,10 +37,10 @@ //! println!("Binding {:?}", binding.stats()?); //! // prints: //! // Binding Stats { -//! // created: Some(SystemTime { tv_sec: 1513704042, tv_nsec: 0 }), +//! // created: Some(Timespec { tv_sec: 1513704042, tv_nsec: 0 }), //! // updated: None, -//! // encryption: Stamps { count: 0, first: None, latest: None }, -//! // verification: Stamps { count: 0, first: None, latest: None } +//! // encryption: Stamps { count: 0, first: None, last: None }, +//! // verification: Stamps { count: 0, first: None, last: None } //! // } //! # Ok(()) //! # } @@ -60,11 +60,11 @@ use std::cell::RefCell; use std::fmt; use std::io; use std::rc::Rc; -use std::time::{SystemTime, SystemTimeError, Duration, UNIX_EPOCH}; use capnp::capability::Promise; use capnp_rpc::rpc_twoparty_capnp::Side; use futures::{Future}; +use time::Timespec; use tokio_core::reactor::Core; extern crate openpgp; @@ -397,10 +397,10 @@ impl Binding { /// println!("Binding {:?}", binding.stats()?); /// // prints: /// // Binding Stats { - /// // created: Some(SystemTime { tv_sec: 1513704042, tv_nsec: 0 }), + /// // created: Some(Timespec { tv_sec: 1513704042, tv_nsec: 0 }), /// // updated: None, - /// // encryption: Stamps { count: 0, first: None, latest: None }, - /// // verification: Stamps { count: 0, first: None, latest: None } + /// // encryption: Stamps { count: 0, first: None, last: None }, + /// // verification: Stamps { count: 0, first: None, last: None } /// // } /// # Ok(()) /// # } @@ -680,12 +680,12 @@ impl Key { } -/// Returns `t` as SystemTime. -fn from_unix(t: i64) -> Option<SystemTime> { - if t <= 0 { +/// Returns `t` as Timespec. +fn from_unix(t: i64) -> Option<Timespec> { + if t == 0 { None } else { - Some(UNIX_EPOCH + Duration::new(t as u64, 0)) + Some(Timespec::new(t, 0)) } } @@ -697,10 +697,10 @@ fn from_unix(t: i64) -> Option<SystemTime> { #[derive(Debug)] pub struct Stats { /// Records the time this item was created. - pub created: Option<SystemTime>, + pub created: Option<Timespec>, /// Records the time this item was last updated. - pub updated: Option<SystemTime>, + pub updated: Option<Timespec>, /// Records counters and timestamps of encryptions. pub encryption: Stamps, @@ -711,7 +711,7 @@ pub struct Stats { #[derive(Debug)] pub struct Log { - pub timestamp: SystemTime, + pub timestamp: Timespec, pub store: Option<Store>, pub binding: Option<Binding>, pub key: Option<Key>, @@ -757,15 +757,17 @@ impl Log { } /// Returns the message with timestamp and context. - pub fn full(&self) -> Result<String> { - Ok(match self.status { + pub fn full(&self) -> String { + let timestamp = + time::strftime("%F %H:%M", &time::at(self.timestamp)) + .unwrap(); // Only parse errors can happen. + + match self.status { Ok(ref m) => format!( - "{}: {}: {}", - format_system_time(&self.timestamp)?, self.slug,m), + "{}: {}: {}", timestamp, self.slug,m), Err((ref m, ref e)) => format!( - "{}: {}: {}: {}", - format_system_time(&self.timestamp)?, self.slug, m, e), - }) + "{}: {}: {}: {}", timestamp, self.slug, m, e), + } } } @@ -776,18 +778,18 @@ pub struct Stamps { pub count: usize, /// Records the time when this has been used first. - pub first: Option<SystemTime>, + pub first: Option<Timespec>, /// Records the time when this has been used last. - pub latest: Option<SystemTime>, + pub last: Option<Timespec>, } impl Stamps { - fn new(count: i64, first: i64, latest: i64) -> Self { + fn new(count: i64, first: Option<Timespec>, last: Option<Timespec>) -> Self { Stamps { count: count as usize, - first: from_unix(first), - latest: from_unix(latest), + first: first, + last: last, } } } @@ -935,16 +937,6 @@ impl Iterator for LogIter { } } -/// XXX Use the correct time type. -/// -/// We should use time::Timespec and get rid of this function. -pub fn format_system_time(t: &SystemTime) -> Result<String> { - let tm = time::at(time::Timespec::new(t.duration_since(UNIX_EPOCH)?.as_secs() as i64, 0)); - Ok(time::strftime("%F %H:%M", &tm) - // Only parse errors can happen. - .unwrap()) -} - /* Error handling. */ /// Results for sequoia-store. @@ -1026,12 +1018,6 @@ impl From<capnp::NotInSchema> for Error { } } -impl From<SystemTimeError> for Error { - fn from(_: SystemTimeError) -> Self { - Error::ProtocolError - } -} - #[cfg(test)] mod store_test { use super::{core, Store, Error, TPK, Fingerprint}; @@ -1177,6 +1163,42 @@ mod store_test { } #[test] + fn stats() { + let ctx = make_some_stores(); + let store = Store::open(&ctx, "default").unwrap(); + let fp = Fingerprint::from_bytes(b"bbbbbbbbbbbbbbbbbbbb"); + let binding = store.add("Mister B.", &fp).unwrap(); + + let stats0 = binding.stats().unwrap(); + assert_match!(Some(_) = stats0.created); + assert_match!(None = stats0.updated); + assert_eq!(stats0.encryption.count, 0); + assert_match!(None = stats0.encryption.first); + assert_match!(None = stats0.encryption.last); + assert_eq!(stats0.verification.count, 0); + assert_match!(None = stats0.verification.first); + assert_match!(None = stats0.verification.last); + + binding.register_encryption().unwrap(); + binding.register_encryption().unwrap(); + binding.register_verification().unwrap(); + + let stats1 = binding.stats().unwrap(); + assert_match!(Some(_) = stats1.created); + assert_eq!(stats0.created, stats1.created); + assert_match!(None = stats1.updated); + assert_eq!(stats1.encryption.count, 2); + assert_match!(Some(_) = stats1.encryption.first); + assert_match!(Some(_) = stats1.encryption.last); + assert!(stats1.encryption.first <= stats1.encryption.last); + assert_eq!(stats1.verification.count, 1); + assert_match!(Some(_) = stats1.verification.first); + assert_match!(Some(_) = stats1.verification.last); + assert_eq!(stats1.verification.first, stats1.verification.last); + } + + + #[test] fn store_iterator() { let ctx = make_some_stores(); let mut iter = Store::list(&ctx, "org.sequoia-pgp.tests.f").unwrap(); diff --git a/store/src/macros.rs b/store/src/macros.rs index c9a932c4..11e5f085 100644 --- a/store/src/macros.rs +++ b/store/src/macros.rs @@ -47,11 +47,11 @@ macro_rules! make_stats_request { created: from_unix(s.get_created()), updated: from_unix(s.get_updated()), encryption: Stamps::new(s.get_encryption_count(), - s.get_encryption_first(), - s.get_encryption_last()), + from_unix(s.get_encryption_first()), + from_unix(s.get_encryption_last())), verification: Stamps::new(s.get_verification_count(), - s.get_verification_first(), - s.get_verification_last()), + from_unix(s.get_verification_first()), + from_unix(s.get_verification_last())), }) }, Which::Err(Ok(e)) => Err(e.into()), diff --git a/tool/Cargo.toml b/tool/Cargo.toml index f0118c1a..276f4c7e 100644 --- a/tool/Cargo.toml +++ b/tool/Cargo.toml @@ -10,6 +10,7 @@ sequoia-net = { path = "../net" } sequoia-store = { path = "../store" } clap = "2.27.1" prettytable-rs = "0.6.7" +time = "0.1.38" [[bin]] name = "sq" diff --git a/tool/src/main.rs b/tool/src/main.rs index 27f75530..ac79cb7d 100644 --- a/tool/src/main.rs +++ b/tool/src/main.rs @@ -3,6 +3,7 @@ extern crate clap; #[macro_use] extern crate prettytable; +extern crate time; use clap::{Arg, App, SubCommand, AppSettings}; use prettytable::Table; @@ -413,8 +414,7 @@ fn real_main() -> Result<()> { Cell::new(&item.fingerprint.to_string()), Cell::new(&format!("{}", item.bindings)), if let Some(ref t) = stats.updated { - Cell::new(&sequoia_store::format_system_time(t) - .expect("Failed to format timestamp")) + Cell::new(&format_time(t)) } else { Cell::new("") }, @@ -462,8 +462,7 @@ fn print_log(iter: LogIter) { for entry in iter { table.add_row(Row::new(vec![ - Cell::new(&sequoia_store::format_system_time(&entry.timestamp) - .expect("Failed to format timestamp")), + Cell::new(&format_time(&entry.timestamp)), Cell::new(&entry.slug), Cell::new(&entry.short())])); } @@ -471,4 +470,9 @@ fn print_log(iter: LogIter) { table.printstd(); } +fn format_time(t: &time::Timespec) -> String { + time::strftime("%F %H:%M", &time::at(*t)) + .unwrap() // Only parse errors can happen. +} + fn main() { real_main().expect("An error occured"); } |