mirror of
https://github.com/chatmail/core.git
synced 2026-05-03 05:16:28 +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 std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
use async_std::path::{Path, PathBuf};
|
use async_std::path::{Path, PathBuf};
|
||||||
|
use async_std::prelude::*;
|
||||||
use async_std::{fs, io};
|
use async_std::{fs, io};
|
||||||
|
|
||||||
use chrono::{Local, TimeZone};
|
use chrono::{Local, TimeZone};
|
||||||
use rand::{thread_rng, Rng};
|
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(
|
pub(crate) async fn dc_copy_file(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
src_path: impl AsRef<Path>,
|
src_path: impl AsRef<Path>,
|
||||||
|
|||||||
63
src/imex.rs
63
src/imex.rs
@@ -82,18 +82,46 @@ pub async fn imex(
|
|||||||
what: ImexMode,
|
what: ImexMode,
|
||||||
param1: Option<impl AsRef<Path>>,
|
param1: Option<impl AsRef<Path>>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
use futures::future::FutureExt;
|
|
||||||
|
|
||||||
let cancel = context.alloc_ongoing().await?;
|
let cancel = context.alloc_ongoing().await?;
|
||||||
let res = imex_inner(context, what, param1)
|
|
||||||
.race(cancel.recv().map(|_| Err(format_err!("canceled"))))
|
let res = async {
|
||||||
.await;
|
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;
|
context.free_ongoing().await;
|
||||||
|
|
||||||
res
|
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)
|
/// Returns the filename of the backup found (otherwise an error)
|
||||||
pub async fn has_backup(context: &Context, dir_name: impl AsRef<Path>) -> Result<String> {
|
pub async fn has_backup(context: &Context, dir_name: impl AsRef<Path>) -> Result<String> {
|
||||||
let dir_name = dir_name.as_ref();
|
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::ExportSelfKeys => export_self_keys(context, path).await,
|
||||||
ImexMode::ImportSelfKeys => import_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,
|
ImexMode::ExportBackup => export_backup_old(context, path).await,
|
||||||
// import_backup() will call import_backup_old() if this is an old backup.
|
// import_backup() will call import_backup_old() if this is an old backup.
|
||||||
ImexMode::ImportBackup => import_backup(context, path).await,
|
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)
|
// get a fine backup file name (the name includes the date so that multiple backup instances are possible)
|
||||||
let now = time();
|
let now = time();
|
||||||
let (temp_path, dest_path) = get_next_backup_path_new(dir, now).await?;
|
let (temp_path, dest_path) = get_next_backup_path_new(dir, now).await?;
|
||||||
|
let _d = DeleteOnDrop(temp_path.clone());
|
||||||
|
|
||||||
context
|
context
|
||||||
.sql
|
.sql
|
||||||
@@ -670,13 +687,19 @@ async fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
|
|||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!(context, "backup failed: {}", 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
|
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<()> {
|
async fn export_backup_inner(context: &Context, temp_path: &PathBuf) -> Result<()> {
|
||||||
let file = File::create(temp_path).await?;
|
let file = File::create(temp_path).await?;
|
||||||
|
|||||||
Reference in New Issue
Block a user