Rewrite library
libimagcontact stores all contact information in the entry header now.
This commit is contained in:
parent
3eab3af7b0
commit
abc142f4b5
7 changed files with 88 additions and 71 deletions
|
@ -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"]
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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")]
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue