Skip to content

Commit

Permalink
Merge pull request #3541 from SwiftPackageIndex/issue-3469-dependency…
Browse files Browse the repository at this point in the history
…-transition-9

Issue 3469 dependency transition 9
  • Loading branch information
finestructure authored Dec 6, 2024
2 parents f526e68 + 45a4797 commit 42f9ffe
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 123 deletions.
20 changes: 11 additions & 9 deletions Sources/App/Controllers/PackageController+routes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,19 @@ enum PackageController {
)

case .css, .data, .faviconIco, .faviconSvg, .images, .img, .index, .js, .linkablePaths, .themeSettings, .svgImages, .svgImg, .videos:
return try await res.encodeResponse(
return try await ClientResponse(
status: .ok,
headers: req.headers
.replacingOrAdding(name: .contentType, value: route.fragment.contentType)
.replacingOrAdding(name: .cacheControl, value: "no-transform"),
for: req
)
body: res.body
).encodeResponse(for: req)
}
}

static func documentationResponse(req: Request,
route: DocRoute,
awsResponse: ClientResponse,
awsResponse: HTTPClient.Response,
documentationMetadata: DocumentationMetadata) async throws -> Response {
guard let documentation = documentationMetadata.versions[reference: route.docVersion.reference]
else {
Expand Down Expand Up @@ -146,12 +146,12 @@ enum PackageController {
updatedAt: documentation.updatedAt,
rawHtml: body.asString())
else {
return try await awsResponse.encodeResponse(
return try await ClientResponse(
status: .ok,
headers: req.headers.replacingOrAdding(name: .contentType,
value: route.contentType),
for: req
)
body: awsResponse.body
).encodeResponse(for: req)
}

return try await processor.processedPage.encodeResponse(
Expand All @@ -162,9 +162,11 @@ enum PackageController {
)
}

static func awsResponse(client: Client, route: DocRoute) async throws -> ClientResponse {
static func awsResponse(client: Client, route: DocRoute) async throws -> HTTPClient.Response {
@Dependency(\.httpClient) var httpClient

let url = try Self.awsDocumentationURL(route: route)
guard let response = try? await Current.fetchDocumentation(client, url) else {
guard let response = try? await httpClient.fetchDocumentation(url) else {
throw Abort(.notFound)
}
guard (200..<399).contains(response.status.code) else {
Expand Down
6 changes: 2 additions & 4 deletions Sources/App/Core/AppEnvironment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import FoundationNetworking


struct AppEnvironment: Sendable {
var fetchDocumentation: @Sendable (_ client: Client, _ url: URI) async throws -> ClientResponse
var fetchHTTPStatusCode: @Sendable (_ url: String) async throws -> HTTPStatus
var fetchLicense: @Sendable (_ client: Client, _ owner: String, _ repository: String) async -> Github.License?
var fetchMetadata: @Sendable (_ client: Client, _ owner: String, _ repository: String) async throws -> Github.Metadata
Expand Down Expand Up @@ -85,7 +84,6 @@ extension AppEnvironment {
nonisolated(unsafe) static var logger: Logger!

static let live = AppEnvironment(
fetchDocumentation: { client, url in try await client.get(url) },
fetchHTTPStatusCode: { url in try await Networking.fetchHTTPStatusCode(url) },
fetchLicense: { client, owner, repo in await Github.fetchLicense(client:client, owner: owner, repository: repo) },
fetchMetadata: { client, owner, repo in try await Github.fetchMetadata(client:client, owner: owner, repository: repo) },
Expand Down Expand Up @@ -152,11 +150,11 @@ extension AppEnvironment {

private enum Networking {
static func fetchHTTPStatusCode(_ url: String) async throws -> HTTPStatus {
var config = HTTPClient.Configuration()
var config = Vapor.HTTPClient.Configuration()
// We're forcing HTTP/1 due to a bug in Github's HEAD request handling
// https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/1676
config.httpVersion = .http1Only
let client = HTTPClient(eventLoopGroupProvider: .singleton, configuration: config)
let client = Vapor.HTTPClient(eventLoopGroupProvider: .singleton, configuration: config)
return try await run {
var req = HTTPClientRequest(url: url)
req.method = .HEAD
Expand Down
75 changes: 75 additions & 0 deletions Sources/App/Core/Dependencies/HTTPClient.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import Dependencies
import DependenciesMacros
import Vapor


@DependencyClient
struct HTTPClient {
typealias Response = Vapor.HTTPClient.Response

var fetchDocumentation: @Sendable (_ url: URI) async throws -> Response
}

extension HTTPClient: DependencyKey {
static var liveValue: HTTPClient {
.init(
fetchDocumentation: { url in
try await Vapor.HTTPClient.shared.get(url: url.string).get()
}
)
}
}


extension HTTPClient: TestDependencyKey {
static var testValue: Self { Self() }
}


extension DependencyValues {
var httpClient: HTTPClient {
get { self[HTTPClient.self] }
set { self[HTTPClient.self] = newValue }
}
}


#if DEBUG
// Convenience initialisers to make testing easier

extension HTTPClient {
static func echoURL(headers: HTTPHeaders = .init()) -> @Sendable (_ url: URI) async throws -> Response {
{ url in
// echo url.path in the body as a simple way to test the requested url
.init(status: .ok, headers: headers, body: .init(string: url.path))
}
}
}

extension HTTPClient.Response {
init(status: HTTPResponseStatus,
version: HTTPVersion = .http1_1,
headers: HTTPHeaders = .init(),
body: ByteBuffer? = nil) {
self.init(host: "host", status: status, version: version, headers: headers, body: body)
}

static var ok: Self { .init(status: .ok) }
static var notFound: Self { .init(status: .notFound) }
static var badRequest: Self { .init(status: .badRequest) }
}
#endif
1 change: 0 additions & 1 deletion Tests/AppTests/Mocks/AppEnvironment+mock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import Vapor
extension AppEnvironment {
static func mock(eventLoop: EventLoop) -> Self {
.init(
fetchDocumentation: { _, _ in .init(status: .ok) },
fetchHTTPStatusCode: { _ in .ok },
fetchLicense: { _, _, _ in .init(htmlUrl: "https://github.com/foo/bar/blob/main/LICENSE") },
fetchMetadata: { _, _, _ in .mock },
Expand Down
Loading

0 comments on commit 42f9ffe

Please sign in to comment.