Rework to get a map of connections in ConnectionManager

This commit is contained in:
2020-05-10 19:04:14 +01:00
parent 04bf72637d
commit 6d79491e32
7 changed files with 175 additions and 40 deletions

1
Cargo.lock generated
View File

@@ -2647,6 +2647,7 @@ dependencies = [
"anyhow",
"dbus",
"deltachat",
"rand 0.7.3",
]
[[package]]

View File

@@ -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

View File

@@ -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<TData>;
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::<TData>();
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<TData> = &m.iface.get_data();
let b: &TData = &a;
&b.cm
});
let proto_iface = telepathy::protocol_server(&f, Arc::clone(&data), |m| {
let a: &Arc<TData> = &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))?;

View File

@@ -1,3 +1,6 @@
mod connection;
pub use self::connection::*;
mod connection_manager;
pub use self::connection_manager::*;

53
src/padfoot/connection.rs Normal file
View File

@@ -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<Self, dbus::tree::MethodErr> {
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::<String>();
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();
}
}

View File

@@ -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<HashMap<String, super::Connection>>, // 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.<id>?
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<Vec<protocol::ParamSpec>, tree::MethodErr> {
fn get_parameters(&self, protocol: &str) -> Result<Vec<super::ParamSpec>, 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<Vec<String>, 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<HashMap<String, HashMap<String, protocol::Variant>>, tree::MethodErr> {
) -> Result<HashMap<String, HashMap<String, super::Variant>>, tree::MethodErr> {
println!("CM::protocols()");
// FIXME: so much duplication
let mut out = HashMap::<String, HashMap<String, protocol::Variant>>::new();
let mut props = HashMap::<String, protocol::Variant>::new();
// FIXME: so much duplication. It would be good if we could get the
// properties from the Protocol instead
let mut out = HashMap::<String, HashMap<String, super::Variant>>::new();
let mut props = HashMap::<String, super::Variant>::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)
}

View File

@@ -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<Box<dyn arg::RefArg + 'static>>;
@@ -14,14 +20,12 @@ pub type ParamSpec = (
Variant, // Default
);
// Requestable_Channel_Class
pub type RequestableChannelSpec = (
// Requestable_Channel_Class
HashMap<String, Variant>, // Fixed properties
Vec<String>, // Allowed properties
);
pub const NAME: &'static str = "delta";
// FIXME: these should come from codegen
//const FLAG_NONE: u32 = 0;
const FLAG_REQUIRED: u32 = 1;