Rewrite library

libimagcontact stores all contact information in the entry header now.
This commit is contained in:
Matthias Beyer 2018-04-25 12:54:00 +02:00
parent 3eab3af7b0
commit abc142f4b5
7 changed files with 88 additions and 71 deletions

View file

@ -25,15 +25,11 @@ log = "0.3"
toml = "0.4" toml = "0.4"
toml-query = "0.6" toml-query = "0.6"
vobject = "0.4" vobject = "0.4"
uuid = { version = "0.6", features = ["v4"] } uuid = "0.6"
serde = { version = "1", optional = true } serde = "1"
serde_derive = { version = "1", optional = true } serde_derive = "1"
libimagstore = { version = "0.8.0", path = "../../../lib/core/libimagstore" } libimagstore = { version = "0.8.0", path = "../../../lib/core/libimagstore" }
libimagerror = { version = "0.8.0", path = "../../../lib/core/libimagerror" } libimagerror = { version = "0.8.0", path = "../../../lib/core/libimagerror" }
libimagentryutil = { version = "0.8.0", path = "../../../lib/entry/libimagentryutil/" } libimagentryutil = { version = "0.8.0", path = "../../../lib/entry/libimagentryutil/" }
[features]
default = []
deser = ["serde", "serde_derive"]

View file

@ -17,16 +17,18 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
// //
use std::ops::Deref; use toml::to_string as toml_to_string;
use toml::from_str as toml_from_str;
use vobject::Component; use toml_query::read::TomlValueReadExt;
use libimagstore::store::Entry; use libimagstore::store::Entry;
use libimagentryutil::isa::Is; use libimagentryutil::isa::Is;
use libimagentryutil::isa::IsKindHeaderPathProvider; use libimagentryutil::isa::IsKindHeaderPathProvider;
use deser::DeserVcard;
use error::Result; use error::Result;
use util; use error::ContactError as CE;
use error::ContactErrorKind as CEK;
/// Trait to be implemented on ::libimagstore::store::Entry /// Trait to be implemented on ::libimagstore::store::Entry
pub trait Contact { pub trait Contact {
@ -35,7 +37,7 @@ pub trait Contact {
// getting data // getting data
fn get_contact_data(&self) -> Result<ContactData>; fn deser(&self) -> Result<DeserVcard>;
// More convenience functionality may follow // More convenience functionality may follow
@ -49,28 +51,18 @@ impl Contact for Entry {
self.is::<IsContact>().map_err(From::from) self.is::<IsContact>().map_err(From::from)
} }
fn get_contact_data(&self) -> Result<ContactData> { fn deser(&self) -> Result<DeserVcard> {
unimplemented!() let data = self
.get_header()
.read("contact.data")?
.ok_or_else(|| CE::from_kind(CEK::HeaderDataMissing("contact.data")))?;
// ugly hack
let data_str = toml_to_string(&data)?;
let deser : DeserVcard = toml_from_str(&data_str)?;
Ok(deser)
} }
} }
pub struct ContactData(Component);
impl ContactData {
pub fn into_inner(self) -> Component {
self.0
}
}
impl Deref for ContactData {
type Target = Component;
fn deref(&self) -> &Self::Target {
&self.0
}
}

View file

@ -20,13 +20,7 @@
use vobject::vcard::Vcard; use vobject::vcard::Vcard;
/// A type which can be build from a Vcard and be serialized. /// A type which can be build from a Vcard and be serialized.
/// #[derive(Serialize, Deserialize, Debug)]
/// # Details
///
/// Deserializing is not supported by libimagcontact yet
/// Elements which are "empty" (as in empty list) or optional and not present are not serialized.
///
#[derive(Serialize, Debug)]
pub struct DeserVcard { pub struct DeserVcard {
#[serde(skip_serializing_if = "Vec::is_empty")] #[serde(skip_serializing_if = "Vec::is_empty")]

View file

@ -32,6 +32,8 @@ error_chain! {
foreign_links { foreign_links {
Io(::std::io::Error); Io(::std::io::Error);
TomlDe(::toml::de::Error);
TomlSer(::toml::ser::Error);
TomlQueryError(::toml_query::error::Error); TomlQueryError(::toml_query::error::Error);
UuidError(::uuid::ParseError); UuidError(::uuid::ParseError);
} }
@ -43,14 +45,19 @@ error_chain! {
display("Type error in header, expected {} at '{}', found other type", ty, loc) display("Type error in header, expected {} at '{}', found other type", ty, loc)
} }
HeaderDataMissing(datapath: &'static str) {
description("Data missing in header")
display("Data missing in header at '{}'", datapath)
}
EntryNotFound(sid: StoreId) { EntryNotFound(sid: StoreId) {
description("Entry not found with StoreId") description("Entry not found with StoreId")
display("Entry {:?} not found", sid) display("Entry {:?} not found", sid)
} }
UidMissing(path: String) { UidMissing(buf: String) {
description("Vcard object has no UID") description("Vcard object has no UID")
display("Vcard at {:?} has no UID", path) display("Vcard has no UID : {}", buf)
} }
} }

View file

