Fix the syncOptions on most channels (#202)
Motivation: Looks like when we previously added syncOptions support to our channels, we had a few issues. The listeners had code added, but the code never worked. This is because the code was defined in subclasses, but the protocol conformance comes from the parent class, and that parent class did not have a customized protocol witness. The datagram channel was also entirely missing its support. Modifications: - Added the missing unit tests for sync options. - Added syncOptions to StateManagedListenerChannel base class. - Added overrides to the listener subclasses. - Added syncOptions to datagram channel Result: Sync options actually work across the board.
This commit is contained in:
parent
4a0fad7658
commit
715e3179d3
|
|
@ -152,7 +152,7 @@ public final class NIOTSDatagramBootstrap {
|
|||
/// - returns: An `EventLoopFuture<Channel>` to deliver the `Channel` when connected.
|
||||
public func connect(to address: SocketAddress) -> EventLoopFuture<Channel> {
|
||||
return self.connect0 { channel, promise in
|
||||
channel.bind(to: address, promise: promise)
|
||||
channel.connect(to: address, promise: promise)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -187,4 +187,27 @@ internal final class NIOTSDatagramChannel: StateManagedNWConnectionChannel {
|
|||
self.connection = connection
|
||||
}
|
||||
}
|
||||
|
||||
@available(OSX 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *)
|
||||
extension NIOTSDatagramChannel {
|
||||
internal struct SynchronousOptions: NIOSynchronousChannelOptions {
|
||||
private let channel: NIOTSDatagramChannel
|
||||
|
||||
fileprivate init(channel: NIOTSDatagramChannel) {
|
||||
self.channel = channel
|
||||
}
|
||||
|
||||
public func setOption<Option: ChannelOption>(_ option: Option, value: Option.Value) throws {
|
||||
try self.channel.setOption0(option: option, value: value)
|
||||
}
|
||||
|
||||
public func getOption<Option: ChannelOption>(_ option: Option) throws -> Option.Value {
|
||||
return try self.channel.getOption0(option: option)
|
||||
}
|
||||
}
|
||||
|
||||
public var syncOptions: NIOSynchronousChannelOptions? {
|
||||
return SynchronousOptions(channel: self)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -127,10 +127,7 @@ internal final class NIOTSDatagramListenerChannel: StateManagedListenerChannel<N
|
|||
self.pipeline.fireChannelRead(NIOAny(newChannel))
|
||||
self.pipeline.fireChannelReadComplete()
|
||||
}
|
||||
}
|
||||
|
||||
@available(OSX 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *)
|
||||
extension NIOTSDatagramListenerChannel {
|
||||
internal struct SynchronousOptions: NIOSynchronousChannelOptions {
|
||||
private let channel: NIOTSDatagramListenerChannel
|
||||
|
||||
|
|
@ -147,7 +144,7 @@ extension NIOTSDatagramListenerChannel {
|
|||
}
|
||||
}
|
||||
|
||||
public var syncOptions: NIOSynchronousChannelOptions? {
|
||||
public override var syncOptions: NIOSynchronousChannelOptions? {
|
||||
return SynchronousOptions(channel: self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,10 +129,7 @@ internal final class NIOTSListenerChannel: StateManagedListenerChannel<NIOTSConn
|
|||
self.pipeline.fireChannelRead(NIOAny(newChannel))
|
||||
self.pipeline.fireChannelReadComplete()
|
||||
}
|
||||
}
|
||||
|
||||
@available(OSX 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *)
|
||||
extension NIOTSListenerChannel {
|
||||
internal struct SynchronousOptions: NIOSynchronousChannelOptions {
|
||||
private let channel: NIOTSListenerChannel
|
||||
|
||||
|
|
@ -149,7 +146,7 @@ extension NIOTSListenerChannel {
|
|||
}
|
||||
}
|
||||
|
||||
public var syncOptions: NIOSynchronousChannelOptions? {
|
||||
public override var syncOptions: NIOSynchronousChannelOptions? {
|
||||
return SynchronousOptions(channel: self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,6 +170,13 @@ internal class StateManagedListenerChannel<ChildChannel: StateManagedChannel>: S
|
|||
func newConnectionHandler(connection: NWConnection) {
|
||||
fatalError("This function must be overridden by the subclass")
|
||||
}
|
||||
|
||||
// This needs to be declared here to make sure the child classes can override
|
||||
// the behaviour.
|
||||
internal var syncOptions: NIOSynchronousChannelOptions? {
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@available(OSX 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *)
|
||||
|
|
|
|||
|
|
@ -158,5 +158,51 @@ final class NIOTSDatagramConnectionChannelTests: XCTestCase {
|
|||
XCTAssertEqual(reads.count, 1)
|
||||
XCTAssertEqual(reads[0], buffer)
|
||||
}
|
||||
|
||||
func testSyncOptionsAreSupported() throws {
|
||||
func testSyncOptions(_ channel: Channel) {
|
||||
if let sync = channel.syncOptions {
|
||||
do {
|
||||
let endpointReuse = try sync.getOption(NIOTSChannelOptions.allowLocalEndpointReuse)
|
||||
try sync.setOption(NIOTSChannelOptions.allowLocalEndpointReuse, value: !endpointReuse)
|
||||
XCTAssertNotEqual(endpointReuse, try sync.getOption(NIOTSChannelOptions.allowLocalEndpointReuse))
|
||||
} catch {
|
||||
XCTFail("Could not get/set allowLocalEndpointReuse: \(error)")
|
||||
}
|
||||
} else {
|
||||
XCTFail("\(channel) unexpectedly returned nil syncOptions")
|
||||
}
|
||||
}
|
||||
|
||||
let promise = self.group.any().makePromise(of: Channel.self)
|
||||
let listener = try NIOTSDatagramListenerBootstrap(group: self.group)
|
||||
.serverChannelInitializer { channel in
|
||||
testSyncOptions(channel)
|
||||
return channel.eventLoop.makeSucceededVoidFuture()
|
||||
}
|
||||
.childChannelInitializer { channel in
|
||||
testSyncOptions(channel)
|
||||
promise.succeed(channel)
|
||||
return channel.pipeline.addHandler(ReadRecorder<ByteBuffer>(), name: "ByteReadRecorder")
|
||||
}
|
||||
.bind(host: "localhost", port: 0)
|
||||
.wait()
|
||||
defer {
|
||||
XCTAssertNoThrow(try listener.close().wait())
|
||||
}
|
||||
|
||||
let connection = try! NIOTSDatagramBootstrap(group: self.group)
|
||||
.channelInitializer { channel in
|
||||
testSyncOptions(channel)
|
||||
return channel.eventLoop.makeSucceededVoidFuture()
|
||||
}
|
||||
.connect(to: listener.localAddress!)
|
||||
.wait()
|
||||
try connection.writeAndFlush(ByteBuffer(string: "hello world")).wait()
|
||||
|
||||
let serverHandle = try promise.futureResult.wait()
|
||||
_ = try serverHandle.waitForDatagrams(count: 1)
|
||||
XCTAssertNoThrow(try connection.close().wait())
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -306,5 +306,31 @@ class NIOTSListenerChannelTests: XCTestCase {
|
|||
|
||||
XCTAssertNoThrow(try workFuture.wait())
|
||||
}
|
||||
|
||||
func testSyncOptionsAreSupported() throws {
|
||||
func testSyncOptions(_ channel: Channel) {
|
||||
if let sync = channel.syncOptions {
|
||||
do {
|
||||
let endpointReuse = try sync.getOption(NIOTSChannelOptions.allowLocalEndpointReuse)
|
||||
try sync.setOption(NIOTSChannelOptions.allowLocalEndpointReuse, value: !endpointReuse)
|
||||
XCTAssertNotEqual(endpointReuse, try sync.getOption(NIOTSChannelOptions.allowLocalEndpointReuse))
|
||||
} catch {
|
||||
XCTFail("Could not get/set allowLocalEndpointReuse: \(error)")
|
||||
}
|
||||
} else {
|
||||
XCTFail("\(channel) unexpectedly returned nil syncOptions")
|
||||
}
|
||||
}
|
||||
|
||||
let listener = try NIOTSListenerBootstrap(group: self.group)
|
||||
.serverChannelInitializer { channel in
|
||||
testSyncOptions(channel)
|
||||
return channel.eventLoop.makeSucceededVoidFuture()
|
||||
}
|
||||
.bind(host: "localhost", port: 0)
|
||||
.wait()
|
||||
|
||||
XCTAssertNoThrow(try listener.close().wait())
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue