From df0772d6556caaf0807f285492bdc84808c60abd Mon Sep 17 00:00:00 2001 From: Ronny Bremer Date: Sun, 12 May 2024 15:19:12 +0200 Subject: [PATCH 1/4] HTTPClient needs to be shutdown after use to avoid memory leak See https://github.com/swift-server/async-http-client/blob/main/README.md#request-response-api --- Examples/PrintPDF/main.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Examples/PrintPDF/main.swift b/Examples/PrintPDF/main.swift index 80d264b..bd01200 100644 --- a/Examples/PrintPDF/main.swift +++ b/Examples/PrintPDF/main.swift @@ -1,8 +1,10 @@ import Foundation import IppClient +let httpClient = HTTPClient(configuration: .init(certificateVerification: .none)) + let printer = IppPrinter( - httpClient: HTTPClient(configuration: .init(certificateVerification: .none)), + httpClient: httpClient, uri: "ipps://macmini.local/printers/EPSON_XP_7100_Series" ) @@ -48,3 +50,5 @@ while true { try await Task.sleep(nanoseconds: 3_000_000_000) } + +try httpClient.syncShutdown() From 66dac44b884d72ac8a01cfc9d0388a7a64f4f8b7 Mon Sep 17 00:00:00 2001 From: Ronny Bremer Date: Sun, 12 May 2024 16:03:36 +0200 Subject: [PATCH 2/4] need to shutdown the HTTPClient before each exit call Not really recommended programming, but it is to demonstrate the shutdown of the HTTPClient before terminating the program. --- Examples/PrintPDF/main.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Examples/PrintPDF/main.swift b/Examples/PrintPDF/main.swift index bd01200..523d7c8 100644 --- a/Examples/PrintPDF/main.swift +++ b/Examples/PrintPDF/main.swift @@ -28,6 +28,7 @@ let response = try await printer.printJob( guard response.statusCode == .successfulOk, let jobId = response[job: \.jobId] else { print("Print job failed with status \(response.statusCode)") + try httpClient.syncShutdown() exit(1) } @@ -37,12 +38,14 @@ while true { let response = try await job.getJobAttributes(requestedAttributes: [.jobState]) guard let jobState = response[job: \.jobState] else { print("Failed to get job state") + try httpClient.syncShutdown() exit(1) } switch jobState { case .aborted, .canceled, .completed: print("Job ended with state \(jobState)") + try httpClient.syncShutdown() exit(0) default: print("Job state is \(jobState)") @@ -50,5 +53,3 @@ while true { try await Task.sleep(nanoseconds: 3_000_000_000) } - -try httpClient.syncShutdown() From 427ef17695a7f5bd31b413ce528fdfaf0bd2b723 Mon Sep 17 00:00:00 2001 From: Ronny Bremer Date: Thu, 4 Jul 2024 12:01:17 +0200 Subject: [PATCH 3/4] use defer to shutdown the HTTPClient --- Examples/PrintPDF/main.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Examples/PrintPDF/main.swift b/Examples/PrintPDF/main.swift index 523d7c8..2903828 100644 --- a/Examples/PrintPDF/main.swift +++ b/Examples/PrintPDF/main.swift @@ -3,6 +3,11 @@ import IppClient let httpClient = HTTPClient(configuration: .init(certificateVerification: .none)) +defer { + // the HTTPClient needs to be shutdown after use to avoid memory leaks + try httpClient.syncShutdown() +} + let printer = IppPrinter( httpClient: httpClient, uri: "ipps://macmini.local/printers/EPSON_XP_7100_Series" @@ -28,7 +33,6 @@ let response = try await printer.printJob( guard response.statusCode == .successfulOk, let jobId = response[job: \.jobId] else { print("Print job failed with status \(response.statusCode)") - try httpClient.syncShutdown() exit(1) } @@ -38,14 +42,12 @@ while true { let response = try await job.getJobAttributes(requestedAttributes: [.jobState]) guard let jobState = response[job: \.jobState] else { print("Failed to get job state") - try httpClient.syncShutdown() exit(1) } switch jobState { case .aborted, .canceled, .completed: print("Job ended with state \(jobState)") - try httpClient.syncShutdown() exit(0) default: print("Job state is \(jobState)") From 19f766da85f71f803661829df10cfc7f34377191 Mon Sep 17 00:00:00 2001 From: Simon Leeb <52261246+sliemeobn@users.noreply.github.com> Date: Sat, 13 Jul 2024 14:19:23 +0200 Subject: [PATCH 4/4] http client shutdown in example --- Examples/PrintPDF/app.swift | 63 ++++++++++++++++++++++++++++++++++++ Examples/PrintPDF/main.swift | 57 -------------------------------- 2 files changed, 63 insertions(+), 57 deletions(-) create mode 100644 Examples/PrintPDF/app.swift delete mode 100644 Examples/PrintPDF/main.swift diff --git a/Examples/PrintPDF/app.swift b/Examples/PrintPDF/app.swift new file mode 100644 index 0000000..b934478 --- /dev/null +++ b/Examples/PrintPDF/app.swift @@ -0,0 +1,63 @@ +import Foundation +import IppClient + +@main +struct App { + static func main() async throws { + let httpClient = HTTPClient(configuration: .init(certificateVerification: .none)) + + do { + let printer = IppPrinter( + httpClient: httpClient, + uri: "ipps://macmini.not.local/printers/EPSON_XP_7100_Series" + ) + + let attributesResponse = try await printer.getPrinterAttributes() + + if let printerName = attributesResponse[printer: \.printerName], + let printerState = attributesResponse[printer: \.printerState], + let printerStateReasons = attributesResponse[printer: \.printerStateReasons] + { + print("Printing on \(printerName) in state \(printerState), state reasons \(printerStateReasons)") + } else { + print("Could not read printer attributes, status code \(attributesResponse.statusCode)") + } + + let pdf = try Data(contentsOf: URL(fileURLWithPath: "Examples/PrintPDF/hi_mom.pdf")) + + let response = try await printer.printJob( + documentFormat: "application/pdf", + data: .bytes(pdf) + ) + + guard response.statusCode == .successfulOk, let jobId = response[job: \.jobId] else { + print("Print job failed with status \(response.statusCode)") + exit(1) + } + + let job = printer.job(jobId) + + while true { + let response = try await job.getJobAttributes(requestedAttributes: [.jobState]) + guard let jobState = response[job: \.jobState] else { + print("Failed to get job state") + exit(1) + } + + switch jobState { + case .aborted, .canceled, .completed: + print("Job ended with state \(jobState)") + exit(0) + default: + print("Job state is \(jobState)") + } + + try await Task.sleep(nanoseconds: 3_000_000_000) + } + } catch { + print("Error: \(error)") + } + + try await httpClient.shutdown() + } +} diff --git a/Examples/PrintPDF/main.swift b/Examples/PrintPDF/main.swift deleted file mode 100644 index 2903828..0000000 --- a/Examples/PrintPDF/main.swift +++ /dev/null @@ -1,57 +0,0 @@ -import Foundation -import IppClient - -let httpClient = HTTPClient(configuration: .init(certificateVerification: .none)) - -defer { - // the HTTPClient needs to be shutdown after use to avoid memory leaks - try httpClient.syncShutdown() -} - -let printer = IppPrinter( - httpClient: httpClient, - uri: "ipps://macmini.local/printers/EPSON_XP_7100_Series" -) - -let attributesResponse = try await printer.getPrinterAttributes() - -if let printerName = attributesResponse[printer: \.printerName], - let printerState = attributesResponse[printer: \.printerState], - let printerStateReasons = attributesResponse[printer: \.printerStateReasons] -{ - print("Printing on \(printerName) in state \(printerState), state reasons \(printerStateReasons)") -} else { - print("Could not read printer attributes, status code \(attributesResponse.statusCode)") -} - -let pdf = try Data(contentsOf: URL(fileURLWithPath: "Examples/PrintPDF/hi_mom.pdf")) - -let response = try await printer.printJob( - documentFormat: "application/pdf", - data: .bytes(pdf) -) - -guard response.statusCode == .successfulOk, let jobId = response[job: \.jobId] else { - print("Print job failed with status \(response.statusCode)") - exit(1) -} - -let job = printer.job(jobId) - -while true { - let response = try await job.getJobAttributes(requestedAttributes: [.jobState]) - guard let jobState = response[job: \.jobState] else { - print("Failed to get job state") - exit(1) - } - - switch jobState { - case .aborted, .canceled, .completed: - print("Job ended with state \(jobState)") - exit(0) - default: - print("Job state is \(jobState)") - } - - try await Task.sleep(nanoseconds: 3_000_000_000) -}