move all alloc/free/stop/has/shall_stop*ongoing* methods to context

introduce stop_ongoing to bindings and test for cancelation of configure
This commit is contained in:
holger krekel
2019-10-06 23:50:16 +02:00
parent 32ef0d4dc3
commit 51534b2fae
7 changed files with 102 additions and 144 deletions

View File

@@ -1621,7 +1621,7 @@ pub unsafe extern "C" fn dc_stop_ongoing_process(context: *mut dc_context_t) {
} }
let ffi_context = &*context; let ffi_context = &*context;
ffi_context ffi_context
.with_inner(|ctx| configure::dc_stop_ongoing_process(ctx)) .with_inner(|ctx| ctx.stop_ongoing())
.ok(); .ok();
} }

View File

@@ -411,6 +411,9 @@ class Account(object):
raise ValueError("could not join group") raise ValueError("could not join group")
return Chat(self, chat_id) return Chat(self, chat_id)
def stop_ongoing(self):
lib.dc_stop_ongoing_process(self._dc_context)
# #
# meta API for start/stop and event based processing # meta API for start/stop and event based processing
# #
@@ -432,7 +435,7 @@ class Account(object):
def stop_threads(self, wait=True): def stop_threads(self, wait=True):
""" stop IMAP/SMTP threads. """ """ stop IMAP/SMTP threads. """
lib.dc_stop_ongoing_process(self._dc_context) self.stop_ongoing()
self._threads.stop(wait=wait) self._threads.stop(wait=wait)
def shutdown(self, wait=True): def shutdown(self, wait=True):

View File

@@ -350,6 +350,12 @@ class TestOnlineAccount:
assert chat.id > const.DC_CHAT_ID_LAST_SPECIAL assert chat.id > const.DC_CHAT_ID_LAST_SPECIAL
return chat return chat
def test_configure_canceled(self, acfactory):
ac1 = acfactory.get_online_configuring_account()
wait_configuration_progress(ac1, 200)
ac1.stop_ongoing()
wait_configuration_progress(ac1, 0, 0)
def test_export_import_self_keys(self, acfactory, tmpdir): def test_export_import_self_keys(self, acfactory, tmpdir):
ac1, ac2 = acfactory.get_two_online_accounts() ac1, ac2 = acfactory.get_two_online_accounts()
dir = tmpdir.mkdir("exportdir") dir = tmpdir.mkdir("exportdir")

View File

