Skip to content

Commit

Permalink
ensure background process is terminated
Browse files Browse the repository at this point in the history
either immediately or after importing current chunk.

closes #8198

Co-authored-by: sug <sug@tutao.de>
  • Loading branch information
kibibytium and tuta-sudipg committed Jan 3, 2025
1 parent 90497f8 commit 1307ff8
Show file tree
Hide file tree
Showing 12 changed files with 94 additions and 34 deletions.
5 changes: 5 additions & 0 deletions ipc-schema/facades/NativeMailImportFacade.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@
}
],
"ret": "void"
},
"deinitLogger": {
"doc": "",
"arg": [],
"ret": "void"
}
}
}
9 changes: 7 additions & 2 deletions packages/node-mimimi/src/importer_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,14 @@ impl ImporterApi {
}

#[napi]
pub fn init_log(env: Env) {
pub unsafe fn init_log(env: Env) {
// this is in a separate fn because Env isn't Send, so can't be used in async fn.
crate::logging::console::Console::init(env);
crate::logging::console::Console::init(env)
}

#[napi]
pub unsafe fn deinit_log() {
crate::logging::console::Console::deinit();
}
}

Expand Down
67 changes: 44 additions & 23 deletions packages/node-mimimi/src/logging/console.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use crate::logging::logger::{LogMessage, Logger};
use crate::logging::logger::{LogLevel, LogMessage, Logger};
use log::{Level, LevelFilter, Log, Metadata, Record};
use napi::Env;
use napi::sys::{napi_async_work, napi_cancel_async_work};
use napi::{AsyncWorkPromise, Env, Task};
use std::sync::OnceLock;

const TAG: &str = file!();

pub static GLOBAL_CONSOLE: OnceLock<Console> = OnceLock::new();
pub static mut GLOBAL_CONSOLE: OnceLock<Console> = OnceLock::new();

/// A way for the rust code to log messages to the main applications log files
/// without having to deal with obtaining a reference to console each time.
Expand Down Expand Up @@ -38,31 +39,51 @@ impl Log for Console {
}

impl Console {
pub fn init(env: Env) {
pub unsafe fn init(env: Env) {
if GLOBAL_CONSOLE.get().is_some() {
// some other thread already initialized the cell, we don't need to set up the logger.
return;
}
let (tx, rx) = std::sync::mpsc::channel::<LogMessage>();
let console = Console { tx };
let logger = Logger::new(rx);
let Ok(()) = GLOBAL_CONSOLE.set(console) else {
// some other thread already initialized the cell, we don't need to set up the logger.
return;
};

// this may be the instance set by another thread, but that's okay.
let console = GLOBAL_CONSOLE.get().expect("not initialized");
let maybe_async_task = env.spawn(logger);

match maybe_async_task {
Ok(_) => console.log(
&Record::builder()
.level(Level::Info)
.file(Some(TAG))
.args(format_args!("{}", "spawned logger"))
.build(),
),
Err(e) => eprintln!("failed to spawn logger: {e}"),
};
set_panic_hook(console);
log::set_logger(console).unwrap_or_else(|e| eprintln!("failed to set logger: {e}"));
log::set_max_level(LevelFilter::Info);
Ok(_logger_task) => {
console.log(
&Record::builder()
.level(Level::Info)
.file(Some(TAG))
.args(format_args!("{}", "spawned logger"))
.build(),
);

GLOBAL_CONSOLE
.set(console)
.map_err(|_| "can not set")
.unwrap();

let console = GLOBAL_CONSOLE.get().unwrap();
set_panic_hook(&console);
log::set_logger(console).unwrap_or_else(|e| eprintln!("failed to set logger: {e}"));
log::set_max_level(LevelFilter::Info);
},
Err(e) => {
eprintln!("failed to spawn logger: {e}");
},
}
}
pub unsafe fn deinit() {
let console = GLOBAL_CONSOLE.take().expect("cannot deinit logger before initializing");
console
.tx
.send(LogMessage {
level: LogLevel::Finish,
message: "called deinit".to_string(),
tag: "[deinit]".to_string(),
})
.expect("Can not send finish log message. Receiver already disconnected");
}
}

Expand Down
14 changes: 9 additions & 5 deletions packages/node-mimimi/src/logging/logger.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use log::Level;
use napi::{bindgen_prelude::*, Env, JsFunction, JsObject, JsUndefined};
use std::sync::mpsc::RecvError;

