From 3ddf7b26808dc5f5825e228f24fe819c29424383 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Mon, 9 Oct 2023 18:03:03 +0100 Subject: [PATCH] ios: close database connections when app is terminating (#3188) * ios: close database connections when app is terminating * update * remove () * close when suspended too * additional check * fix * refactore * reset "terminating" flag --- apps/ios/Shared/Model/SuspendChat.swift | 28 ++++++++++++++++++++----- apps/ios/SimpleXChat/API.swift | 7 +++++++ apps/ios/SimpleXChat/AppGroup.swift | 8 +++++++ apps/ios/SimpleXChat/SimpleX.h | 1 + 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/apps/ios/Shared/Model/SuspendChat.swift b/apps/ios/Shared/Model/SuspendChat.swift index 58ed46a05..1c8c32f8b 100644 --- a/apps/ios/Shared/Model/SuspendChat.swift +++ b/apps/ios/Shared/Model/SuspendChat.swift @@ -19,7 +19,11 @@ let bgSuspendTimeout: Int = 5 // seconds let terminationTimeout: Int = 3 // seconds private func _suspendChat(timeout: Int) { - if ChatModel.ok { + // this is a redundant check to prevent logical errors, like the one fixed in this PR + let state = appStateGroupDefault.get() + if !state.canSuspend { + logger.error("_suspendChat called, current state: \(state.rawValue, privacy: .public)") + } else if ChatModel.ok { appStateGroupDefault.set(.suspending) apiSuspendChat(timeoutMicroseconds: timeout * 1000000) let endTask = beginBGTask(chatSuspended) @@ -31,9 +35,7 @@ private func _suspendChat(timeout: Int) { func suspendChat() { suspendLockQueue.sync { - if appStateGroupDefault.get() != .stopped { - _suspendChat(timeout: appSuspendTimeout) - } + _suspendChat(timeout: appSuspendTimeout) } } @@ -45,15 +47,25 @@ func suspendBgRefresh() { } } +private var terminating = false + func terminateChat() { + logger.debug("terminateChat") suspendLockQueue.sync { switch appStateGroupDefault.get() { case .suspending: // suspend instantly if already suspending _chatSuspended() + // when apiSuspendChat is called with timeout 0, it won't send any events on suspension if ChatModel.ok { apiSuspendChat(timeoutMicroseconds: 0) } - case .stopped: () + chatCloseStore() + case .suspended: + chatCloseStore() + case .stopped: + chatCloseStore() default: + terminating = true + // the store will be closed in _chatSuspended when event is received _suspendChat(timeout: terminationTimeout) } } @@ -73,10 +85,14 @@ private func _chatSuspended() { if ChatModel.shared.chatRunning == true { ChatReceiver.shared.stop() } + if terminating { + chatCloseStore() + } } func activateChat(appState: AppState = .active) { logger.debug("DEBUGGING: activateChat") + terminating = false suspendLockQueue.sync { appStateGroupDefault.set(appState) if ChatModel.ok { apiActivateChat() } @@ -85,6 +101,7 @@ func activateChat(appState: AppState = .active) { } func initChatAndMigrate(refreshInvitations: Bool = true) { + terminating = false let m = ChatModel.shared if (!m.chatInitialized) { do { @@ -97,6 +114,7 @@ func initChatAndMigrate(refreshInvitations: Bool = true) { } func startChatAndActivate() { + terminating = false logger.debug("DEBUGGING: startChatAndActivate") if ChatModel.shared.chatRunning == true { ChatReceiver.shared.start() diff --git a/apps/ios/SimpleXChat/API.swift b/apps/ios/SimpleXChat/API.swift index e3d202c12..fbf9d3b2c 100644 --- a/apps/ios/SimpleXChat/API.swift +++ b/apps/ios/SimpleXChat/API.swift @@ -50,6 +50,13 @@ public func chatMigrateInit(_ useKey: String? = nil, confirmMigrations: Migratio return result } +public func chatCloseStore() { + let err = fromCString(chat_close_store(getChatCtrl())) + if err != "" { + logger.error("chatCloseStore error: \(err)") + } +} + public func resetChatCtrl() { chatController = nil migrationResult = nil diff --git a/apps/ios/SimpleXChat/AppGroup.swift b/apps/ios/SimpleXChat/AppGroup.swift index e09b95717..4943dbd4e 100644 --- a/apps/ios/SimpleXChat/AppGroup.swift +++ b/apps/ios/SimpleXChat/AppGroup.swift @@ -80,6 +80,14 @@ public enum AppState: String { default: return false } } + + public var canSuspend: Bool { + switch self { + case .active: true + case .bgRefresh: true + default: false + } + } } public enum DBContainer: String { diff --git a/apps/ios/SimpleXChat/SimpleX.h b/apps/ios/SimpleXChat/SimpleX.h index 67c2fa728..644569c1b 100644 --- a/apps/ios/SimpleXChat/SimpleX.h +++ b/apps/ios/SimpleXChat/SimpleX.h @@ -17,6 +17,7 @@ typedef void* chat_ctrl; // the last parameter is used to return the pointer to chat controller extern char *chat_migrate_init(char *path, char *key, char *confirm, chat_ctrl *ctrl); +extern char *chat_close_store(chat_ctrl ctl); extern char *chat_send_cmd(chat_ctrl ctl, char *cmd); extern char *chat_recv_msg(chat_ctrl ctl); extern char *chat_recv_msg_wait(chat_ctrl ctl, int wait);