update ffi

This commit is contained in:
dignifiedquire
2020-01-29 15:44:20 +01:00
parent 41a7e06332
commit e93911effb
4 changed files with 105 additions and 103 deletions

View File

@@ -243,7 +243,7 @@ typedef uintptr_t (*dc_callback_t) (dc_context_t* context, int event, uintptr_t
* The object must be passed to the other context functions * The object must be passed to the other context functions
* and must be freed using dc_context_unref() after usage. * and must be freed using dc_context_unref() after usage.
*/ */
dc_context_t* dc_context_new (dc_callback_t cb, void* userdata, const char* os_name); dc_context_t* dc_context_new (void* userdata, const char* os_name);
/** /**
@@ -540,12 +540,12 @@ int dc_is_configured (const dc_context_t* context);
/** /**
* TODO: Document * TODO: Document
*/ */
void dc_run (dc_context_t* context); void dc_context_run (dc_context_t* context, dc_callback_t cb);
/** /**
* TODO: Document * TODO: Document
*/ */
void dc_shutdown (dc_context_t* context); void dc_context_shutdown (dc_context_t* context);
/** /**
* This function can be called whenever there is a hint * This function can be called whenever there is a hint

View File

@@ -57,7 +57,6 @@ use self::string::*;
/// and protected by an [RwLock]. Other than that it needs to store /// and protected by an [RwLock]. Other than that it needs to store
/// the data which is passed into [dc_context_new]. /// the data which is passed into [dc_context_new].
pub struct ContextWrapper { pub struct ContextWrapper {
cb: Option<dc_callback_t>,
userdata: *mut libc::c_void, userdata: *mut libc::c_void,
os_name: String, os_name: String,
inner: RwLock<Option<context::Context>>, inner: RwLock<Option<context::Context>>,
@@ -91,7 +90,10 @@ impl ContextWrapper {
/// ///
/// This function makes it easy to log an error. /// This function makes it easy to log an error.
unsafe fn error(&self, msg: &str) { unsafe fn error(&self, msg: &str) {
self.translate_cb(Event::Error(msg.to_string())); self.with_inner(|ctx| {
ctx.call_cb(Event::Error(msg.to_string()));
})
.unwrap();
} }
/// Unlock the context and execute a closure with it. /// Unlock the context and execute a closure with it.
@@ -122,88 +124,10 @@ impl ContextWrapper {
} }
} }
} }
/// Translates the callback from the rust style to the C-style version.
unsafe fn translate_cb(&self, event: Event) {
if let Some(ffi_cb) = self.cb {
let event_id = event.as_id();
match event {
Event::Info(msg)
| Event::SmtpConnected(msg)
| Event::ImapConnected(msg)
| Event::SmtpMessageSent(msg)
| Event::ImapMessageDeleted(msg)
| Event::ImapMessageMoved(msg)
| Event::ImapFolderEmptied(msg)
| Event::NewBlobFile(msg)
| Event::DeletedBlobFile(msg)
| Event::Warning(msg)
| Event::Error(msg)
| Event::ErrorNetwork(msg)
| Event::ErrorSelfNotInGroup(msg) => {
let data2 = CString::new(msg).unwrap_or_default();
ffi_cb(self, event_id, 0, data2.as_ptr() as uintptr_t);
}
Event::MsgsChanged { chat_id, msg_id }
| Event::IncomingMsg { chat_id, msg_id }
| Event::MsgDelivered { chat_id, msg_id }
| Event::MsgFailed { chat_id, msg_id }
| Event::MsgRead { chat_id, msg_id } => {
ffi_cb(
self,
event_id,
chat_id.to_u32() as uintptr_t,
msg_id.to_u32() as uintptr_t,
);
}
Event::ChatModified(chat_id) => {
ffi_cb(self, event_id, chat_id.to_u32() as uintptr_t, 0);
}
Event::ContactsChanged(id) | Event::LocationChanged(id) => {
let id = id.unwrap_or_default();
ffi_cb(self, event_id, id as uintptr_t, 0);
}
Event::ConfigureProgress(progress) | Event::ImexProgress(progress) => {
ffi_cb(self, event_id, progress as uintptr_t, 0);
}
Event::ImexFileWritten(file) => {
let data1 = file.to_c_string().unwrap_or_default();
ffi_cb(self, event_id, data1.as_ptr() as uintptr_t, 0);
}
Event::SecurejoinInviterProgress {
contact_id,
progress,
}
| Event::SecurejoinJoinerProgress {
contact_id,
progress,
} => {
ffi_cb(
self,
event_id,
contact_id as uintptr_t,
progress as uintptr_t,
);
}
Event::SecurejoinMemberAdded {
chat_id,
contact_id,
} => {
ffi_cb(
self,
event_id,
chat_id.to_u32() as uintptr_t,
contact_id as uintptr_t,
);
}
}
}
}
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn dc_context_new( pub unsafe extern "C" fn dc_context_new(
cb: Option<dc_callback_t>,
userdata: *mut libc::c_void, userdata: *mut libc::c_void,
os_name: *const libc::c_char, os_name: *const libc::c_char,
) -> *mut dc_context_t { ) -> *mut dc_context_t {
@@ -215,7 +139,6 @@ pub unsafe extern "C" fn dc_context_new(
to_string_lossy(os_name) to_string_lossy(os_name)
}; };
let ffi_ctx = ContextWrapper { let ffi_ctx = ContextWrapper {
cb,
userdata, userdata,
os_name, os_name,
inner: RwLock::new(None), inner: RwLock::new(None),
@@ -257,17 +180,11 @@ pub unsafe extern "C" fn dc_open(
return 0; return 0;
} }
let ffi_context = &*context; let ffi_context = &*context;
let rust_cb = move |_ctx: &Context, evt: Event| ffi_context.translate_cb(evt);
let ctx = if blobdir.is_null() || *blobdir == 0 { let ctx = if blobdir.is_null() || *blobdir == 0 {
Context::new( Context::new(ffi_context.os_name.clone(), as_path(dbfile).to_path_buf())
Box::new(rust_cb),
ffi_context.os_name.clone(),
as_path(dbfile).to_path_buf(),
)
} else { } else {
Context::with_blobdir( Context::with_blobdir(
Box::new(rust_cb),
ffi_context.os_name.clone(), ffi_context.os_name.clone(),
as_path(dbfile).to_path_buf(), as_path(dbfile).to_path_buf(),
as_path(blobdir).to_path_buf(), as_path(blobdir).to_path_buf(),
@@ -471,17 +388,100 @@ pub unsafe extern "C" fn dc_is_configured(context: *mut dc_context_t) -> libc::c
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn dc_run(context: *mut dc_context_t) { pub unsafe extern "C" fn dc_context_run(context: *mut dc_context_t, cb: Option<dc_callback_t>) {
if context.is_null() { if context.is_null() {
eprintln!("ignoring careless call to dc_run()"); eprintln!("ignoring careless call to dc_run()");
return; return;
} }
let ffi_context = &*context; let ffi_context = &*context;
ffi_context.with_inner(|ctx| ctx.run()).unwrap_or(()) ffi_context
.with_inner(|ctx| {
ctx.run(|_ctx, event| {
translate_cb(ffi_context, cb, event);
})
})
.unwrap_or(())
}
/// Translates the callback from the rust style to the C-style version.
unsafe fn translate_cb(ctx: &ContextWrapper, ffi_cb: Option<dc_callback_t>, event: Event) {
if let Some(ffi_cb) = ffi_cb {
let event_id = event.as_id();
match event {
Event::Info(msg)
| Event::SmtpConnected(msg)
| Event::ImapConnected(msg)
| Event::SmtpMessageSent(msg)
| Event::ImapMessageDeleted(msg)
| Event::ImapMessageMoved(msg)
| Event::ImapFolderEmptied(msg)
| Event::NewBlobFile(msg)
| Event::DeletedBlobFile(msg)
| Event::Warning(msg)
| Event::Error(msg)
| Event::ErrorNetwork(msg)
| Event::ErrorSelfNotInGroup(msg) => {
let data2 = CString::new(msg).unwrap_or_default();
ffi_cb(ctx, event_id, 0, data2.as_ptr() as uintptr_t);
}
Event::MsgsChanged { chat_id, msg_id }
| Event::IncomingMsg { chat_id, msg_id }
| Event::MsgDelivered { chat_id, msg_id }
| Event::MsgFailed { chat_id, msg_id }
| Event::MsgRead { chat_id, msg_id } => {
ffi_cb(
ctx,
event_id,
chat_id.to_u32() as uintptr_t,
msg_id.to_u32() as uintptr_t,
);
}
Event::ChatModified(chat_id) => {
ffi_cb(ctx, event_id, chat_id.to_u32() as uintptr_t, 0);
}
Event::ContactsChanged(id) | Event::LocationChanged(id) => {
let id = id.unwrap_or_default();
ffi_cb(ctx, event_id, id as uintptr_t, 0);
}
Event::ConfigureProgress(progress) | Event::ImexProgress(progress) => {
ffi_cb(ctx, event_id, progress as uintptr_t, 0);
}
Event::ImexFileWritten(file) => {
let data1 = file.to_c_string().unwrap_or_default();
ffi_cb(ctx, event_id, data1.as_ptr() as uintptr_t, 0);
}
Event::SecurejoinInviterProgress {
contact_id,
progress,
}
| Event::SecurejoinJoinerProgress {
contact_id,
progress,
} => {
ffi_cb(
ctx,
event_id,
contact_id as uintptr_t,
progress as uintptr_t,
);
}
Event::SecurejoinMemberAdded {
chat_id,
contact_id,
} => {
ffi_cb(
ctx,
event_id,
chat_id.to_u32() as uintptr_t,
contact_id as uintptr_t,
);
}
}
}
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn dc_shutdown(context: *mut dc_context_t) { pub unsafe extern "C" fn dc_context_shutdown(context: *mut dc_context_t) {
if context.is_null() { if context.is_null() {
eprintln!("ignoring careless call to dc_shutdown()"); eprintln!("ignoring careless call to dc_shutdown()");
return; return;

View File

@@ -38,7 +38,7 @@ class Account(object):
:param debug: turn on debug logging for events. :param debug: turn on debug logging for events.
""" """
self._dc_context = ffi.gc( self._dc_context = ffi.gc(
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, as_dc_charpointer(os_name)), lib.dc_context_new(ffi.NULL, as_dc_charpointer(os_name)),
_destroy_dc_context, _destroy_dc_context,
) )
if eventlogging: if eventlogging:
@@ -566,7 +566,7 @@ class IOThreads:
t.start() t.start()
def stop(self, wait=False): def stop(self, wait=False):
lib.dc_shutdown(self._dc_context) lib.dc_context_shutdown(self._dc_context)
if wait: if wait:
for name, thread in self._name2thread.items(): for name, thread in self._name2thread.items():
@@ -575,7 +575,7 @@ class IOThreads:
def dc_thread_run(self): def dc_thread_run(self):
self._log_event("py-bindings-info", 0, "DC THREAD START") self._log_event("py-bindings-info", 0, "DC THREAD START")
lib.dc_run(self._dc_context) lib.dc_context_run(self._dc_context, lib.py_dc_callback)
self._log_event("py-bindings-info", 0, "INBOX THREAD FINISHED") self._log_event("py-bindings-info", 0, "INBOX THREAD FINISHED")

View File

@@ -8,6 +8,7 @@ use std::sync::{
Arc, Condvar, Mutex, RwLock, Arc, Condvar, Mutex, RwLock,
}; };
use crossbeam::channel::select;
use crossbeam::channel::{bounded, unbounded, Receiver, Sender}; use crossbeam::channel::{bounded, unbounded, Receiver, Sender};
use crate::chat::*; use crate::chat::*;
@@ -188,10 +189,9 @@ impl Context {
where where
F: Fn(&Context, Event) -> () + Send + Sync, F: Fn(&Context, Event) -> () + Send + Sync,
{ {
// TODO: ensure this can be only called once. if self.is_running.swap(true, Ordering::Relaxed) {
panic!("Run can only be called once");
use crossbeam::channel::select; }
self.is_running.store(true, Ordering::Relaxed);
crossbeam::scope(|s| { crossbeam::scope(|s| {
let imap_handle = s.spawn(|_| loop { let imap_handle = s.spawn(|_| loop {
@@ -249,7 +249,10 @@ impl Context {
/// Stop the run loop. Blocks until all threads have shutdown. /// Stop the run loop. Blocks until all threads have shutdown.
pub fn shutdown(&self) { pub fn shutdown(&self) {
self.is_running.store(false, Ordering::Relaxed); if !self.is_running.swap(false, Ordering::Relaxed) {
// already shutdown
return;
}
self.shutdown_sender.send(()).unwrap(); self.shutdown_sender.send(()).unwrap();
job::interrupt_inbox_idle(self); job::interrupt_inbox_idle(self);
@@ -258,7 +261,6 @@ impl Context {
job::interrupt_smtp_idle(self); job::interrupt_smtp_idle(self);
} }
// connect
pub fn configure(&self) { pub fn configure(&self) {
if self.has_ongoing() { if self.has_ongoing() {
warn!(self, "There is already another ongoing process running."); warn!(self, "There is already another ongoing process running.");