From 6d79491e32d38686145eb066894d06be61d57bff Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Sun, 10 May 2020 19:04:14 +0100 Subject: [PATCH] Rework to get a map of connections in ConnectionManager --- Cargo.lock | 1 + Cargo.toml | 3 +- src/main.rs | 65 ++++++++++++++++++-------- src/padfoot.rs | 3 ++ src/padfoot/connection.rs | 53 +++++++++++++++++++++ src/padfoot/connection_manager.rs | 78 ++++++++++++++++++++++++------- src/padfoot/protocol.rs | 12 +++-- 7 files changed, 175 insertions(+), 40 deletions(-) create mode 100644 src/padfoot/connection.rs diff --git a/Cargo.lock b/Cargo.lock index c1eff57..ff0a61b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2647,6 +2647,7 @@ dependencies = [ "anyhow", "dbus", "deltachat", + "rand 0.7.3", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 443d35e..e1e760f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,8 +9,9 @@ license = "MIT" [dependencies] anyhow = "1.0" -dbus = "0.8.2" +dbus = "0.8" deltachat = { git = "https://github.com/deltachat/deltachat-core-rust", tag="1.31.0" } +rand = "0.7" [profile.release] lto = true diff --git a/src/main.rs b/src/main.rs index 1946a37..e5b03c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,22 +6,50 @@ use dbus::{ blocking::{stdintf::org_freedesktop_dbus::RequestNameReply, LocalConnection}, tree::Factory, }; -use padfoot::{ConnectionManager, Protocol}; +use padfoot::{ + Connection, ConnectionManager, Protocol, CM_BUS_NAME, CM_CONN_BUS_NAME, CM_OBJECT_PATH, + CONN_BUS_NAME, PROTO_BUS_NAME, PROTO_OBJECT_PATH, +}; +use std::sync::Arc; use std::time::Duration; -const CM_BUS_NAME: &'static str = "org.freedesktop.Telepathy.ConnectionManager.padfoot"; -const CM_OBJECT_PATH: &'static str = "/org/freedesktop/Telepathy/ConnectionManager/padfoot"; -const PROTO_OBJECT_PATH: &'static str = - "/org/freedesktop/Telepathy/ConnectionManager/padfoot/delta"; +#[derive(Debug, Default)] +struct TData { + cm: ConnectionManager, + p: Protocol, +} + +impl dbus::tree::DataType for TData { + type Interface = Arc; + type Tree = (); + type Property = (); + type ObjectPath = (); + + type Method = (); + type Signal = (); +} fn run() -> Result<()> { - let f = Factory::new_fn::<()>(); + let cm = ConnectionManager::new(); + let proto = Protocol {}; + let data = Arc::new(TData { cm: cm, p: proto }); + + let f = Factory::new_fn::(); let mut tree = f.tree(()); - let proto: &'static Protocol = &Protocol {}; - let cm: &'static ConnectionManager = &ConnectionManager {}; - let cm_iface = telepathy::connection_manager_server(&f, (), move |_m| cm); - let proto_iface = telepathy::protocol_server(&f, (), move |_m| proto); + let cm_iface = telepathy::connection_manager_server(&f, Arc::clone(&data), |m| { + let a: &Arc = &m.iface.get_data(); + let b: &TData = &a; + + &b.cm + }); + + let proto_iface = telepathy::protocol_server(&f, Arc::clone(&data), |m| { + let a: &Arc = &m.iface.get_data(); + let b: &TData = &a; + + &b.p + }); tree = tree.add( f.object_path(CM_OBJECT_PATH, ()) @@ -40,16 +68,15 @@ fn run() -> Result<()> { let mut c = LocalConnection::new_session()?; tree.start_receive(&c); - let result = c.request_name(CM_BUS_NAME, false, false, true)?; - match result { - RequestNameReply::Exists => { - return Err(anyhow!( - "Another process is already registered on {}", - CM_BUS_NAME - )) + for name in vec![CM_BUS_NAME, PROTO_BUS_NAME, CM_CONN_BUS_NAME, CONN_BUS_NAME] { + let result = c.request_name(name, false, false, true)?; + match result { + RequestNameReply::Exists => { + return Err(anyhow!("Another process is already registered on {}", name)) + } + _ => println!("{} listening on {}", c.unique_name(), name), // All other responses we can get are a success } - _ => println!("{} listening on {}", c.unique_name(), CM_BUS_NAME), // All other responses we can get are a success - }; + } loop { c.process(Duration::from_secs(1))?; diff --git a/src/padfoot.rs b/src/padfoot.rs index 3c6feb2..de26bd3 100644 --- a/src/padfoot.rs +++ b/src/padfoot.rs @@ -1,3 +1,6 @@ +mod connection; +pub use self::connection::*; + mod connection_manager; pub use self::connection_manager::*; diff --git a/src/padfoot/connection.rs b/src/padfoot/connection.rs new file mode 100644 index 0000000..ec01aa2 --- /dev/null +++ b/src/padfoot/connection.rs @@ -0,0 +1,53 @@ +use rand::Rng; + +use std::collections::HashMap; + +pub const CONN_BUS_NAME: &'static str = "org.freedesktop.Telepathy.Connection.padfoot.delta"; +pub const CONN_OBJECT_PATH: &'static str = "org/freedesktop/Telepathy/Connection/padfoot/delta"; + +#[derive(Debug)] +pub struct Connection { + path: String, + account: String, + password: String, +} + +impl Connection { + pub fn new(params: HashMap<&str, super::Variant>) -> Result { + let err = Err(dbus::tree::MethodErr::no_arg()); + + // Generate a unique identifier for this connection + let id = rand::thread_rng() + .sample_iter(&rand::distributions::Alphanumeric) + .take(16) + .collect::(); + + let path = super::CONN_OBJECT_PATH.to_owned() + "/" + &id; + + let acct = match params.get("account") { + Some(variant) => match variant.0.as_str() { + Some(str) => str.to_string(), + None => return err, + }, + None => return err, + }; + + let password = match params.get("password") { + Some(variant) => match variant.0.as_str() { + Some(str) => str.to_string(), + None => return err, + }, + None => return err, + }; + + Ok(Connection { + path: path, + account: acct, + password: password, + }) + } + + pub fn path(&self) -> String { + return self.path.to_owned(); + } +} diff --git a/src/padfoot/connection_manager.rs b/src/padfoot/connection_manager.rs index ec877c8..e698efc 100644 --- a/src/padfoot/connection_manager.rs +++ b/src/padfoot/connection_manager.rs @@ -1,19 +1,61 @@ use crate::telepathy; + use dbus::{arg, tree}; use std::collections::HashMap; +use std::sync::Mutex; -// FIXME: CM should take an opaque set of protocols to advertise -use super::protocol; +pub const CM_BUS_NAME: &'static str = "org.freedesktop.Telepathy.ConnectionManager.padfoot"; +pub const CM_CONN_BUS_NAME: &'static str = "org.freedesktop.Telepathy.Connection.padfoot"; +pub const CM_OBJECT_PATH: &'static str = "/org/freedesktop/Telepathy/ConnectionManager/padfoot"; #[derive(Debug)] -pub struct ConnectionManager {} +pub struct ConnectionManager { + conns: Mutex>, // FIXME: remove mutex if we can +} + +impl Default for ConnectionManager { + fn default() -> Self { + ConnectionManager { + conns: Mutex::new(HashMap::new()), + } + } +} + +impl ConnectionManager { + pub fn new() -> Self { + Default::default() + } + + fn new_connection( + &self, + params: HashMap<&str, super::Variant>, + ) -> Result<(String, dbus::Path<'static>), tree::MethodErr> { + let conn = super::Connection::new(params)?; + let path = conn.path(); + + let mut conns = self.conns.lock().expect("mutex should be lockable"); + + conns.insert(path.to_owned(), conn); + + // TODO: register new object path + bus name + // Will this be easier if I give each one its own dbus connection? + + // FIXME: does the bus name matter? Is it used for client recovery? + // Maybe it should be org.freedesktop.Telepathy.Connection.padfoot.delta.? + Ok(( + CM_CONN_BUS_NAME.to_string(), + dbus::strings::Path::new(path).expect("Object path should meet DBUS requirements"), + )) + // Err(tree::MethodErr::no_arg()) + } +} impl telepathy::ConnectionManager for ConnectionManager { - fn get_parameters(&self, protocol: &str) -> Result, tree::MethodErr> { + fn get_parameters(&self, protocol: &str) -> Result, tree::MethodErr> { println!("CM::get_parameters({})", protocol); match protocol { - protocol::NAME => Ok(protocol::parameters()), + super::PROTO_NAME => Ok(super::parameters()), _ => Err(tree::MethodErr::no_arg()), // FIXME: should be NotImplemented? } } @@ -21,27 +63,31 @@ impl telepathy::ConnectionManager for ConnectionManager { fn list_protocols(&self) -> Result, tree::MethodErr> { println!("CM::list_protocols()"); - Ok(vec![protocol::NAME.to_string()]) + Ok(vec![super::PROTO_NAME.to_string()]) } fn request_connection( &self, protocol: &str, - parameters: HashMap<&str, protocol::Variant>, + params: HashMap<&str, super::Variant>, ) -> Result<(String, dbus::Path<'static>), tree::MethodErr> { - println!("CM::request_connection({}, {:?})", protocol, parameters); + println!("CM::request_connection({}, {:?})", protocol, params); - Err(tree::MethodErr::no_arg()) + match protocol { + super::PROTO_NAME => self.new_connection(params), + _ => Err(tree::MethodErr::no_arg()), // FIXME: should be NotImplemented? + } } fn protocols( &self, - ) -> Result>, tree::MethodErr> { + ) -> Result>, tree::MethodErr> { println!("CM::protocols()"); - // FIXME: so much duplication - let mut out = HashMap::>::new(); - let mut props = HashMap::::new(); + // FIXME: so much duplication. It would be good if we could get the + // properties from the Protocol instead + let mut out = HashMap::>::new(); + let mut props = HashMap::::new(); props.insert( "org.freedesktop.Telepathy.Protocol.AuthenticationTypes".to_string(), @@ -71,18 +117,18 @@ impl telepathy::ConnectionManager for ConnectionManager { ); props.insert( "org.freedesktop.Telepathy.Protocol.Parameters".to_string(), - arg::Variant(Box::new(protocol::parameters())), + arg::Variant(Box::new(super::parameters())), ); props.insert( "org.freedesktop.Telepathy.Protocol.RequestableChannelClasses".to_string(), - arg::Variant(Box::new(protocol::requestables())), + arg::Variant(Box::new(super::requestables())), ); props.insert( "org.freedesktop.Telepathy.Protocol.VCardField".to_string(), arg::Variant(Box::new("email".to_string())), ); - out.insert(protocol::NAME.to_string(), props); + out.insert(super::PROTO_NAME.to_string(), props); Ok(out) } diff --git a/src/padfoot/protocol.rs b/src/padfoot/protocol.rs index dbdde17..f26de4a 100644 --- a/src/padfoot/protocol.rs +++ b/src/padfoot/protocol.rs @@ -2,7 +2,13 @@ use crate::telepathy; use dbus::{arg, tree}; use std::collections::HashMap; -#[derive(Debug)] +pub const PROTO_OBJECT_PATH: &'static str = + "/org/freedesktop/Telepathy/ConnectionManager/padfoot/delta"; +pub const PROTO_BUS_NAME: &'static str = + "org.freedesktop.Telepathy.ConnectionManager.padfoot.delta"; + +pub const PROTO_NAME: &'static str = "delta"; +#[derive(Clone, Copy, Default, Debug)] pub struct Protocol {} pub type Variant = arg::Variant>; @@ -14,14 +20,12 @@ pub type ParamSpec = ( Variant, // Default ); +// Requestable_Channel_Class pub type RequestableChannelSpec = ( - // Requestable_Channel_Class HashMap, // Fixed properties Vec, // Allowed properties ); -pub const NAME: &'static str = "delta"; - // FIXME: these should come from codegen //const FLAG_NONE: u32 = 0; const FLAG_REQUIRED: u32 = 1;