|
#if canImport(Atlantis) |
|
import Atlantis |
|
#endif |
|
import Vapor |
|
|
|
#if canImport(Atlantis) |
|
extension Application.Clients.Provider { |
|
static var atlantis: Self { |
|
.init { application in |
|
application.clients.use { |
|
let normal = EventLoopHTTPClient(http: $0.http.client.shared, eventLoop: $0.eventLoopGroup.next(), logger: $0.logger) |
|
return AtlantisHTTPClient(original: normal) |
|
} |
|
} |
|
} |
|
} |
|
|
|
private struct AtlantisHTTPClient: Client { |
|
fileprivate let original: Client |
|
|
|
var eventLoop: EventLoop { |
|
original.eventLoop |
|
} |
|
|
|
func send(_ client: ClientRequest) -> EventLoopFuture<ClientResponse> { |
|
let atlantisRequest = Request( |
|
url: client.url.string, |
|
method: client.method.string, |
|
headers: client.headers.atlantisHeaders, |
|
body: client.body.flatMap { Data(buffer: $0) } |
|
) |
|
|
|
return original.send(client).map { result in |
|
let atlantisResponse = Response(statusCode: Int(result.status.code), headers: result.headers.atlantisHeaders) |
|
Atlantis.add(request: atlantisRequest, response: atlantisResponse, responseBody: result.body.flatMap { Data(buffer: $0) }) |
|
|
|
return result |
|
} |
|
} |
|
|
|
func delegating(to eventLoop: EventLoop) -> Client { |
|
AtlantisHTTPClient(original: original.delegating(to: eventLoop)) |
|
} |
|
|
|
func logging(to logger: Logger) -> Client { |
|
AtlantisHTTPClient(original: original.logging(to: logger)) |
|
} |
|
} |
|
|
|
// Needed because both `HTTPClient.delegating(to:logger:)` and `EventLoopHTTPClient` are private |
|
// So we need our own copy. Last checked on 2022-02-18 |
|
private struct EventLoopHTTPClient: Client { |
|
let http: HTTPClient |
|
let eventLoop: EventLoop |
|
var logger: Logger? |
|
|
|
func send(_ client: ClientRequest) -> EventLoopFuture<ClientResponse> { |
|
let urlString = client.url.string |
|
guard let url = URL(string: urlString) else { |
|
logger?.debug("\(urlString) is an invalid URL") |
|
return eventLoop.makeFailedFuture(Abort(.internalServerError, reason: "\(urlString) is an invalid URL")) |
|
} |
|
do { |
|
let request = try HTTPClient.Request( |
|
url: url, |
|
method: client.method, |
|
headers: client.headers, |
|
body: client.body.map { .byteBuffer($0) } |
|
) |
|
return http.execute(request: request, eventLoop: .delegate(on: eventLoop), logger: logger) |
|
.map { response in |
|
ClientResponse( |
|
status: response.status, |
|
headers: response.headers, |
|
body: response.body |
|
) |
|
} |
|
} catch { |
|
return eventLoop.makeFailedFuture(error) |
|
} |
|
} |
|
|
|
func delegating(to eventLoop: EventLoop) -> Client { |
|
EventLoopHTTPClient(http: http, eventLoop: eventLoop, logger: logger) |
|
} |
|
|
|
func logging(to logger: Logger) -> Client { |
|
EventLoopHTTPClient(http: http, eventLoop: eventLoop, logger: logger) |
|
} |
|
} |
|
#endif |