summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--store/src/backend/mod.rs109
-rw-r--r--store/src/lib.rs106
-rw-r--r--store/src/macros.rs8
-rw-r--r--tool/Cargo.toml1
-rw-r--r--tool/src/main.rs12
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"); }