diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index 495209499c..181d763a49 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -107,13 +107,13 @@ func chatSendCmdSync(_ cmd: ChatCommand, bgTask: Bool = true, bgDelay: Double? = } func chatSendCmd(_ cmd: ChatCommand, bgTask: Bool = true, bgDelay: Double? = nil, _ ctrl: chat_ctrl? = nil, log: Bool = true) async -> ChatResponse { - await withCheckedContinuation { cont in + await withUnsafeContinuation { cont in cont.resume(returning: chatSendCmdSync(cmd, bgTask: bgTask, bgDelay: bgDelay, ctrl, log: log)) } } func chatRecvMsg(_ ctrl: chat_ctrl? = nil) async -> ChatResponse? { - await withCheckedContinuation { cont in + await withUnsafeContinuation { cont in _ = withBGTask(bgDelay: msgDelay) { () -> ChatResponse? in let resp = recvSimpleXMsg(ctrl) cont.resume(returning: resp) diff --git a/apps/ios/SimpleXChat/API.swift b/apps/ios/SimpleXChat/API.swift index 5e5f047611..38c8b6e0bd 100644 --- a/apps/ios/SimpleXChat/API.swift +++ b/apps/ios/SimpleXChat/API.swift @@ -177,14 +177,65 @@ public func fromCString(_ c: UnsafeMutablePointer) -> String { return s } +class ThreadExecutor { + private var stackSize: Int + private var qos: QualityOfService + + /// Initialize by specifying the stack size + init(stackSize: Int, qos: QualityOfService) { + self.stackSize = stackSize + self.qos = qos + } + + /// Execute a closure synchronously on a separate thread and return the result + func executeSync(_ task: @escaping () throws -> ResultType) throws -> ResultType { + // Initialize the semaphore (initially locked) + let semaphore = DispatchSemaphore(value: 0) + var result: Result? + + // Initialize the thread + let thread = Thread { + do { + let taskResult = try task() + result = .success(taskResult) + } catch { + result = .failure(error) + } + // Release the semaphore when the task is completed + semaphore.signal() + } + + thread.stackSize = stackSize + thread.qualityOfService = qos + + thread.start() + + // Wait until the thread completes + semaphore.wait() + + // Return the result + switch result! { + case .success(let result): + return result + case .failure(let error): + throw error + } + } +} + public func chatResponse(_ s: String) -> ChatResponse { let d = s.data(using: .utf8)! // TODO is there a way to do it without copying the data? e.g: // let p = UnsafeMutableRawPointer.init(mutating: UnsafeRawPointer(cjson)) // let d = Data.init(bytesNoCopy: p, count: strlen(cjson), deallocator: .free) do { - let r = try jsonDecoder.decode(APIResponse.self, from: d) - return r.resp + let executor = ThreadExecutor( + stackSize: 2*1024*1024, // 2MiB + qos: Thread.current.qualityOfService // inherit priority + ) + return try executor.executeSync { + try jsonDecoder.decode(APIResponse.self, from: d) + }.resp } catch { logger.error("chatResponse jsonDecoder.decode error: \(error.localizedDescription)") }