diff options
author | Manos Pitsidianakis <el13635@mail.ntua.gr> | 2020-01-02 00:13:18 +0200 |
---|---|---|
committer | Manos Pitsidianakis <el13635@mail.ntua.gr> | 2020-01-02 00:13:18 +0200 |
commit | f6de511abdafb4cb08c0264df6e2c88cf88faaab (patch) | |
tree | e7094232b99fad2b0f24ea1102f75cfd77f649a5 /ui/src/plugins/backend.rs | |
parent | beeea9a0c10e9e0480ed51cd44ba9f440ce56682 (diff) |
plugin-backend: add BackendOp for PluginBackend
Diffstat (limited to 'ui/src/plugins/backend.rs')
-rw-r--r-- | ui/src/plugins/backend.rs | 169 |
1 files changed, 153 insertions, 16 deletions
diff --git a/ui/src/plugins/backend.rs b/ui/src/plugins/backend.rs index 2cd701c3..e1062ca0 100644 --- a/ui/src/plugins/backend.rs +++ b/ui/src/plugins/backend.rs @@ -32,25 +32,53 @@ use melib::error::{MeliError, Result}; use std::collections::BTreeMap; use std::sync::{Arc, Mutex, RwLock}; +// TODO replace with melib::Envelope after simplifying melib::Envelope's +// fields/interface/deserializing +#[derive(Debug, Clone, Serialize, Deserialize)] +struct SimpleEnvelope { + hash: EnvelopeHash, + subject: String, + from: String, + to: String, + date: String, + message_id: String, + references: String, +} + #[derive(Debug)] pub struct PluginBackend { plugin: Plugin, child: std::process::Child, channel: Arc<Mutex<RpcChannel>>, + tag_index: Option<Arc<RwLock<BTreeMap<u64, String>>>>, is_online: Arc<Mutex<(std::time::Instant, Result<()>)>>, } +impl Drop for PluginBackend { + fn drop(&mut self) { + if let Err(err) = debug!(self.child.kill()) { + eprintln!( + "Error: could not kill process {} spawned by plugin {} ({})", + self.child.id(), + &self.plugin.name, + err + ); + } + } +} + impl MailBackend for PluginBackend { fn is_online(&self) -> Result<()> { if let Ok(mut is_online) = self.is_online.try_lock() { let now = std::time::Instant::now(); if now.duration_since(is_online.0) >= std::time::Duration::new(2, 0) { - let mut channel = self.channel.lock().unwrap(); - channel.write_ref(&rmpv::ValueRef::Ext(BACKEND_FN, b"is_online"))?; - debug!(channel.expect_ack())?; - let ret: PluginResult<()> = debug!(channel.from_read())?; - is_online.0 = now; - is_online.1 = ret.into(); + if let Ok(mut channel) = self.channel.try_lock() { + channel.write_ref(&rmpv::ValueRef::Ext(BACKEND_FN, b"is_online"))?; + debug!(channel.expect_ack())?; + let ret: PluginResult<()> = debug!(channel.from_read())?; + is_online.0 = now; + is_online.1 = ret.into(); + } } is_online.1.clone() } else { @@ -62,7 +90,7 @@ impl MailBackend for PluginBackend { fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> { let mut w = AsyncBuilder::new(); - let folder_hash = folder.hash(); + let _folder_hash = folder.hash(); let channel = self.channel.clone(); let handle = { let tx = w.tx(); @@ -73,13 +101,65 @@ impl MailBackend for PluginBackend { .unwrap(); channel.expect_ack().unwrap(); loop { - let read_val: Result<PluginResult<Option<Vec<String>>>> = + let read_val: Result<PluginResult<Option<Vec<SimpleEnvelope>>>> = debug!(channel.from_read()); match read_val.map(Into::into).and_then(std::convert::identity) { Ok(Some(a)) => { tx.send(AsyncStatus::Payload(Ok(a .into_iter() - .filter_map(|s| Envelope::from_bytes(s.as_bytes(), None).ok()) + .filter_map( + |SimpleEnvelope { + hash, + date, + from, + to, + subject, + message_id, + references, + }| { + let mut env = melib::Envelope::new(hash); + env.set_date(date.as_bytes()); + if let Ok(d) = melib::email::parser::date(date.as_bytes()) { + env.set_datetime(d); + } + env.set_message_id(message_id.as_bytes()); + let parse_result = + melib::email::parser::rfc2822address_list( + from.as_bytes(), + ); + if parse_result.is_done() { + let value = parse_result.to_full_result().unwrap(); + env.set_from(value); + } + let parse_result = + melib::email::parser::rfc2822address_list( + to.as_bytes(), + ); + if parse_result.is_done() { + let value = parse_result.to_full_result().unwrap(); + env.set_to(value); + } + let parse_result = + melib::email::parser::phrase(subject.as_bytes()); + if parse_result.is_done() { + let value = parse_result.to_full_result().unwrap(); + env.set_subject(value); + } + if !references.is_empty() { + let parse_result = melib::email::parser::references( + references.as_bytes(), + ); + if parse_result.is_done() { + for v in parse_result.to_full_result().unwrap() { + env.push_references(v); + } + } + env.set_references(references.as_bytes()); + } + + Some(env) + }, + ) .collect::<Vec<Envelope>>()))) .unwrap(); } @@ -109,28 +189,35 @@ impl MailBackend for PluginBackend { } fn watch( &self, - sender: RefreshEventConsumer, - work_context: WorkContext, + _sender: RefreshEventConsumer, + _work_context: WorkContext, ) -> Result<std::thread::ThreadId> { Err(MeliError::new("Unimplemented.")) } + fn folders(&self) -> Result<FnvHashMap<FolderHash, Folder>> { let mut ret: FnvHashMap<FolderHash, Folder> = Default::default(); ret.insert(0, Folder::default()); Ok(ret) } + fn operation(&self, hash: EnvelopeHash) -> Box<dyn BackendOp> { - unimplemented!() + Box::new(PluginOp { + hash, + channel: self.channel.clone(), + tag_index: self.tag_index.clone(), + bytes: None, + }) } - fn save(&self, bytes: &[u8], folder: &str, flags: Option<Flag>) -> Result<()> { + fn save(&self, _bytes: &[u8], _folder: &str, _flags: Option<Flag>) -> Result<()> { Err(MeliError::new("Unimplemented.")) } - fn create_folder(&mut self, name: String) -> Result<Folder> { + fn create_folder(&mut self, _name: String) -> Result<Folder> { Err(MeliError::new("Unimplemented.")) } fn tags(&self) -> Option<Arc<RwLock<BTreeMap<u64, String>>>> { - None + self.tag_index.clone() } fn as_any(&self) -> &dyn::std::any::Any { self @@ -156,7 +243,7 @@ impl PluginBackend { .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn()?; - let (mut stream, _) = listener.accept()?; + let (stream, _) = listener.accept()?; /* send init message to plugin to register hooks */ let session = Uuid::new_v4(); let channel = RpcChannel::new(stream, &session)?; @@ -166,6 +253,7 @@ impl PluginBackend { child, plugin, channel: Arc::new(Mutex::new(channel)), + tag_index: None, is_online: Arc::new(Mutex::new((now, Err(MeliError::new("Unitialized"))))), })) } @@ -188,3 +276,52 @@ impl PluginBackend { ); } } + +#[derive(Debug)] +struct PluginOp { + hash: EnvelopeHash, + channel: Arc<Mutex<RpcChannel>>, + tag_index: Option<Arc<RwLock<BTreeMap<u64, String>>>>, + bytes: Option<String>, +} + +impl BackendOp for PluginOp { + fn description(&self) -> String { + String::new() + } + + fn as_bytes(&mut self) -> Result<&[u8]> { + if let Some(ref bytes) = self.bytes { + return Ok(bytes.as_bytes()); + } + + if let Ok(mut channel) = self.channel.try_lock() { + channel.write_ref(&rmpv::ValueRef::Ext(BACKEND_OP_FN, b"as_bytes"))?; + debug!(channel.expect_ack())?; + channel.write_ref(&rmpv::ValueRef::Integer(self.hash.into()))?; + debug!(channel.expect_ack())?; + let bytes: Result<PluginResult<String>> = debug!(channel.from_read()); + self.bytes = Some(bytes.map(Into::into).and_then(std::convert::identity)?); + if let Some(ref bytes) = self.bytes { + debug!(Envelope::from_bytes(bytes.as_bytes(), None)); + } + Ok(self.bytes.as_ref().map(String::as_bytes).unwrap()) + } else { + Err(MeliError::new("busy")) + } + } + + fn fetch_flags(&self) -> Flag { + let flag = Flag::default(); + + flag + } + + fn set_flag(&mut self, __envelope: &mut Envelope, _f: Flag, _value: bool) -> Result<()> { + Err(MeliError::new("Unimplemented.")) + } + + fn set_tag(&mut self, _envelope: &mut Envelope, _tag: String, _value: bool) -> Result<()> { + Err(MeliError::new("Unimplemented.")) + } +} |