Skip to content

Commit 64851a1

Browse files
artemredkinweissi
authored andcommitted
add NIO event loop as an argument for execute (#79)
* add NIO event loop as an argument for execute * review fix: add to np-delegate method as well * Resolve confict * add missing linux test * fix formatting * missing self * review fix: add event loop preference argument instead of eventloop * formatting * review fix: spelling * fix compilation error * review fixes: make preference argument not explicit and add precondition that EL must be part of ELG
1 parent 6c6162b commit 64851a1

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-0
lines changed

Sources/AsyncHTTPClient/HTTPClient.swift

+54
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,17 @@ public class HTTPClient {
172172
return self.execute(request: request, delegate: accumulator, deadline: deadline).futureResult
173173
}
174174

175+
/// Execute arbitrary HTTP request using specified URL.
176+
///
177+
/// - parameters:
178+
/// - request: HTTP request to execute.
179+
/// - eventLoop: NIO Event Loop preference.
180+
/// - deadline: Point in time by which the request must complete.
181+
public func execute(request: Request, eventLoop: EventLoopPreference, deadline: NIODeadline? = nil) -> EventLoopFuture<Response> {
182+
let accumulator = ResponseAccumulator(request: request)
183+
return self.execute(request: request, delegate: accumulator, eventLoop: eventLoop, deadline: deadline).futureResult
184+
}
185+
175186
/// Execute arbitrary HTTP request and handle response processing using provided delegate.
176187
///
177188
/// - parameters:
@@ -180,7 +191,27 @@ public class HTTPClient {
180191
/// - deadline: Point in time by which the request must complete.
181192
public func execute<T: HTTPClientResponseDelegate>(request: Request, delegate: T, deadline: NIODeadline? = nil) -> Task<T.Response> {
182193
let eventLoop = self.eventLoopGroup.next()
194+
return self.execute(request: request, delegate: delegate, eventLoop: eventLoop, deadline: deadline)
195+
}
196+
197+
/// Execute arbitrary HTTP request and handle response processing using provided delegate.
198+
///
199+
/// - parameters:
200+
/// - request: HTTP request to execute.
201+
/// - delegate: Delegate to process response parts.
202+
/// - eventLoop: NIO Event Loop preference.
203+
/// - deadline: Point in time by which the request must complete.
204+
public func execute<T: HTTPClientResponseDelegate>(request: Request, delegate: T, eventLoop: EventLoopPreference, deadline: NIODeadline? = nil) -> Task<T.Response> {
205+
switch eventLoop.preference {
206+
case .indifferent:
207+
return self.execute(request: request, delegate: delegate, eventLoop: self.eventLoopGroup.next(), deadline: deadline)
208+
case .prefers(let preferred):
209+
precondition(self.eventLoopGroup.makeIterator().contains { $0 === preferred }, "Provided EventLoop must be part of clients EventLoopGroup.")
210+
return self.execute(request: request, delegate: delegate, eventLoop: preferred, deadline: deadline)
211+
}
212+
}
183213

214+
private func execute<T: HTTPClientResponseDelegate>(request: Request, delegate: T, eventLoop: EventLoop, deadline: NIODeadline? = nil) -> Task<T.Response> {
184215
let redirectHandler: RedirectHandler<T.Response>?
185216
if self.configuration.followRedirects {
186217
redirectHandler = RedirectHandler<T.Response>(request: request) { newRequest in
@@ -312,6 +343,29 @@ public class HTTPClient {
312343
case createNew
313344
}
314345

346+
/// Specifies how the library will treat event loop passed by the user.
347+
public struct EventLoopPreference {
348+
enum Preference {
349+
/// Event Loop will be selected by the library.
350+
case indifferent
351+
/// Library will try to use provided event loop if possible.
352+
case prefers(EventLoop)
353+
}
354+
355+
var preference: Preference
356+
357+
init(_ preference: Preference) {
358+
self.preference = preference
359+
}
360+
361+
/// Event Loop will be selected by the library.
362+
public static let indifferent = EventLoopPreference(.indifferent)
363+
/// Library will try to use provided event loop if possible.
364+
public static func prefers(_ eventLoop: EventLoop) -> EventLoopPreference {
365+
return EventLoopPreference(.prefers(eventLoop))
366+
}
367+
}
368+
315369
/// Timeout configuration
316370
public struct Timeout {
317371
/// Specifies connect timeout.

Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ extension HTTPClientTests {
5353
("testNoResponseWithIgnoreErrorForSSLUncleanShutdown", testNoResponseWithIgnoreErrorForSSLUncleanShutdown),
5454
("testWrongContentLengthForSSLUncleanShutdown", testWrongContentLengthForSSLUncleanShutdown),
5555
("testWrongContentLengthWithIgnoreErrorForSSLUncleanShutdown", testWrongContentLengthWithIgnoreErrorForSSLUncleanShutdown),
56+
("testEventLoopArgument", testEventLoopArgument),
5657
]
5758
}
5859
}

Tests/AsyncHTTPClientTests/HTTPClientTests.swift

+37
Original file line numberDiff line numberDiff line change
@@ -484,4 +484,41 @@ class HTTPClientTests: XCTestCase {
484484
}
485485
}
486486
}
487+
488+
func testEventLoopArgument() throws {
489+
let httpBin = HttpBin()
490+
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
491+
let httpClient = HTTPClient(eventLoopGroupProvider: .shared(eventLoopGroup))
492+
defer {
493+
try! eventLoopGroup.syncShutdownGracefully()
494+
httpBin.shutdown()
495+
}
496+
497+
class EventLoopValidatingDelegate: HTTPClientResponseDelegate {
498+
typealias Response = Bool
499+
500+
let eventLoop: EventLoop
501+
var result = false
502+
503+
init(eventLoop: EventLoop) {
504+
self.eventLoop = eventLoop
505+
}
506+
507+
func didReceiveHead(task: HTTPClient.Task<Bool>, _ head: HTTPResponseHead) -> EventLoopFuture<Void> {
508+
self.result = task.eventLoop === self.eventLoop
509+
return task.eventLoop.makeSucceededFuture(())
510+
}
511+
512+
func didFinishRequest(task: HTTPClient.Task<Bool>) throws -> Bool {
513+
return self.result
514+
}
515+
}
516+
517+
let eventLoop = eventLoopGroup.next()
518+
let delegate = EventLoopValidatingDelegate(eventLoop: eventLoop)
519+
let request = try HTTPClient.Request(url: "http://localhost:\(httpBin.port)/get")
520+
let response = try httpClient.execute(request: request, delegate: delegate, eventLoop: .prefers(eventLoop)).wait()
521+
522+
XCTAssertEqual(true, response)
523+
}
487524
}

0 commit comments

Comments
 (0)