Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 12 additions & 69 deletions Sources/SwiftlyCore/HTTPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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<T: Decodable>(
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()
Expand Down
42 changes: 0 additions & 42 deletions Tests/SwiftlyTests/HTTPClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down