diff --git a/Sources/SwiftlyCore/HTTPClient.swift b/Sources/SwiftlyCore/HTTPClient.swift index 09d97b17..75572a97 100644 --- a/Sources/SwiftlyCore/HTTPClient.swift +++ b/Sources/SwiftlyCore/HTTPClient.swift @@ -123,46 +123,33 @@ class HTTPRequestExecutorImpl: HTTPRequestExecutor { try await self.httpClient.execute(request, timeout: timeout) } - public func getCurrentSwiftlyRelease() async throws -> Components.Schemas.SwiftlyRelease { - let config = AsyncHTTPClientTransport.Configuration(client: self.httpClient, timeout: .seconds(30)) + private func client() throws -> Client { let swiftlyUserAgent = SwiftlyUserAgentMiddleware() + let transport: ClientTransport + + let config = AsyncHTTPClientTransport.Configuration(client: self.httpClient, timeout: .seconds(30)) + transport = AsyncHTTPClientTransport(configuration: config) - let client = Client( + return Client( serverURL: try Servers.Server1.url(), - transport: AsyncHTTPClientTransport(configuration: config), + transport: transport, middlewares: [swiftlyUserAgent] ) + } - let response = try await client.getCurrentSwiftlyRelease() + public func getCurrentSwiftlyRelease() async throws -> Components.Schemas.SwiftlyRelease { + let response = try await client().getCurrentSwiftlyRelease() return try response.ok.body.json } public func getReleaseToolchains() async throws -> [Components.Schemas.Release] { - let config = AsyncHTTPClientTransport.Configuration(client: self.httpClient, timeout: .seconds(30)) - let swiftlyUserAgent = SwiftlyUserAgentMiddleware() - - let client = Client( - serverURL: try Servers.Server1.url(), - transport: AsyncHTTPClientTransport(configuration: config), - middlewares: [swiftlyUserAgent] - ) - - let response = try await client.listReleases() + let response = try await client().listReleases() return try response.ok.body.json } public func getSnapshotToolchains(branch: Components.Schemas.SourceBranch, platform: Components.Schemas.PlatformIdentifier) async throws -> Components.Schemas.DevToolchains { - let config = AsyncHTTPClientTransport.Configuration(client: self.httpClient, timeout: .seconds(30)) - let swiftlyUserAgent = SwiftlyUserAgentMiddleware() - - let client = Client( - serverURL: try Servers.Server1.url(), - transport: AsyncHTTPClientTransport(configuration: config), - middlewares: [swiftlyUserAgent] - ) - - let response = try await client.listDevToolchains(.init(path: .init(branch: branch, platform: platform))) + let response = try await client().listDevToolchains(.init(path: .init(branch: branch, platform: platform))) return try response.ok.body.json } @@ -295,52 +282,8 @@ extension Components.Schemas.DevToolchainForArch { /// HTTPClient wrapper used for interfacing with various REST APIs and downloading things. public struct SwiftlyHTTPClient { - private struct Response { - let status: HTTPResponseStatus - let buffer: ByteBuffer - } - public init() {} - private func get(url: String, headers: [String: String], maxBytes: Int) async throws -> Response { - var request = makeRequest(url: url) - - for (k, v) in headers { - request.headers.add(name: k, value: v) - } - - let response = try await SwiftlyCore.httpRequestExecutor.execute(request, timeout: .seconds(30)) - - return Response(status: response.status, buffer: try await response.body.collect(upTo: maxBytes)) - } - - public struct JSONNotFoundError: LocalizedError { - public var url: String - } - - /// Decode the provided type `T` from the JSON body of the response from a GET request - /// to the given URL. - public func getFromJSON( - url: String, - type: T.Type, - headers: [String: String] = [:] - ) async throws -> T { - // Maximum expected size for a JSON payload for an API is 1MB - let response = try await self.get(url: url, headers: headers, maxBytes: 1024 * 1024) - - switch response.status { - case .ok: - break - case .notFound: - throw SwiftlyHTTPClient.JSONNotFoundError(url: url) - default: - let json = String(buffer: response.buffer) - throw SwiftlyError(message: "Received \(response.status) when reaching \(url) for JSON: \(json)") - } - - return try JSONDecoder().decode(type.self, from: response.buffer) - } - /// Return the current Swiftly release using the swift.org API. public func getCurrentSwiftlyRelease() async throws -> Components.Schemas.SwiftlyRelease { try await SwiftlyCore.httpRequestExecutor.getCurrentSwiftlyRelease() diff --git a/Tests/SwiftlyTests/HTTPClientTests.swift b/Tests/SwiftlyTests/HTTPClientTests.swift index 275e9ab2..30a9fce9 100644 --- a/Tests/SwiftlyTests/HTTPClientTests.swift +++ b/Tests/SwiftlyTests/HTTPClientTests.swift @@ -3,48 +3,6 @@ import XCTest final class HTTPClientTests: SwiftlyTests { - func testGet() async throws { - // GIVEN: we have a swiftly http client - // WHEN: we make get request for a particular type of JSON - var releases: [Components.Schemas.Release] = try await SwiftlyCore.httpClient.getFromJSON( - url: "https://www.swift.org/api/v1/install/releases.json", - type: [Components.Schemas.Release].self, - headers: [:] - ) - // THEN: we get a decoded JSON response - XCTAssertTrue(releases.count > 0) - - // GIVEN: we have a swiftly http client - // WHEN: we make a request to an invalid URL path - var exceptionThrown = false - do { - releases = try await SwiftlyCore.httpClient.getFromJSON( - url: "https://www.swift.org/api/v1/install/releases-invalid.json", - type: [Components.Schemas.Release].self, - headers: [:] - ) - } catch { - exceptionThrown = true - } - // THEN: we receive an exception - XCTAssertTrue(exceptionThrown) - - // GIVEN: we have a swiftly http client - // WHEN: we make a request to an invalid host path - exceptionThrown = false - do { - releases = try await SwiftlyCore.httpClient.getFromJSON( - url: "https://invalid.swift.org/api/v1/install/releases.json", - type: [Components.Schemas.Release].self, - headers: [:] - ) - } catch { - exceptionThrown = true - } - // THEN: we receive an exception - XCTAssertTrue(exceptionThrown) - } - func testGetSwiftlyReleaseMetadataFromSwiftOrg() async throws { let currentRelease = try await SwiftlyCore.httpClient.getCurrentSwiftlyRelease() XCTAssertNoThrow(try currentRelease.swiftlyVersion)