/// The part of the logging setup that receives log messages from the rust log
/// {@link struct Console} and forwards them to the node environment to log.
Expand Down Expand Up @@ -44,11 +45,14 @@ impl Task for Logger {
/// runs on the libuv thread pool.
fn compute(&mut self) -> Result<Self::Output> {
if let Some(rx) = &self.rx {
Ok(rx.recv().unwrap_or_else(|_| LogMessage {
level: LogLevel::Finish,
tag: "Logger".to_string(),
message: "channel closed, logger finished".to_string(),
}))
match rx.recv() {
Ok(log_message) => Ok(log_message),
Err(RecvError) => Ok(LogMessage {
level: LogLevel::Finish,
tag: "Logger".to_string(),
message: "channel closed, logger finished".to_string(),
}),
}
} else {
// should not happen - each Logger instance listens for exactly one message and then
// gets dropped and reincarnated.
Expand Down
1 change: 0 additions & 1 deletion src/common/desktop/DesktopMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ import { AlarmScheduler } from "../calendar/date/AlarmScheduler.js"
import { DesktopExternalCalendarFacade } from "./ipc/DesktopExternalCalendarFacade.js"
import { customFetch } from "./net/NetAgent"
import { DesktopMailImportFacade } from "./mailimport/DesktopMailImportFacade.js"
import { locator } from "../../mail-app/workerUtils/worker/WorkerLocator.js"

mp()

Expand Down
8 changes: 6 additions & 2 deletions src/common/desktop/DesktopWindowManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { DesktopNotifier } from "./DesktopNotifier"
import { DesktopContextMenu } from "./DesktopContextMenu"
import { log } from "./DesktopLog"
import type { LocalShortcutManager } from "./electron-localshortcut/LocalShortcut"
import { BuildConfigKey, DesktopConfigEncKey, DesktopConfigKey } from "./config/ConfigKeys"
import { DesktopConfigEncKey, DesktopConfigKey } from "./config/ConfigKeys"
import { isRectContainedInRect } from "./DesktopUtils"
import { DesktopThemeFacade } from "./DesktopThemeFacade"
import { ElectronExports } from "./ElectronExportTypes"
Expand Down Expand Up @@ -108,8 +108,12 @@ export class WindowManager {
await this.loadStartingBounds()
const w: ApplicationWindow = await this._newWindowFactory(noAutoLogin)
windows.unshift(w)
w.on("close", () => {
w.on("close", async () => {
this.saveBounds(w.getBounds())

if (windows.length === 1) {
await this.remoteBridge.denitImportFacadeLogger(w)
}
})
.on("closed", () => {
w.setUserId(null)
Expand Down
4 changes: 4 additions & 0 deletions src/common/desktop/ipc/RemoteBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,8 @@ export class RemoteBridge {
unsubscribe(ipc: { removeHandler: (channel: string) => void }) {
ipc.removeHandler(primaryIpcConfig.renderToMainEvent)
}

async denitImportFacadeLogger(win: ApplicationWindow) {
return this.dispatcherFactory(win).dispatcher.denitImportFacadeLogger()
}
}
6 changes: 5 additions & 1 deletion src/common/desktop/mailimport/DesktopMailImportFacade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export class DesktopMailImportFacade implements NativeMailImportFacade {
this.configDirectory = configDirectory
}

async deinitLogger() {
ImporterApi.deinitLog()
}

async importFromFiles(
apiUrl: string,
unencTutaCredentials: UnencryptedCredentials,
Expand Down Expand Up @@ -48,7 +52,7 @@ export class DesktopMailImportFacade implements NativeMailImportFacade {
}

static async importStateCallback(mailImportFacade: MailImportFacade, callbackAction: ImportProgressAction, localState: LocalImportState) {
await mailImportFacade.onNewLocalImportMailState({
mailImportFacade.onNewLocalImportMailState({
remoteStateId: [localState.remoteStateId.listId, localState.remoteStateId.elementId],
status: localState.currentStatus,
start_timestamp: localState.startTimestamp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export class DesktopGlobalDispatcher {
private readonly sqlCipherFacade: SqlCipherFacadeReceiveDispatcher
private readonly themeFacade: ThemeFacadeReceiveDispatcher
private readonly webAuthnFacade: WebAuthnFacadeReceiveDispatcher

constructor(
commonSystemFacade: CommonSystemFacade,
desktopSystemFacade: DesktopSystemFacade,
Expand Down Expand Up @@ -81,6 +82,10 @@ export class DesktopGlobalDispatcher {
this.webAuthnFacade = new WebAuthnFacadeReceiveDispatcher(webAuthnFacade)
}

async denitImportFacadeLogger() {
return this.nativeMailImportFacade.dispatch("deinitLogger", [])
}

async dispatch(facadeName: string, methodName: string, args: Array<any>) {
switch (facadeName) {
case "CommonSystemFacade":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,6 @@ export interface NativeMailImportFacade {
* resumes the import for a previously paused import
*/
resumeImport(apiUrl: string, unencryptedTutaCredentials: UnencryptedCredentials, importStateId: IdTuple): Promise<void>

deinitLogger(): Promise<void>
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { NativeMailImportFacade } from "./NativeMailImportFacade.js"

export class NativeMailImportFacadeReceiveDispatcher {
constructor(private readonly facade: NativeMailImportFacade) {}

async dispatch(method: string, arg: Array<any>): Promise<any> {
switch (method) {
case "importFromFiles": {
Expand Down Expand Up @@ -34,6 +35,9 @@ export class NativeMailImportFacadeReceiveDispatcher {
const importStateId: IdTuple = arg[2]
return this.facade.resumeImport(apiUrl, unencryptedTutaCredentials, importStateId)
}
case "deinitLogger": {
return this.facade.deinitLogger()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,7 @@ export class NativeMailImportFacadeSendDispatcher implements NativeMailImportFac
async resumeImport(...args: Parameters<NativeMailImportFacade["resumeImport"]>) {
return this.transport.invokeNative("ipc", ["NativeMailImportFacade", "resumeImport", ...args])
}
async deinitLogger(...args: Parameters<NativeMailImportFacade["deinitLogger"]>) {
return this.transport.invokeNative("ipc", ["NativeMailImportFacade", "deinitLogger", ...args])
}
}

0 comments on commit 1307ff8

Please sign in to comment.