From 386486c8ffa59f646a5dc6bd0ff08c799d92c632 Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Fri, 7 Jul 2023 17:25:16 +0300 Subject: [PATCH 1/3] Gracefully close client to fix #36 --- Sources/TDLibKit/TdClientImpl.swift | 15 +++++++++++---- Tests/TDLibKitTests/TDLibKitTests.swift | 8 +++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Sources/TDLibKit/TdClientImpl.swift b/Sources/TDLibKit/TdClientImpl.swift index aacb87bbd6..f6ff7c06b7 100644 --- a/Sources/TDLibKit/TdClientImpl.swift +++ b/Sources/TDLibKit/TdClientImpl.swift @@ -41,8 +41,6 @@ open class TdClientImpl: TdClient { if !stopFlag { try! send(query: DTO(Close()), completion: { _ in }) } - isClientDestroyed = true - td_json_client_destroy(client) } /// Receives incoming updates and request responses from the TDLib client @@ -64,12 +62,18 @@ open class TdClientImpl: TdClient { self.logger?.log(String(cString: res), type: .receive) self.queryResultAsync(data) } + self.isClientDestroyed = true + td_json_client_destroy(self.client) + self.stopFlag = false } } /// Sends request to the TDLib client. public func send(query: TdQuery, completion: (CompletionHandler)? = nil) throws { - guard !self.isClientDestroyed else { throw Error(code: 404, message: "Client destroyed") } + guard !self.isClientDestroyed else { + logger?.log("Client destroyed. Query send aborted. Query: \(query)", type: .custom("Warning")) + return + } tdlibQueryQueue.async { [weak self] in guard let `self` = self else { return } @@ -95,7 +99,10 @@ open class TdClientImpl: TdClient { /// Synchronously executes TDLib request. public func execute(query: TdQuery) throws -> [String:Any]? { - guard !self.isClientDestroyed else { throw Error(code: 404, message: "Client destroyed") } + guard !self.isClientDestroyed else { + logger?.log("Client destroyed. Execution aborted. Query: \(query)", type: .custom("Warning")) + return nil + } do { let data = try query.make(with: nil) diff --git a/Tests/TDLibKitTests/TDLibKitTests.swift b/Tests/TDLibKitTests/TDLibKitTests.swift index 21ca160817..03f3d0fad6 100644 --- a/Tests/TDLibKitTests/TDLibKitTests.swift +++ b/Tests/TDLibKitTests/TDLibKitTests.swift @@ -84,7 +84,7 @@ class TDLibKitTests: XCTestCase { } override func tearDownWithError() throws { - // api.client.close() + self.client.close() try super.tearDownWithError() } @@ -103,6 +103,12 @@ class TDLibKitTests: XCTestCase { let configs = await [config1, config2, config3, config4, config5, config6, config7, config8, config9, config10] print("Application Configs \(configs)") } + + func testGetCountries() async { + let countries = try! await api.getCountries() + print("Countries \(countries)") + XCTAssertNotEqual(countries, nil) + } } From e0342d910b6a327345a12e927f014383dd3327a0 Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Fri, 7 Jul 2023 17:26:30 +0300 Subject: [PATCH 2/3] Bump patch --- version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version b/version index 9df886c42a..428b770e3e 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.4.2 +1.4.3 From 72426b62c198fe8a67997e5411a76db47a22acdd Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Mon, 17 Jul 2023 00:11:57 +0300 Subject: [PATCH 3/3] Handle internal errors during send & execute Co-Authored-By: XMLHexagram <52130356+XMLHexagram@users.noreply.github.com> --- Sources/TDLibKit/Generated/API/TdApi.swift | 40 +++++++++++++------ .../Composer/MethodsComposer.swift | 40 +++++++++++++------ 2 files changed, 54 insertions(+), 26 deletions(-) diff --git a/Sources/TDLibKit/Generated/API/TdApi.swift b/Sources/TDLibKit/Generated/API/TdApi.swift index 588ebd6343..a4561f5cf8 100644 --- a/Sources/TDLibKit/Generated/API/TdApi.swift +++ b/Sources/TDLibKit/Generated/API/TdApi.swift @@ -17994,14 +17994,21 @@ public final class TdApi { where Q: Codable, R: Codable { let dto = DTO(query, encoder: self.encoder) - try! client.send(query: dto) { [weak self] result in - guard let strongSelf = self else { return } - if let error = try? strongSelf.decoder.decode(DTO.self, from: result) { - completion(.failure(error.payload)) - } else { - let response = strongSelf.decoder.tryDecode(DTO.self, from: result) - completion(response.map { $0.payload }) + do { + try client.send(query: dto) { [weak self] result in + guard let strongSelf = self else { return } + if let error = try? strongSelf.decoder.decode(DTO.self, from: result) { + completion(.failure(error.payload)) + } else { + let response = strongSelf.decoder.tryDecode(DTO.self, from: result) + completion(response.map { $0.payload }) + } } + } catch let err as Error { + completion( .failure(err)) + } catch let any { + let err = Error(code: 500, message: any.localizedDescription) + completion( .failure(err)) } } @@ -18010,13 +18017,20 @@ public final class TdApi { private func execute(query: Q) async throws -> R where Q: Codable, R: Codable { let dto = DTO(query, encoder: self.encoder) return try await withCheckedThrowingContinuation { continuation in - try! client.send(query: dto) { result in - if let error = try? self.decoder.decode(DTO.self, from: result) { - continuation.resume(with: .failure(error.payload)) - } else { - let response = self.decoder.tryDecode(DTO.self, from: result) - continuation.resume(with: response.map { $0.payload }) + do { + try client.send(query: dto) { result in + if let error = try? self.decoder.decode(DTO.self, from: result) { + continuation.resume(with: .failure(error.payload)) + } else { + let response = self.decoder.tryDecode(DTO.self, from: result) + continuation.resume(with: response.map { $0.payload }) + } } + } catch let err as Error { + continuation.resume(with: .failure(err)) + } catch let any { + let err = Error(code: 500, message: any.localizedDescription) + continuation.resume(with: .failure(err)) } } } diff --git a/scripts/tl2swift/Sources/TlParserLib/Composer/MethodsComposer.swift b/scripts/tl2swift/Sources/TlParserLib/Composer/MethodsComposer.swift index fa2db041f5..eb13991119 100644 --- a/scripts/tl2swift/Sources/TlParserLib/Composer/MethodsComposer.swift +++ b/scripts/tl2swift/Sources/TlParserLib/Composer/MethodsComposer.swift @@ -198,13 +198,20 @@ final class MethodsComposer: Composer { .addLine("private func execute(query: Q) async throws -> R where Q: Codable, R: Codable {") .addLine(" let dto = DTO(query, encoder: self.encoder)") .addLine(" return try await withCheckedThrowingContinuation { continuation in") - .addLine(" try! client.send(query: dto) { result in") - .addLine(" if let error = try? self.decoder.decode(DTO.self, from: result) {") - .addLine(" continuation.resume(with: .failure(error.payload))") - .addLine(" } else {") - .addLine(" let response = self.decoder.tryDecode(DTO.self, from: result)") - .addLine(" continuation.resume(with: response.map { $0.payload })") + .addLine(" do {") + .addLine(" try client.send(query: dto) { result in") + .addLine(" if let error = try? self.decoder.decode(DTO.self, from: result) {") + .addLine(" continuation.resume(with: .failure(error.payload))") + .addLine(" } else {") + .addLine(" let response = self.decoder.tryDecode(DTO.self, from: result)") + .addLine(" continuation.resume(with: response.map { $0.payload })") + .addLine(" }") .addLine(" }") + .addLine(" } catch let err as Error {") + .addLine(" continuation.resume(with: .failure(err))") + .addLine(" } catch let any {") + .addLine(" let err = Error(code: 500, message: any.localizedDescription)") + .addLine(" continuation.resume(with: .failure(err))") .addLine(" }") .addLine(" }") .addLine("}") @@ -216,14 +223,21 @@ final class MethodsComposer: Composer { .addLine(" where Q: Codable, R: Codable {") .addBlankLine() .addLine(" let dto = DTO(query, encoder: self.encoder)") - .addLine(" try! client.send(query: dto) { [weak self] result in") - .addLine(" guard let strongSelf = self else { return }") - .addLine(" if let error = try? strongSelf.decoder.decode(DTO.self, from: result) {") - .addLine(" completion(.failure(error.payload))") - .addLine(" } else {") - .addLine(" let response = strongSelf.decoder.tryDecode(DTO.self, from: result)") - .addLine(" completion(response.map { $0.payload })") + .addLine(" do {") + .addLine(" try client.send(query: dto) { [weak self] result in") + .addLine(" guard let strongSelf = self else { return }") + .addLine(" if let error = try? strongSelf.decoder.decode(DTO.self, from: result) {") + .addLine(" completion(.failure(error.payload))") + .addLine(" } else {") + .addLine(" let response = strongSelf.decoder.tryDecode(DTO.self, from: result)") + .addLine(" completion(response.map { $0.payload })") + .addLine(" }") .addLine(" }") + .addLine(" } catch let err as Error {") + .addLine(" completion( .failure(err))") + .addLine(" } catch let any {") + .addLine(" let err = Error(code: 500, message: any.localizedDescription)") + .addLine(" completion( .failure(err))") .addLine(" }") .addLine("}") }