mirror of
https://github.com/chatmail/core.git
synced 2026-04-26 01:46:34 +03:00
Fix cancelling imex (#1855)
Fix deltachat/deltachat-android#1579 Also: Make sure that if an error happens, the UI can show the error to the user
This commit is contained in:
@@ -9,7 +9,9 @@ use std::str::FromStr;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
use async_std::path::{Path, PathBuf};
|
||||
use async_std::prelude::*;
|
||||
use async_std::{fs, io};
|
||||
|
||||
use chrono::{Local, TimeZone};
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
@@ -296,6 +298,23 @@ pub(crate) async fn dc_delete_file(context: &Context, path: impl AsRef<Path>) ->
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn dc_delete_files_in_dir(context: &Context, path: impl AsRef<Path>) {
|
||||
match async_std::fs::read_dir(path).await {
|
||||
Ok(mut read_dir) => {
|
||||
while let Some(entry) = read_dir.next().await {
|
||||
match entry {
|
||||
Ok(file) => {
|
||||
dc_delete_file(context, file.file_name()).await;
|
||||
}
|
||||
Err(e) => warn!(context, "Could not read file to delete: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(e) => warn!(context, "Could not read dir to delete: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn dc_copy_file(
|
||||
context: &Context,
|
||||
src_path: impl AsRef<Path>,
|
||||
|
||||
63
src/imex.rs
63
src/imex.rs
@@ -82,18 +82,46 @@ pub async fn imex(
|
||||
what: ImexMode,
|
||||
param1: Option<impl AsRef<Path>>,
|
||||
) -> Result<()> {
|
||||
use futures::future::FutureExt;
|
||||
|
||||
let cancel = context.alloc_ongoing().await?;
|
||||
let res = imex_inner(context, what, param1)
|
||||
.race(cancel.recv().map(|_| Err(format_err!("canceled"))))
|
||||
.await;
|
||||
|
||||
let res = async {
|
||||
let success = imex_inner(context, what, param1).await;
|
||||
match success {
|
||||
Ok(()) => {
|
||||
info!(context, "IMEX successfully completed");
|
||||
context.emit_event(EventType::ImexProgress(1000));
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => {
|
||||
cleanup_aborted_imex(context, what).await;
|
||||
error!(context, "{}", err);
|
||||
context.emit_event(EventType::ImexProgress(0));
|
||||
bail!("IMEX FAILED to complete: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
.race(async {
|
||||
cancel.recv().await.ok();
|
||||
cleanup_aborted_imex(context, what).await;
|
||||
Err(format_err!("canceled"))
|
||||
})
|
||||
.await;
|
||||
|
||||
context.free_ongoing().await;
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
async fn cleanup_aborted_imex(context: &Context, what: ImexMode) {
|
||||
if what == ImexMode::ImportBackup {
|
||||
dc_delete_file(context, context.get_dbfile()).await;
|
||||
dc_delete_files_in_dir(context, context.get_blobdir()).await;
|
||||
}
|
||||
if what == ImexMode::ExportBackup || what == ImexMode::ImportBackup {
|
||||
context.sql.open(context, context.get_dbfile(), false).await;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the filename of the backup found (otherwise an error)
|
||||
pub async fn has_backup(context: &Context, dir_name: impl AsRef<Path>) -> Result<String> {
|
||||
let dir_name = dir_name.as_ref();
|
||||
@@ -425,7 +453,7 @@ async fn imex_inner(
|
||||
}
|
||||
}
|
||||
|
||||
let success = match what {
|
||||
match what {
|
||||
ImexMode::ExportSelfKeys => export_self_keys(context, path).await,
|
||||
ImexMode::ImportSelfKeys => import_self_keys(context, path).await,
|
||||
|
||||
@@ -434,18 +462,6 @@ async fn imex_inner(
|
||||
ImexMode::ExportBackup => export_backup_old(context, path).await,
|
||||
// import_backup() will call import_backup_old() if this is an old backup.
|
||||
ImexMode::ImportBackup => import_backup(context, path).await,
|
||||
};
|
||||
|
||||
match success {
|
||||
Ok(()) => {
|
||||
info!(context, "IMEX successfully completed");
|
||||
context.emit_event(EventType::ImexProgress(1000));
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => {
|
||||
context.emit_event(EventType::ImexProgress(0));
|
||||
bail!("IMEX FAILED to complete: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -632,6 +648,7 @@ async fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
|
||||
// get a fine backup file name (the name includes the date so that multiple backup instances are possible)
|
||||
let now = time();
|
||||
let (temp_path, dest_path) = get_next_backup_path_new(dir, now).await?;
|
||||
let _d = DeleteOnDrop(temp_path.clone());
|
||||
|
||||
context
|
||||
.sql
|
||||
@@ -670,13 +687,19 @@ async fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
|
||||
}
|
||||
Err(e) => {
|
||||
error!(context, "backup failed: {}", e);
|
||||
// Not using dc_delete_file() here because it would send a DeletedBlobFile event
|
||||
fs::remove_file(temp_path).await?;
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
struct DeleteOnDrop(PathBuf);
|
||||
impl Drop for DeleteOnDrop {
|
||||
fn drop(&mut self) {
|
||||
let file = self.0.clone();
|
||||
// Not using dc_delete_file() here because it would send a DeletedBlobFile event
|
||||
async_std::task::block_on(async move { fs::remove_file(file).await.ok() });
|
||||
}
|
||||
}
|
||||
|
||||
async fn export_backup_inner(context: &Context, temp_path: &PathBuf) -> Result<()> {
|
||||
let file = File::create(temp_path).await?;
|
||||
|
||||
Reference in New Issue
Block a user