@ -33,12 +33,16 @@
while_true, while_true,
)] )]
#![recursion_limit="128"]
#[macro_use] extern crate log; #[macro_use] extern crate log;
#[macro_use] extern crate error_chain; #[macro_use] extern crate error_chain;
extern crate vobject; extern crate vobject;
extern crate toml; extern crate toml;
extern crate toml_query; extern crate toml_query;
extern crate uuid; extern crate uuid;
extern crate serde;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate libimagstore; #[macro_use] extern crate libimagstore;
extern crate libimagerror; extern crate libimagerror;
@ -50,15 +54,6 @@ pub mod contact;
pub mod error; pub mod error;
pub mod iter; pub mod iter;
pub mod store; pub mod store;
pub mod deser;
mod util; mod util;
#[cfg(feature = "serde")]
extern crate serde;
#[cfg(feature = "serde")]
#[macro_use] extern crate serde_derive;
#[cfg(feature = "deser")]
pub mod deser;

View file

@ -17,18 +17,24 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
// //
use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::result::Result as RResult;
use vobject::parse_component; use toml::Value;
use toml::to_string as toml_to_string;
use toml::from_str as toml_from_str;
use toml_query::insert::TomlValueInsertExt;
use vobject::vcard::Vcard;
use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreId;
use libimagstore::store::Store; use libimagstore::store::Store;
use libimagstore::store::FileLockEntry; use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreIdIterator; use libimagstore::storeid::StoreIdIterator;
use libimagentryutil::isa::Is; use libimagentryutil::isa::Is;
use contact::IsContact; use contact::IsContact;
use deser::DeserVcard;
use module_path::ModuleEntryPath;
use error::ContactError as CE; use error::ContactError as CE;
use error::ContactErrorKind as CEK; use error::ContactErrorKind as CEK;
use error::Result; use error::Result;
@ -38,10 +44,11 @@ pub trait ContactStore<'a> {
// creating // creating
fn create_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>>; fn create_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>>;
fn retrieve_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>>;
/// Create contact ref from buffer fn create_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>>;
fn create_from_buf(&'a self, buf: &String) -> Result<FileLockEntry<'a>>; fn retrieve_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>>;
// getting // getting
@ -55,12 +62,19 @@ impl<'a> ContactStore<'a> for Store {
util::read_to_string(p).and_then(|buf| self.create_from_buf(&buf)) util::read_to_string(p).and_then(|buf| self.create_from_buf(&buf))
} }
/// Create contact ref from buffer fn retrieve_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>> {
fn create_from_buf(&'a self, buf: &String) -> Result<FileLockEntry<'a>> { util::read_to_string(p).and_then(|buf| self.retrieve_from_buf(&buf))
let component = parse_component(&buf)?; }
debug!("Parsed: {:?}", component);
unimplemented!() /// Create contact ref from buffer
fn create_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>> {
let (sid, value) = prepare_fetching_from_store(buf)?;
postprocess_fetched_entry(self.create(sid)?, value)
}
fn retrieve_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>> {
let (sid, value) = prepare_fetching_from_store(buf)?;
postprocess_fetched_entry(self.retrieve(sid)?, value)
} }
fn all_contacts(&'a self) -> Result<StoreIdIterator> { fn all_contacts(&'a self) -> Result<StoreIdIterator> {
@ -74,3 +88,30 @@ impl<'a> ContactStore<'a> for Store {
} }
/// Prepare the fetching from the store.
///
/// That means calculating the StoreId and the Value from the vcard data
fn prepare_fetching_from_store(buf: &str) -> Result<(StoreId, Value)> {
let vcard = Vcard::build(&buf)?;
debug!("Parsed: {:?}", vcard);
let uid = vcard.uid().ok_or_else(|| CE::from_kind(CEK::UidMissing(buf.to_string())))?;
let value = { // dirty ugly hack
let serialized = DeserVcard::from(vcard);
let serialized = toml_to_string(&serialized)?;
toml_from_str::<Value>(&serialized)?
};
let sid = ModuleEntryPath::new(uid.raw()).into_storeid()?;
Ok((sid, value))
}
/// Postprocess the entry just fetched from the store
fn postprocess_fetched_entry<'a>(mut entry: FileLockEntry<'a>, value: Value) -> Result<FileLockEntry<'a>> {
entry.set_isflag::<IsContact>()?;
entry.get_header_mut().insert("contact.data", value)?;
Ok(entry)
}

View file

@ -24,8 +24,6 @@ use std::io::Read;
use error::Result; use error::Result;
use vobject::Component;
pub fn read_to_string<A: AsRef<Path> + Debug>(pb: A) -> Result<String> { pub fn read_to_string<A: AsRef<Path> + Debug>(pb: A) -> Result<String> {
let mut cont = String::new(); let mut cont = String::new();
@ -37,9 +35,3 @@ pub fn read_to_string<A: AsRef<Path> + Debug>(pb: A) -> Result<String> {
Ok(cont) Ok(cont)
} }
/// Helper for chaining results nicely
pub fn parse(buf: String) -> Result<Component> {
use vobject::parse_component;
parse_component(&buf).map_err(From::from)
}