Track connection state and implement more properties
Empathy still doesn't show us as connected. I think we need to add the Requests and Contacts interfaces (which we're advertising as a minimal requirement, but not implementing) before it will.
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
use crate::telepathy;
|
use crate::telepathy;
|
||||||
use dbus::blocking::{stdintf::org_freedesktop_dbus::RequestNameReply, LocalConnection};
|
use dbus::blocking::{stdintf::org_freedesktop_dbus::RequestNameReply, LocalConnection};
|
||||||
|
use dbus::channel::Sender;
|
||||||
|
use dbus::message::SignalArgs;
|
||||||
use dbus::tree;
|
use dbus::tree;
|
||||||
|
|
||||||
use dc::config::Config;
|
use dc::config::Config;
|
||||||
@@ -7,22 +9,30 @@ use dc::context::Context;
|
|||||||
use dc::Event;
|
use dc::Event;
|
||||||
use deltachat as dc;
|
use deltachat as dc;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, VecDeque};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
pub const CONN_BUS_NAME: &'static str = "org.freedesktop.Telepathy.Connection.padfoot.delta";
|
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";
|
pub const CONN_OBJECT_PATH: &'static str = "/org/freedesktop/Telepathy/Connection/padfoot/delta";
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
enum ConnState {
|
||||||
|
Initial,
|
||||||
|
Connected,
|
||||||
|
Disconnected,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Connection {
|
pub struct Connection {
|
||||||
id: String,
|
id: String,
|
||||||
ctx: Arc<RwLock<Context>>,
|
ctx: Arc<RwLock<Context>>,
|
||||||
|
|
||||||
// set to false when disconnect() is called. Note that it is true even
|
state: Arc<RwLock<ConnState>>,
|
||||||
// before connect() is called
|
|
||||||
disconnected: Arc<RwLock<bool>>,
|
// Used for sending out messages
|
||||||
|
msgq: Arc<Mutex<VecDeque<dbus::Message>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Connection {
|
impl Connection {
|
||||||
@@ -55,7 +65,10 @@ impl Connection {
|
|||||||
dbfile.push("db.sqlite3");
|
dbfile.push("db.sqlite3");
|
||||||
|
|
||||||
// FIXME: how to give it access to the connection (initialized later)?
|
// FIXME: how to give it access to the connection (initialized later)?
|
||||||
|
let msgq = Arc::new(Mutex::new(VecDeque::<dbus::Message>::new()));
|
||||||
|
|
||||||
let id2 = id.clone();
|
let id2 = id.clone();
|
||||||
|
let msgq2 = msgq.clone();
|
||||||
let f = move |_c: &Context, e: Event| {
|
let f = move |_c: &Context, e: Event| {
|
||||||
match e {
|
match e {
|
||||||
Event::Info(msg) => println!("Connection<{}>: INFO: {}", id2, msg),
|
Event::Info(msg) => println!("Connection<{}>: INFO: {}", id2, msg),
|
||||||
@@ -63,6 +76,32 @@ impl Connection {
|
|||||||
Event::Error(msg) | Event::ErrorNetwork(msg) | Event::ErrorSelfNotInGroup(msg) => {
|
Event::Error(msg) | Event::ErrorNetwork(msg) | Event::ErrorSelfNotInGroup(msg) => {
|
||||||
println!("Connection<{}>: ERR : {}", id2, msg)
|
println!("Connection<{}>: ERR : {}", id2, msg)
|
||||||
}
|
}
|
||||||
|
Event::ConfigureProgress(progress) => {
|
||||||
|
println!("Connection<{}>: Configuration progress: {}", id2, progress)
|
||||||
|
}
|
||||||
|
Event::ImapConnected(msg) | Event::SmtpConnected(msg) => {
|
||||||
|
println!("Connection<{}>: Network: {}", id2, msg);
|
||||||
|
}
|
||||||
|
/* Unhandled messages:
|
||||||
|
SmtpMessageSent(String),
|
||||||
|
ImapMessageDeleted(String),
|
||||||
|
ImapMessageMoved(String),
|
||||||
|
ImapFolderEmptied(String),
|
||||||
|
NewBlobFile(String),
|
||||||
|
DeletedBlobFile(String),
|
||||||
|
MsgsChanged
|
||||||
|
IncomingMsg
|
||||||
|
MsgDelivered
|
||||||
|
MsgFailed
|
||||||
|
MsgRead
|
||||||
|
ChatModified(ChatId),
|
||||||
|
ContactsChanged(Option<u32>),
|
||||||
|
LocationChanged(Option<u32>),
|
||||||
|
ImexProgress(usize),
|
||||||
|
ImexFileWritten(PathBuf),
|
||||||
|
SecurejoinInviterProgress
|
||||||
|
SecurejoinJoinerProgress
|
||||||
|
*/
|
||||||
_ => println!("Connection<{}>: unhandled event received: {:?}", id2, e),
|
_ => println!("Connection<{}>: unhandled event received: {:?}", id2, e),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -87,7 +126,8 @@ impl Connection {
|
|||||||
Ok(Connection {
|
Ok(Connection {
|
||||||
id: id,
|
id: id,
|
||||||
ctx: Arc::new(RwLock::new(ctx)),
|
ctx: Arc::new(RwLock::new(ctx)),
|
||||||
disconnected: Arc::new(RwLock::new(false)),
|
state: Arc::new(RwLock::new(ConnState::Initial)),
|
||||||
|
msgq: msgq.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +138,9 @@ impl Connection {
|
|||||||
pub fn run(self) {
|
pub fn run(self) {
|
||||||
let bus = self.bus();
|
let bus = self.bus();
|
||||||
let path = self.path();
|
let path = self.path();
|
||||||
let disconnected = self.disconnected.clone();
|
let state = self.state.clone();
|
||||||
|
let msgq = self.msgq.clone();
|
||||||
|
let id = self.id.clone();
|
||||||
let c_rc = std::rc::Rc::new(self);
|
let c_rc = std::rc::Rc::new(self);
|
||||||
|
|
||||||
let f = tree::Factory::new_fn::<()>();
|
let f = tree::Factory::new_fn::<()>();
|
||||||
@@ -134,7 +176,7 @@ impl Connection {
|
|||||||
|
|
||||||
// Set up delta jobs last in case registering to DBUS fails
|
// Set up delta jobs last in case registering to DBUS fails
|
||||||
// "Borrowed" from https://github.com/deltachat/deltachat-core-rust/blob/master/examples/simple.rs
|
// "Borrowed" from https://github.com/deltachat/deltachat-core-rust/blob/master/examples/simple.rs
|
||||||
while !*disconnected.read().unwrap() {
|
while *state.read().unwrap() != ConnState::Disconnected {
|
||||||
match c.process(Duration::from_millis(100)) {
|
match c.process(Duration::from_millis(100)) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Error processing: {}", e);
|
println!("Error processing: {}", e);
|
||||||
@@ -142,6 +184,20 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Spend a bit of time sending any outgoing messages - signals, mostly
|
||||||
|
loop {
|
||||||
|
let msg = match msgq.lock().unwrap().pop_front() {
|
||||||
|
Some(msg) => msg,
|
||||||
|
None => break,
|
||||||
|
};
|
||||||
|
|
||||||
|
print!("Connection<{}>: Sending message...", id);
|
||||||
|
match c.send(msg) {
|
||||||
|
Err(e) => println!("error! {:?}", e),
|
||||||
|
_ => println!("OK!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: clean up, emit disconnected signal. Join on threads started in
|
// TODO: clean up, emit disconnected signal. Join on threads started in
|
||||||
@@ -169,14 +225,14 @@ impl telepathy::Connection for Connection {
|
|||||||
println!("Connection<{}>::connect()", self.id);
|
println!("Connection<{}>::connect()", self.id);
|
||||||
|
|
||||||
let inbox_ctx = self.ctx.clone();
|
let inbox_ctx = self.ctx.clone();
|
||||||
let disconnected = self.disconnected.clone();
|
let state = self.state.clone();
|
||||||
let _inbox_thread = thread::spawn(move || {
|
let _inbox_thread = thread::spawn(move || {
|
||||||
while !*disconnected.read().unwrap() {
|
while *state.read().unwrap() != ConnState::Disconnected {
|
||||||
dc::job::perform_inbox_jobs(&inbox_ctx.read().unwrap());
|
dc::job::perform_inbox_jobs(&inbox_ctx.read().unwrap());
|
||||||
if !*disconnected.read().unwrap() {
|
if *state.read().unwrap() != ConnState::Disconnected {
|
||||||
dc::job::perform_inbox_fetch(&inbox_ctx.read().unwrap());
|
dc::job::perform_inbox_fetch(&inbox_ctx.read().unwrap());
|
||||||
|
|
||||||
if !*disconnected.read().unwrap() {
|
if *state.read().unwrap() != ConnState::Disconnected {
|
||||||
dc::job::perform_inbox_idle(&inbox_ctx.read().unwrap());
|
dc::job::perform_inbox_idle(&inbox_ctx.read().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,64 +240,120 @@ impl telepathy::Connection for Connection {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let smtp_ctx = self.ctx.clone();
|
let smtp_ctx = self.ctx.clone();
|
||||||
let disconnected = self.disconnected.clone();
|
let state = self.state.clone();
|
||||||
let _smtp_thread = thread::spawn(move || {
|
let _smtp_thread = thread::spawn(move || {
|
||||||
while !*disconnected.read().unwrap() {
|
while *state.read().unwrap() != ConnState::Disconnected {
|
||||||
dc::job::perform_smtp_jobs(&smtp_ctx.read().unwrap());
|
dc::job::perform_smtp_jobs(&smtp_ctx.read().unwrap());
|
||||||
if !*disconnected.read().unwrap() {
|
if *state.read().unwrap() != ConnState::Disconnected {
|
||||||
dc::job::perform_smtp_idle(&smtp_ctx.read().unwrap());
|
dc::job::perform_smtp_idle(&smtp_ctx.read().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let mvbox_ctx = self.ctx.clone();
|
let mvbox_ctx = self.ctx.clone();
|
||||||
let disconnected = self.disconnected.clone();
|
let state = self.state.clone();
|
||||||
let _mvbox_thread = thread::spawn(move || {
|
let _mvbox_thread = thread::spawn(move || {
|
||||||
while !*disconnected.read().unwrap() {
|
while *state.read().unwrap() != ConnState::Disconnected {
|
||||||
dc::job::perform_mvbox_fetch(&mvbox_ctx.read().unwrap());
|
dc::job::perform_mvbox_fetch(&mvbox_ctx.read().unwrap());
|
||||||
if !*disconnected.read().unwrap() {
|
if *state.read().unwrap() != ConnState::Disconnected {
|
||||||
dc::job::perform_mvbox_idle(&mvbox_ctx.read().unwrap());
|
dc::job::perform_mvbox_idle(&mvbox_ctx.read().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let sentbox_ctx = self.ctx.clone();
|
let sentbox_ctx = self.ctx.clone();
|
||||||
let disconnected = self.disconnected.clone();
|
let state = self.state.clone();
|
||||||
let _sentbox_thread = thread::spawn(move || {
|
let _sentbox_thread = thread::spawn(move || {
|
||||||
while !*disconnected.read().unwrap() {
|
while *state.read().unwrap() != ConnState::Disconnected {
|
||||||
dc::job::perform_sentbox_fetch(&sentbox_ctx.read().unwrap());
|
dc::job::perform_sentbox_fetch(&sentbox_ctx.read().unwrap());
|
||||||
if !*disconnected.read().unwrap() {
|
if *state.read().unwrap() != ConnState::Disconnected {
|
||||||
dc::job::perform_sentbox_idle(&sentbox_ctx.read().unwrap());
|
dc::job::perform_sentbox_idle(&sentbox_ctx.read().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Just pretend to be connected all the time for now. Tracking IMAP+SMTP
|
||||||
|
// state is a pain
|
||||||
|
let state = self.state.clone();
|
||||||
|
let mut w = state.write().unwrap();
|
||||||
|
*w = ConnState::Connected;
|
||||||
|
|
||||||
|
// Emit a NewConnection signal for the benefit of others, but the caller
|
||||||
|
// learns from our RPC response
|
||||||
|
let sig = telepathy::ConnectionStatusChanged {
|
||||||
|
status: 0, // Connected
|
||||||
|
reason: 1, // Requested
|
||||||
|
};
|
||||||
|
|
||||||
|
let dbus_conn_path = dbus::strings::Path::new(CONN_OBJECT_PATH.to_string())
|
||||||
|
.expect("Object path should meet DBUS requirements");
|
||||||
|
|
||||||
|
self.msgq
|
||||||
|
.clone()
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.push_back(sig.to_emit_message(&dbus_conn_path));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disconnect(&self) -> Result<(), tree::MethodErr> {
|
fn disconnect(&self) -> Result<(), tree::MethodErr> {
|
||||||
println!("Connection<{}>::disconnect()", self.id);
|
println!("Connection<{}>::disconnect()", self.id);
|
||||||
Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
|
||||||
|
let state = self.state.clone();
|
||||||
|
let mut w = state.write().unwrap();
|
||||||
|
*w = ConnState::Disconnected;
|
||||||
|
|
||||||
|
// FIXME: we need to signal to the CM that they should remove the
|
||||||
|
// connection from the active list
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interfaces(&self) -> Result<Vec<String>, tree::MethodErr> {
|
||||||
|
println!("Connection<{}>::interfaces()", self.id);
|
||||||
|
|
||||||
|
self.get_interfaces()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_interfaces(&self) -> Result<Vec<String>, tree::MethodErr> {
|
fn get_interfaces(&self) -> Result<Vec<String>, tree::MethodErr> {
|
||||||
println!("Connection<{}>::get_interfaces()", self.id);
|
println!("Connection<{}>::get_interfaces()", self.id);
|
||||||
Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
|
||||||
|
Ok(vec![
|
||||||
|
"org.freedesktop.Telepathy.Connection.Interface.Contacts".to_string(),
|
||||||
|
"org.freedesktop.Telepathy.Connection.Interface.Requests".to_string(),
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_protocol(&self) -> Result<String, tree::MethodErr> {
|
fn get_protocol(&self) -> Result<String, tree::MethodErr> {
|
||||||
println!("Connection<{}>::get_protocol()", self.id);
|
println!("Connection<{}>::get_protocol()", self.id);
|
||||||
|
|
||||||
Ok(super::PROTO_NAME.to_string())
|
Ok(super::PROTO_NAME.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn self_handle(&self) -> Result<u32, tree::MethodErr> {
|
||||||
|
println!("Connection<{}>::self_handle()", self.id);
|
||||||
|
|
||||||
|
self.get_self_handle()
|
||||||
|
}
|
||||||
|
|
||||||
fn get_self_handle(&self) -> Result<u32, tree::MethodErr> {
|
fn get_self_handle(&self) -> Result<u32, tree::MethodErr> {
|
||||||
println!("Connection<{}>::get_self_handle()", self.id);
|
println!("Connection<{}>::get_self_handle()", self.id);
|
||||||
Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
|
||||||
|
Ok(deltachat::constants::DC_CONTACT_ID_SELF)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn status(&self) -> Result<u32, tree::MethodErr> {
|
||||||
|
println!("Connection<{}>::status()", self.id);
|
||||||
|
|
||||||
|
self.get_status()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_status(&self) -> Result<u32, tree::MethodErr> {
|
fn get_status(&self) -> Result<u32, tree::MethodErr> {
|
||||||
println!("Connection<{}>::get_status()", self.id);
|
match *self.state.clone().read().unwrap() {
|
||||||
Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
ConnState::Initial | ConnState::Disconnected => Ok(2),
|
||||||
|
ConnState::Connected => Ok(0),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hold_handles(&self, handle_type: u32, handles: Vec<u32>) -> Result<(), tree::MethodErr> {
|
fn hold_handles(&self, handle_type: u32, handles: Vec<u32>) -> Result<(), tree::MethodErr> {
|
||||||
@@ -318,28 +430,15 @@ impl telepathy::Connection for Connection {
|
|||||||
Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interfaces(&self) -> Result<Vec<String>, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::interfaces()", self.id);
|
|
||||||
Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
|
||||||
}
|
|
||||||
|
|
||||||
fn self_handle(&self) -> Result<u32, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::self_handle()", self.id);
|
|
||||||
Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
|
||||||
}
|
|
||||||
|
|
||||||
fn self_id(&self) -> Result<String, tree::MethodErr> {
|
fn self_id(&self) -> Result<String, tree::MethodErr> {
|
||||||
println!("Connection<{}>::self_id()", self.id);
|
println!("Connection<{}>::self_id()", self.id);
|
||||||
Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
|
||||||
}
|
|
||||||
|
|
||||||
fn status(&self) -> Result<u32, tree::MethodErr> {
|
Ok("Yourself".to_string()) // FIXME: this could be passed through config
|
||||||
println!("Connection<{}>::status()", self.id);
|
|
||||||
Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_immortal_handles(&self) -> Result<bool, tree::MethodErr> {
|
fn has_immortal_handles(&self) -> Result<bool, tree::MethodErr> {
|
||||||
println!("Connection<{}>::has_immortal_handles()", self.id);
|
println!("Connection<{}>::has_immortal_handles()", self.id);
|
||||||
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user