diff --git a/.travis.yml b/.travis.yml index 8bbd91f4..e77f18f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,12 @@ matrix: cache: cargo: true +addons: + apt: + packages: + - libdbus-1-dev + - pkg-config + script: - cargo build --all --all-features --verbose -j 1 - cargo test --all --all-features --verbose -j 1 diff --git a/Cargo.toml b/Cargo.toml index c8a2b9f1..62b680d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ members = [ "lib/entry/libimagentrytag", "lib/entry/libimagentryview", "lib/etc/libimaginteraction", + "lib/etc/libimagnotification", "lib/etc/libimagtimeui", "lib/etc/libimagutil", ] diff --git a/default.nix b/default.nix index bbc0e812..68429750 100644 --- a/default.nix +++ b/default.nix @@ -15,6 +15,8 @@ let pkgconfig which zlib + dbus + pkgconfig ]; in diff --git a/doc/src/09020-changelog.md b/doc/src/09020-changelog.md index dfc23e47..8a3ec5d7 100644 --- a/doc/src/09020-changelog.md +++ b/doc/src/09020-changelog.md @@ -44,6 +44,8 @@ This section contains the changelog from the last release to the next release. any other crate. * imag now reads the `IMAG_RTP` environment variable before trying to access `$HOME/.imag` for its runtimepath. + * `libimagnotification` was introduced, though not yet integrated into the + CLI tools * Bugfixes * `Store::entries()` does not yield StoreIds which point to directories diff --git a/lib/etc/libimagnotification/Cargo.toml b/lib/etc/libimagnotification/Cargo.toml new file mode 100644 index 00000000..88cd3852 --- /dev/null +++ b/lib/etc/libimagnotification/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "libimagnotification" +version = "0.4.0" +authors = ["Matthias Beyer "] + +description = "Library for the imag core distribution" + +keywords = ["imag", "PIM", "personal", "information", "management"] +readme = "../README.md" +license = "LGPL-2.1" + +documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html" +repository = "https://github.com/matthiasbeyer/imag" +homepage = "http://imag-pim.org" + +[dependencies] +notify-rust = "3.4.2" +error-chain = "0.11" + +libimagerror = { version = "0.5.0", path = "../../../lib/core/libimagerror" } + diff --git a/lib/etc/libimagnotification/src/error.rs b/lib/etc/libimagnotification/src/error.rs new file mode 100644 index 00000000..535a7c89 --- /dev/null +++ b/lib/etc/libimagnotification/src/error.rs @@ -0,0 +1,36 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015, 2016 Matthias Beyer and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +error_chain! { + types { + NotificationError, NotificationErrorKind, ResultExt, Result; + } + + foreign_links { + NotifyError(::notify_rust::error::Error); + } + + errors { + Unknown { + description("Unknown Error") + display("Unknown Error") + } + } +} + diff --git a/lib/etc/libimagnotification/src/lib.rs b/lib/etc/libimagnotification/src/lib.rs new file mode 100644 index 00000000..6e1f27f1 --- /dev/null +++ b/lib/etc/libimagnotification/src/lib.rs @@ -0,0 +1,28 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015, 2016 Matthias Beyer and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +extern crate notify_rust; +#[macro_use] extern crate error_chain; + +#[macro_use] extern crate libimagerror; + +pub mod error; +pub mod notificator; +pub mod result_notification; + diff --git a/lib/etc/libimagnotification/src/notificator.rs b/lib/etc/libimagnotification/src/notificator.rs new file mode 100644 index 00000000..5772ff0d --- /dev/null +++ b/lib/etc/libimagnotification/src/notificator.rs @@ -0,0 +1,118 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015, 2016 Matthias Beyer and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +use error::Result; +use error::ResultExt; + +/// A Notificator provides a function that can be called to notify about a certain object. +/// +/// # TODO +/// +/// The user of the library does _not_ get access to the notification handle. +/// This is not optimal, but enough for today. +/// +pub trait Notificator { + fn notify(&self, item: &T) -> Result<()>; +} + +pub mod default { + use std::fmt::Debug; + use std::fmt::Display; + + use error::Result; + + use notify_rust::Notification as RustNotification; + use notify_rust::NotificationUrgency; + + use super::Notificator; + + #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] + pub enum Urgency { + Low, + Normal, + High + } + + impl Default for Urgency { + fn default() -> Urgency { + Urgency::Normal + } + } + + impl Into for Urgency { + + fn into(self) -> NotificationUrgency { + match self { + Urgency::Low => NotificationUrgency::Low, + Urgency::Normal => NotificationUrgency::Normal, + Urgency::High => NotificationUrgency::Critical, + } + } + + } + + #[derive(Debug, Default, Clone)] + pub struct Notification { + pub timeout: i32, + pub message: String, + pub summary: String, + pub urgency: Urgency, + } + + impl Notificator for Notification { + + /// A default implementation for all Types that implement Display + fn notify(&self, item: &T) -> Result<()> { + let mut n = RustNotification::new(); + n.appname("imag"); + n.summary(&self.summary); + n.urgency(self.urgency.clone().into()); + n.body(&format!("{}: {}", &self.message, item)); + let _ = n.finalize().show(); // Ignoring error here + Ok(()) + } + + } + + #[derive(Debug, Default, Clone)] + pub struct DebugNotification(Notification); + + impl From for DebugNotification { + fn from(n: Notification) -> DebugNotification { + DebugNotification(n) + } + } + + impl Notificator for DebugNotification { + + /// A default implementation for all Types that implement Display + fn notify(&self, item: &T) -> Result<()> { + let mut n = RustNotification::new(); + n.appname("imag"); + n.summary(&self.0.summary); + n.urgency(self.0.urgency.clone().into()); + n.body(&format!("{}: {:?}", &self.0.message, item)); + let _ = n.finalize().show(); // Ignoring error here + Ok(()) + } + + } + +} + diff --git a/lib/etc/libimagnotification/src/result_notification.rs b/lib/etc/libimagnotification/src/result_notification.rs new file mode 100644 index 00000000..b458f767 --- /dev/null +++ b/lib/etc/libimagnotification/src/result_notification.rs @@ -0,0 +1,200 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015, 2016 Matthias Beyer and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +use std::error::Error; + +use notificator::Notificator; +use self::err::*; +use self::ok::*; + +pub mod err { + use std::ops::Deref; + use std::ops::DerefMut; + use std::error::Error; + + use notify_rust::Notification as RustNotification; + use notify_rust::NotificationUrgency; + + use error::ResultExt; + use error::NotificationErrorKind as NEK; + use notificator::default::Urgency; + use notificator::default::Notification; + use notificator::Notificator; + use error::Result; + + #[derive(Debug, Default, Clone)] + pub struct ErrorNotification(Notification, usize); + + impl ErrorNotification { + pub fn new(trace: usize, timeout: i32) -> ErrorNotification { + let notif = Notification { + timeout: timeout, + message: String::new(), // Not used in this special case + summary: "[Error]".to_owned(), + urgency: Urgency::High, + }; + + ErrorNotification(notif, trace) + } + } + + impl Notificator for ErrorNotification { + + /// A default implementation for all Types that implement Display + fn notify(&self, item: &T) -> Result<()>{ + fn trace_notify(urgency: NotificationUrgency, e: &Error, u: usize) -> Result<()> { + let mut n = RustNotification::new(); + n.appname("imag"); + n.summary("[Error]"); + n.urgency(urgency.clone()); + n.body(e.description()); + try!(n.finalize().show().map(|_| ()).chain_err(|| NEK::Unknown)); + + if u > 0 { + e.cause().map(|cause| trace_notify(urgency, cause, u - 1)); + } + + Ok(()) + } + + trace_notify(self.0.urgency.clone().into(), item, self.1) + } + + } + + impl Deref for ErrorNotification { + type Target = Notification; + + fn deref(&self) -> &Notification { + &self.0 + } + + } + + impl DerefMut for ErrorNotification { + + fn deref_mut(&mut self) -> &mut Notification { + &mut self.0 + } + + } + +} + +pub mod ok { + use std::ops::Deref; + use std::ops::DerefMut; + + use notify_rust::Notification as RustNotification; + + use notificator::default::Notification; + use notificator::Notificator; + use error::NotificationErrorKind as NEK; + use error::Result; + use error::ResultExt; + + #[derive(Debug, Default, Clone)] + pub struct OkNotification(Notification); + + impl From for OkNotification { + + fn from(n: Notification) -> OkNotification { + OkNotification(n) + } + + } + + impl Notificator for OkNotification { + + /// A default implementation for all Types that implement Display + fn notify(&self, _: &T) -> Result<()> { + let mut n = RustNotification::new(); + n.appname("imag"); + n.summary("[Ok]"); + n.urgency(self.0.urgency.clone().into()); + n.body(&"< >".to_owned()); + n.finalize().show().map(|_| ())?; + Ok(()) + } + + } + + impl Deref for OkNotification { + type Target = Notification; + + fn deref(&self) -> &Notification { + &self.0 + } + + } + + impl DerefMut for OkNotification { + + fn deref_mut(&mut self) -> &mut Notification { + &mut self.0 + } + + } + +} + +/// An extension trait for Result types +/// +/// Can be used to notify on error or on "Ok(_)" values. +/// +/// # Warning +/// +/// As the notification could go wrong, but inside a mapping function, the error cannot be given to +/// someone, we ignore errors in the Notificator::notify() call. +pub trait ResultNotification { + + /// Notify with a custom Notificator, only notify on Ok(T) + fn notify_with(self, n: &Notificator) -> Self; + + /// Notify with the OkNotification::default(), only notify on Ok(T) + fn notify(self) -> Self; + + /// Notify with a custom Notificator, only notify on Err(E) + fn notify_on_err_with(self, n: &Notificator) -> Self; + + /// Notify with the ErrorNotification::default(), only notify on Err(E) + fn notify_on_err(self) -> Self; + +} + +impl ResultNotification for Result { + + fn notify_with(self, n: &Notificator) -> Self { + self.map(|item| { let _ = n.notify(&item); item }) + } + + fn notify(self) -> Self { + self.notify_with(&OkNotification::default()) + } + + fn notify_on_err_with(self, n: &Notificator) -> Self { + self.map_err(|e| { let _ = n.notify(&e); e }) + } + + fn notify_on_err(self) -> Self { + self.notify_on_err_with(&ErrorNotification::default()) + } + +} +