@@ -28,7 +28,7 @@ macro_rules! progress {
// connect // connect
pub unsafe fn configure(context: &Context) { pub unsafe fn configure(context: &Context) {
if dc_has_ongoing(context) { if context.has_ongoing() {
warn!(context, "There is already another ongoing process running.",); warn!(context, "There is already another ongoing process running.",);
return; return;
} }
@@ -53,7 +53,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
let mut ongoing_allocated_here = false; let mut ongoing_allocated_here = false;
let mut param_autoconfig: Option<LoginParam> = None; let mut param_autoconfig: Option<LoginParam> = None;
if dc_alloc_ongoing(context) { if context.alloc_ongoing() {
ongoing_allocated_here = true; ongoing_allocated_here = true;
if !context.sql.is_open() { if !context.sql.is_open() {
error!(context, "Cannot configure, database not opened.",); error!(context, "Cannot configure, database not opened.",);
@@ -74,9 +74,6 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
context.smtp.clone().lock().unwrap().disconnect(); context.smtp.clone().lock().unwrap().disconnect();
info!(context, "Configure ...",); info!(context, "Configure ...",);
let s_a = context.running_state.clone();
let s = s_a.read().unwrap();
// Variables that are shared between steps: // Variables that are shared between steps:
let mut param = LoginParam::from_database(context, ""); let mut param = LoginParam::from_database(context, "");
// need all vars here to be mutable because rust thinks the same step could be called multiple times // need all vars here to be mutable because rust thinks the same step could be called multiple times
@@ -88,7 +85,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
const STEP_3_INDEX: u8 = 13; const STEP_3_INDEX: u8 = 13;
let mut step_counter: u8 = 0; let mut step_counter: u8 = 0;
while !s.shall_stop_ongoing { while !context.shall_stop_ongoing() {
step_counter = step_counter + 1; step_counter = step_counter + 1;
let success = match step_counter { let success = match step_counter {
@@ -358,7 +355,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
break; break;
} }
// probe STARTTLS/993 // probe STARTTLS/993
if s.shall_stop_ongoing { if context.shall_stop_ongoing() {
ok_to_continue8 = false; ok_to_continue8 = false;
break; break;
} }
@@ -372,7 +369,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
break; break;
} }
// probe STARTTLS/143 // probe STARTTLS/143
if s.shall_stop_ongoing { if context.shall_stop_ongoing() {
ok_to_continue8 = false; ok_to_continue8 = false;
break; break;
} }
@@ -389,7 +386,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
break; break;
} }
// next probe round with only the localpart of the email-address as the loginname // next probe round with only the localpart of the email-address as the loginname
if s.shall_stop_ongoing { if context.shall_stop_ongoing() {
ok_to_continue8 = false; ok_to_continue8 = false;
break; break;
} }
@@ -426,7 +423,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
{ {
if param_autoconfig.is_some() { if param_autoconfig.is_some() {
success = false; success = false;
} else if s.shall_stop_ongoing { } else if context.shall_stop_ongoing() {
success = false; success = false;
} else { } else {
progress!(context, 850); progress!(context, 850);
@@ -442,7 +439,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
.unwrap() .unwrap()
.connect(context, &param) .connect(context, &param)
{ {
if s.shall_stop_ongoing { if context.shall_stop_ongoing() {
success = false; success = false;
} else { } else {
progress!(context, 860); progress!(context, 860);
@@ -553,47 +550,12 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
} }
*/ */
if ongoing_allocated_here { if ongoing_allocated_here {
dc_free_ongoing(context); context.free_ongoing();
} }
progress!(context, if success { 1000 } else { 0 }); progress!(context, if success { 1000 } else { 0 });
} }
/*******************************************************************************
* Ongoing process allocation/free/check
******************************************************************************/
pub fn dc_alloc_ongoing(context: &Context) -> bool {
if dc_has_ongoing(context) {
warn!(context, "There is already another ongoing process running.",);
false
} else {
let s_a = context.running_state.clone();
let mut s = s_a.write().unwrap();
s.ongoing_running = true;
s.shall_stop_ongoing = false;
true
}
}
pub fn dc_free_ongoing(context: &Context) {
let s_a = context.running_state.clone();
let mut s = s_a.write().unwrap();
s.ongoing_running = false;
s.shall_stop_ongoing = true;
}
fn dc_has_ongoing(context: &Context) -> bool {
let s_a = context.running_state.clone();
let s = s_a.read().unwrap();
s.ongoing_running || !s.shall_stop_ongoing
}
/******************************************************************************* /*******************************************************************************
* Connect to configured account * Connect to configured account
******************************************************************************/ ******************************************************************************/
@@ -620,19 +582,6 @@ pub fn dc_connect_to_configured_imap(context: &Context, imap: &Imap) -> libc::c_
* Configure a Context * Configure a Context
******************************************************************************/ ******************************************************************************/
/// Signal an ongoing process to stop.
pub fn dc_stop_ongoing_process(context: &Context) {
let s_a = context.running_state.clone();
let mut s = s_a.write().unwrap();
if s.ongoing_running && !s.shall_stop_ongoing {
info!(context, "Signaling the ongoing process to stop ASAP.",);
s.shall_stop_ongoing = true;
} else {
info!(context, "No ongoing process to stop.",);
};
}
pub fn read_autoconf_file(context: &Context, url: &str) -> Option<String> { pub fn read_autoconf_file(context: &Context, url: &str) -> Option<String> {
info!(context, "Testing {} ...", url); info!(context, "Testing {} ...", url);

View File

@@ -68,7 +68,7 @@ pub struct Context {
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub struct RunningState { pub struct RunningState {
pub ongoing_running: bool, pub ongoing_running: bool,
pub shall_stop_ongoing: bool, shall_stop_ongoing: bool,
} }
/// Return some info about deltachat-core /// Return some info about deltachat-core
@@ -220,6 +220,62 @@ impl Context {
(*self.cb)(self, event) (*self.cb)(self, event)
} }
/*******************************************************************************
* Ongoing process allocation/free/check
******************************************************************************/
pub fn alloc_ongoing(&self) -> bool {
if self.has_ongoing() {
warn!(self, "There is already another ongoing process running.",);
false
} else {
let s_a = self.running_state.clone();
let mut s = s_a.write().unwrap();
s.ongoing_running = true;
s.shall_stop_ongoing = false;
true
}
}
pub fn free_ongoing(&self) {
let s_a = self.running_state.clone();
let mut s = s_a.write().unwrap();
s.ongoing_running = false;
s.shall_stop_ongoing = true;
}
pub fn has_ongoing(&self) -> bool {
let s_a = self.running_state.clone();
let s = s_a.read().unwrap();
s.ongoing_running || !s.shall_stop_ongoing
}
/// Signal an ongoing process to stop.
pub fn stop_ongoing(&self) {
let s_a = self.running_state.clone();
let mut s = s_a.write().unwrap();
if s.ongoing_running && !s.shall_stop_ongoing {
info!(self, "Signaling the ongoing process to stop ASAP.",);
s.shall_stop_ongoing = true;
} else {
info!(self, "No ongoing process to stop.",);
};
}
pub fn shall_stop_ongoing(&self) -> bool {
self.running_state.clone().read().unwrap().shall_stop_ongoing
}
/*******************************************************************************
* UI chat/message related API
******************************************************************************/
pub fn get_info(&self) -> HashMap<&'static str, String> { pub fn get_info(&self) -> HashMap<&'static str, String> {
let unset = "0"; let unset = "0";
let l = LoginParam::from_database(self, ""); let l = LoginParam::from_database(self, "");

View File

@@ -110,32 +110,26 @@ pub fn has_backup(context: &Context, dir_name: impl AsRef<Path>) -> Result<Strin
} }
pub fn initiate_key_transfer(context: &Context) -> Result<String> { pub fn initiate_key_transfer(context: &Context) -> Result<String> {
ensure!(context.alloc_ongoing(), "could not allocate ongoing");
let res = do_initiate_key_transfer(context);
context.free_ongoing();
res
}
fn do_initiate_key_transfer(context: &Context) -> Result<String> {
let mut msg: Message; let mut msg: Message;
ensure!(dc_alloc_ongoing(context), "could not allocate ongoing");
let setup_code = create_setup_code(context); let setup_code = create_setup_code(context);
/* this may require a keypair to be created. this may take a second ... */ /* this may require a keypair to be created. this may take a second ... */
if !context ensure!(!context.shall_stop_ongoing(), "canceled");
.running_state let setup_file_content = render_setup_file(context, &setup_code)?;
.clone()
.read()
.unwrap()
.shall_stop_ongoing
{
if let Ok(ref setup_file_content) = render_setup_file(context, &setup_code) {
/* encrypting may also take a while ... */ /* encrypting may also take a while ... */
if !context ensure!(!context.shall_stop_ongoing(), "canceled");
.running_state
.clone()
.read()
.unwrap()
.shall_stop_ongoing
{
let setup_file_name = context.new_blob_file( let setup_file_name = context.new_blob_file(
"autocrypt-setup-message.html", "autocrypt-setup-message.html",
setup_file_content.as_bytes(), setup_file_content.as_bytes(),
)?; )?;
{
if let Ok(chat_id) = chat::create_by_contact_id(context, 1) { let chat_id = chat::create_by_contact_id(context, 1)?;
msg = Message::default(); msg = Message::default();
msg.type_0 = Viewtype::File; msg.type_0 = Viewtype::File;
msg.param.set(Param::File, setup_file_name); msg.param.set(Param::File, setup_file_name);
@@ -146,25 +140,10 @@ pub fn initiate_key_transfer(context: &Context) -> Result<String> {
msg.param msg.param
.set_int(Param::ForcePlaintext, DC_FP_NO_AUTOCRYPT_HEADER); .set_int(Param::ForcePlaintext, DC_FP_NO_AUTOCRYPT_HEADER);
if !context ensure!(!context.shall_stop_ongoing(), "canceled");
.running_state let msg_id = chat::send_msg(context, chat_id, &mut msg)?;
.clone()
.read()
.unwrap()
.shall_stop_ongoing
{
if let Ok(msg_id) = chat::send_msg(context, chat_id, &mut msg) {
info!(context, "Wait for setup message being sent ...",); info!(context, "Wait for setup message being sent ...",);
loop { while !context.shall_stop_ongoing() {
if context
.running_state
.clone()
.read()
.unwrap()
.shall_stop_ongoing
{
break;
}
std::thread::sleep(std::time::Duration::from_secs(1)); std::thread::sleep(std::time::Duration::from_secs(1));
if let Ok(msg) = Message::load_from_db(context, msg_id) { if let Ok(msg) = Message::load_from_db(context, msg_id) {
if msg.is_sent() { if msg.is_sent() {
@@ -173,15 +152,6 @@ pub fn initiate_key_transfer(context: &Context) -> Result<String> {
} }
} }
} }
}
}
}
}
}
}
}
dc_free_ongoing(context);
Ok(setup_code) Ok(setup_code)
} }
@@ -420,7 +390,7 @@ pub fn normalize_setup_code(s: &str) -> String {
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) -> Result<()> { pub fn job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) -> Result<()> {
ensure!(dc_alloc_ongoing(context), "could not allocate ongoing"); ensure!(context.alloc_ongoing(), "could not allocate ongoing");
let what: Option<ImexMode> = job.param.get_int(Param::Cmd).and_then(ImexMode::from_i32); let what: Option<ImexMode> = job.param.get_int(Param::Cmd).and_then(ImexMode::from_i32);
let param = job.param.get(Param::Arg).unwrap_or_default(); let param = job.param.get(Param::Arg).unwrap_or_default();
@@ -432,7 +402,7 @@ pub fn job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) -> Result<()> {
if what == Some(ImexMode::ExportBackup) || what == Some(ImexMode::ExportSelfKeys) { if what == Some(ImexMode::ExportBackup) || what == Some(ImexMode::ExportSelfKeys) {
// before we export anything, make sure the private key exists // before we export anything, make sure the private key exists
if e2ee::ensure_secret_key_exists(context).is_err() { if e2ee::ensure_secret_key_exists(context).is_err() {
dc_free_ongoing(context); context.free_ongoing();
bail!("Cannot create private key or private key not available."); bail!("Cannot create private key or private key not available.");
} else { } else {
dc_create_folder(context, &param); dc_create_folder(context, &param);
@@ -448,7 +418,7 @@ pub fn job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) -> Result<()> {
bail!("unknown IMEX type"); bail!("unknown IMEX type");
} }
}; };
dc_free_ongoing(context); context.free_ongoing();
match success { match success {
Ok(()) => { Ok(()) => {
info!(context, "IMEX successfully completed"); info!(context, "IMEX successfully completed");
@@ -514,15 +484,7 @@ fn import_backup(context: &Context, backup_to_import: impl AsRef<Path>) -> Resul
|files| { |files| {
for (processed_files_cnt, file) in files.enumerate() { for (processed_files_cnt, file) in files.enumerate() {
let (file_name, file_blob) = file?; let (file_name, file_blob) = file?;
if context ensure!(!context.shall_stop_ongoing(), "received stop signal");
.running_state
.clone()
.read()
.unwrap()
.shall_stop_ongoing
{
bail!("received stop signal");
}
let mut permille = processed_files_cnt * 1000 / total_files_cnt; let mut permille = processed_files_cnt * 1000 / total_files_cnt;
if permille < 10 { if permille < 10 {
permille = 10 permille = 10
@@ -636,15 +598,7 @@ fn add_files_to_export(context: &Context, dest_path_filename: &PathBuf) -> Resul
let mut processed_files_cnt = 0; let mut processed_files_cnt = 0;
for entry in dir_handle { for entry in dir_handle {
let entry = entry?; let entry = entry?;
if context ensure!(!context.shall_stop_ongoing(), "canceled during export-files");
.running_state
.clone()
.read()
.unwrap()
.shall_stop_ongoing
{
bail!("canceled during export-files");
}
processed_files_cnt += 1; processed_files_cnt += 1;
let permille = max(min(processed_files_cnt * 1000 / total_files_cnt, 990), 10); let permille = max(min(processed_files_cnt * 1000 / total_files_cnt, 990), 10);
context.call_cb(Event::ImexProgress(permille)); context.call_cb(Event::ImexProgress(permille));

View File

@@ -3,7 +3,6 @@ use percent_encoding::{utf8_percent_encode, AsciiSet, NON_ALPHANUMERIC};
use crate::aheader::EncryptPreference; use crate::aheader::EncryptPreference;
use crate::chat::{self, Chat}; use crate::chat::{self, Chat};
use crate::config::*; use crate::config::*;
use crate::configure::*;
use crate::constants::*; use crate::constants::*;
use crate::contact::*; use crate::contact::*;
use crate::context::Context; use crate::context::Context;
@@ -157,7 +156,7 @@ pub fn dc_join_securejoin(context: &Context, qr: &str) -> u32 {
bob.qr_scan = None; bob.qr_scan = None;
if ongoing_allocated { if ongoing_allocated {
dc_free_ongoing(context); context.free_ongoing();
} }
ret_chat_id as u32 ret_chat_id as u32
}; };
@@ -170,7 +169,7 @@ pub fn dc_join_securejoin(context: &Context, qr: &str) -> u32 {
info!(context, "Requesting secure-join ...",); info!(context, "Requesting secure-join ...",);
ensure_secret_key_exists(context).ok(); ensure_secret_key_exists(context).ok();
if !dc_alloc_ongoing(context) { if !context.alloc_ongoing() {
return cleanup(&context, contact_chat_id, false, join_vg); return cleanup(&context, contact_chat_id, false, join_vg);
} }
let qr_scan = check_qr(context, &qr); let qr_scan = check_qr(context, &qr);
@@ -184,7 +183,7 @@ pub fn dc_join_securejoin(context: &Context, qr: &str) -> u32 {
error!(context, "Unknown contact.",); error!(context, "Unknown contact.",);
return cleanup(&context, contact_chat_id, true, join_vg); return cleanup(&context, contact_chat_id, true, join_vg);
} }
if check_exit(context) { if context.shall_stop_ongoing() {
return cleanup(&context, contact_chat_id, true, join_vg); return cleanup(&context, contact_chat_id, true, join_vg);
} }
join_vg = qr_scan.get_state() == LotState::QrAskVerifyGroup; join_vg = qr_scan.get_state() == LotState::QrAskVerifyGroup;
@@ -240,21 +239,12 @@ pub fn dc_join_securejoin(context: &Context, qr: &str) -> u32 {
} }
// Bob -> Alice // Bob -> Alice
while !check_exit(&context) { while !context.shall_stop_ongoing() {
std::thread::sleep(std::time::Duration::new(0, 3_000_000)); std::thread::sleep(std::time::Duration::new(0, 3_000_000));
} }
cleanup(&context, contact_chat_id, true, join_vg) cleanup(&context, contact_chat_id, true, join_vg)
} }
fn check_exit(context: &Context) -> bool {
context
.running_state
.clone()
.read()
.unwrap()
.shall_stop_ongoing
}
fn send_handshake_msg( fn send_handshake_msg(
context: &Context, context: &Context,
contact_chat_id: u32, contact_chat_id: u32,
@@ -636,7 +626,7 @@ pub fn handle_securejoin_handshake(
fn end_bobs_joining(context: &Context, status: libc::c_int) { fn end_bobs_joining(context: &Context, status: libc::c_int) {
context.bob.write().unwrap().status = status; context.bob.write().unwrap().status = status;
dc_stop_ongoing_process(context); context.stop_ongoing();
} }
fn secure_connection_established(context: &Context, contact_chat_id: u32) { fn secure_connection_established(context: &Context, contact_chat_id: u32) {