Provide configurability for receiving connection data (#212)
Motivation: Users are stuck with the hardcoded parameters for receiving data from a connection. Modifications: - Add new options to `NIOTSChannelOptions` for configuring how to receive data from a connection. Result: Users can configure how they receive data from a connection.
This commit is contained in:
parent
fc398db673
commit
bbd5e63cf9
|
|
@ -68,6 +68,12 @@ internal final class NIOTSDatagramChannel: StateManagedNWConnectionChannel {
|
||||||
/// after the initial connection attempt has been made.
|
/// after the initial connection attempt has been made.
|
||||||
internal var connection: NWConnection?
|
internal var connection: NWConnection?
|
||||||
|
|
||||||
|
/// The minimum length of data to receive from this connection, until the content is complete.
|
||||||
|
internal var minimumIncompleteReceiveLength: Int
|
||||||
|
|
||||||
|
/// The maximum length of data to receive from this connection in a single completion.
|
||||||
|
internal var maximumReceiveLength: Int
|
||||||
|
|
||||||
/// The `DispatchQueue` that socket events for this connection will be dispatched onto.
|
/// The `DispatchQueue` that socket events for this connection will be dispatched onto.
|
||||||
internal let connectionQueue: DispatchQueue
|
internal let connectionQueue: DispatchQueue
|
||||||
|
|
||||||
|
|
@ -169,11 +175,15 @@ internal final class NIOTSDatagramChannel: StateManagedNWConnectionChannel {
|
||||||
internal init(eventLoop: NIOTSEventLoop,
|
internal init(eventLoop: NIOTSEventLoop,
|
||||||
parent: Channel? = nil,
|
parent: Channel? = nil,
|
||||||
qos: DispatchQoS? = nil,
|
qos: DispatchQoS? = nil,
|
||||||
|
minimumIncompleteReceiveLength: Int = 1,
|
||||||
|
maximumReceiveLength: Int = 8192,
|
||||||
udpOptions: NWProtocolUDP.Options,
|
udpOptions: NWProtocolUDP.Options,
|
||||||
tlsOptions: NWProtocolTLS.Options?) {
|
tlsOptions: NWProtocolTLS.Options?) {
|
||||||
self.tsEventLoop = eventLoop
|
self.tsEventLoop = eventLoop
|
||||||
self.closePromise = eventLoop.makePromise()
|
self.closePromise = eventLoop.makePromise()
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
self.minimumIncompleteReceiveLength = minimumIncompleteReceiveLength
|
||||||
|
self.maximumReceiveLength = maximumReceiveLength
|
||||||
self.connectionQueue = eventLoop.channelQueue(label: "nio.nioTransportServices.connectionchannel", qos: qos)
|
self.connectionQueue = eventLoop.channelQueue(label: "nio.nioTransportServices.connectionchannel", qos: qos)
|
||||||
self.udpOptions = udpOptions
|
self.udpOptions = udpOptions
|
||||||
self.tlsOptions = tlsOptions
|
self.tlsOptions = tlsOptions
|
||||||
|
|
@ -187,11 +197,15 @@ internal final class NIOTSDatagramChannel: StateManagedNWConnectionChannel {
|
||||||
on eventLoop: NIOTSEventLoop,
|
on eventLoop: NIOTSEventLoop,
|
||||||
parent: Channel,
|
parent: Channel,
|
||||||
qos: DispatchQoS? = nil,
|
qos: DispatchQoS? = nil,
|
||||||
|
minimumIncompleteReceiveLength: Int = 1,
|
||||||
|
maximumReceiveLength: Int = 8192,
|
||||||
udpOptions: NWProtocolUDP.Options,
|
udpOptions: NWProtocolUDP.Options,
|
||||||
tlsOptions: NWProtocolTLS.Options?) {
|
tlsOptions: NWProtocolTLS.Options?) {
|
||||||
self.init(eventLoop: eventLoop,
|
self.init(eventLoop: eventLoop,
|
||||||
parent: parent,
|
parent: parent,
|
||||||
qos: qos,
|
qos: qos,
|
||||||
|
minimumIncompleteReceiveLength: minimumIncompleteReceiveLength,
|
||||||
|
maximumReceiveLength: maximumReceiveLength,
|
||||||
udpOptions: udpOptions,
|
udpOptions: udpOptions,
|
||||||
tlsOptions: tlsOptions)
|
tlsOptions: tlsOptions)
|
||||||
self.connection = connection
|
self.connection = connection
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,12 @@ public struct NIOTSChannelOptions {
|
||||||
/// See: ``Types/NIOTSListenerOption``.
|
/// See: ``Types/NIOTSListenerOption``.
|
||||||
@available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
|
@available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
|
||||||
public static let listener = NIOTSChannelOptions.Types.NIOTSListenerOption()
|
public static let listener = NIOTSChannelOptions.Types.NIOTSListenerOption()
|
||||||
|
|
||||||
|
/// See: ``Types/NIOTSMinimumIncompleteReceiveLengthOption``.
|
||||||
|
public static let minimumIncompleteReceiveLength = NIOTSChannelOptions.Types.NIOTSMinimumIncompleteReceiveLengthOption()
|
||||||
|
|
||||||
|
/// See: ``Types/NIOTSMaximumReceiveLengthOption``.
|
||||||
|
public static let maximumReceiveLength = NIOTSChannelOptions.Types.NIOTSMaximumReceiveLengthOption()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -179,6 +185,26 @@ extension NIOTSChannelOptions {
|
||||||
|
|
||||||
public init() {}
|
public init() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ``NIOTSMinimumIncompleteReceiveLengthOption`` controls the minimum length to receive from a given
|
||||||
|
/// `NWConnection`, until the content is complete.
|
||||||
|
///
|
||||||
|
/// This option is only valid with a `Channel` backed by an `NWConnection`.
|
||||||
|
public struct NIOTSMinimumIncompleteReceiveLengthOption: ChannelOption, Equatable {
|
||||||
|
public typealias Value = Int
|
||||||
|
|
||||||
|
public init() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ``NIOTSMaximumReceiveLengthOption`` controls the maximum length to receive from a given
|
||||||
|
/// `NWConnection` in a single completion.
|
||||||
|
///
|
||||||
|
/// This option is only valid with a `Channel` backed by an `NWConnection`.
|
||||||
|
public struct NIOTSMaximumReceiveLengthOption: ChannelOption, Equatable {
|
||||||
|
public typealias Value = Int
|
||||||
|
|
||||||
|
public init() {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,12 @@ internal final class NIOTSConnectionChannel: StateManagedNWConnectionChannel {
|
||||||
/// after the initial connection attempt has been made.
|
/// after the initial connection attempt has been made.
|
||||||
internal var connection: NWConnection?
|
internal var connection: NWConnection?
|
||||||
|
|
||||||
|
/// The minimum length of data to receive from this connection, until the content is complete.
|
||||||
|
internal var minimumIncompleteReceiveLength: Int
|
||||||
|
|
||||||
|
/// The maximum length of data to receive from this connection in a single completion.
|
||||||
|
internal var maximumReceiveLength: Int
|
||||||
|
|
||||||
/// The `DispatchQueue` that socket events for this connection will be dispatched onto.
|
/// The `DispatchQueue` that socket events for this connection will be dispatched onto.
|
||||||
internal let connectionQueue: DispatchQueue
|
internal let connectionQueue: DispatchQueue
|
||||||
|
|
||||||
|
|
@ -230,11 +236,15 @@ internal final class NIOTSConnectionChannel: StateManagedNWConnectionChannel {
|
||||||
internal init(eventLoop: NIOTSEventLoop,
|
internal init(eventLoop: NIOTSEventLoop,
|
||||||
parent: Channel? = nil,
|
parent: Channel? = nil,
|
||||||
qos: DispatchQoS? = nil,
|
qos: DispatchQoS? = nil,
|
||||||
|
minimumIncompleteReceiveLength: Int = 1,
|
||||||
|
maximumReceiveLength: Int = 8192,
|
||||||
tcpOptions: NWProtocolTCP.Options,
|
tcpOptions: NWProtocolTCP.Options,
|
||||||
tlsOptions: NWProtocolTLS.Options?) {
|
tlsOptions: NWProtocolTLS.Options?) {
|
||||||
self.tsEventLoop = eventLoop
|
self.tsEventLoop = eventLoop
|
||||||
self.closePromise = eventLoop.makePromise()
|
self.closePromise = eventLoop.makePromise()
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
self.minimumIncompleteReceiveLength = minimumIncompleteReceiveLength
|
||||||
|
self.maximumReceiveLength = maximumReceiveLength
|
||||||
self.connectionQueue = eventLoop.channelQueue(label: "nio.nioTransportServices.connectionchannel", qos: qos)
|
self.connectionQueue = eventLoop.channelQueue(label: "nio.nioTransportServices.connectionchannel", qos: qos)
|
||||||
self.tcpOptions = tcpOptions
|
self.tcpOptions = tcpOptions
|
||||||
self.tlsOptions = tlsOptions
|
self.tlsOptions = tlsOptions
|
||||||
|
|
@ -248,11 +258,15 @@ internal final class NIOTSConnectionChannel: StateManagedNWConnectionChannel {
|
||||||
on eventLoop: NIOTSEventLoop,
|
on eventLoop: NIOTSEventLoop,
|
||||||
parent: Channel? = nil,
|
parent: Channel? = nil,
|
||||||
qos: DispatchQoS? = nil,
|
qos: DispatchQoS? = nil,
|
||||||
|
minimumIncompleteReceiveLength: Int = 1,
|
||||||
|
maximumReceiveLength: Int = 8192,
|
||||||
tcpOptions: NWProtocolTCP.Options,
|
tcpOptions: NWProtocolTCP.Options,
|
||||||
tlsOptions: NWProtocolTLS.Options?) {
|
tlsOptions: NWProtocolTLS.Options?) {
|
||||||
self.init(eventLoop: eventLoop,
|
self.init(eventLoop: eventLoop,
|
||||||
parent: parent,
|
parent: parent,
|
||||||
qos: qos,
|
qos: qos,
|
||||||
|
minimumIncompleteReceiveLength: minimumIncompleteReceiveLength,
|
||||||
|
maximumReceiveLength: maximumReceiveLength,
|
||||||
tcpOptions: tcpOptions,
|
tcpOptions: tcpOptions,
|
||||||
tlsOptions: tlsOptions)
|
tlsOptions: tlsOptions)
|
||||||
self.connection = connection
|
self.connection = connection
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,10 @@ internal protocol StateManagedNWConnectionChannel: StateManagedChannel where Act
|
||||||
|
|
||||||
var connection: NWConnection? { get set }
|
var connection: NWConnection? { get set }
|
||||||
|
|
||||||
|
var minimumIncompleteReceiveLength: Int { get set }
|
||||||
|
|
||||||
|
var maximumReceiveLength: Int { get set }
|
||||||
|
|
||||||
var connectionQueue: DispatchQueue { get }
|
var connectionQueue: DispatchQueue { get }
|
||||||
|
|
||||||
var connectPromise: EventLoopPromise<Void>? { get set }
|
var connectPromise: EventLoopPromise<Void>? { get set }
|
||||||
|
|
@ -249,9 +253,13 @@ extension StateManagedNWConnectionChannel {
|
||||||
preconditionFailure("Connection should not be nil")
|
preconditionFailure("Connection should not be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Can we do something sensible with these numbers?
|
|
||||||
self.outstandingRead = true
|
self.outstandingRead = true
|
||||||
conn.receive(minimumIncompleteLength: 1, maximumLength: 8192, completion: self.dataReceivedHandler(content:context:isComplete:error:))
|
|
||||||
|
conn.receive(
|
||||||
|
minimumIncompleteLength: self.minimumIncompleteReceiveLength,
|
||||||
|
maximumLength: self.maximumReceiveLength,
|
||||||
|
completion: self.dataReceivedHandler(content:context:isComplete:error:)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func doClose0(error: Error) {
|
public func doClose0(error: Error) {
|
||||||
|
|
@ -554,6 +562,10 @@ extension StateManagedNWConnectionChannel {
|
||||||
self.options.supportRemoteHalfClosure = value as! Bool
|
self.options.supportRemoteHalfClosure = value as! Bool
|
||||||
case is NIOTSChannelOptions.Types.NIOTSAllowLocalEndpointReuse:
|
case is NIOTSChannelOptions.Types.NIOTSAllowLocalEndpointReuse:
|
||||||
self.allowLocalEndpointReuse = value as! NIOTSChannelOptions.Types.NIOTSAllowLocalEndpointReuse.Value
|
self.allowLocalEndpointReuse = value as! NIOTSChannelOptions.Types.NIOTSAllowLocalEndpointReuse.Value
|
||||||
|
case is NIOTSChannelOptions.Types.NIOTSMinimumIncompleteReceiveLengthOption:
|
||||||
|
self.minimumIncompleteReceiveLength = value as! NIOTSChannelOptions.Types.NIOTSMinimumIncompleteReceiveLengthOption.Value
|
||||||
|
case is NIOTSChannelOptions.Types.NIOTSMaximumReceiveLengthOption:
|
||||||
|
self.maximumReceiveLength = value as! NIOTSChannelOptions.Types.NIOTSMaximumReceiveLengthOption.Value
|
||||||
default:
|
default:
|
||||||
try self.setChannelSpecificOption0(option: option, value: value)
|
try self.setChannelSpecificOption0(option: option, value: value)
|
||||||
}
|
}
|
||||||
|
|
@ -610,6 +622,10 @@ extension StateManagedNWConnectionChannel {
|
||||||
throw NIOTSErrors.NoCurrentConnection()
|
throw NIOTSErrors.NoCurrentConnection()
|
||||||
}
|
}
|
||||||
return connection.metadata(definition: optionValue.definition) as! Option.Value
|
return connection.metadata(definition: optionValue.definition) as! Option.Value
|
||||||
|
case is NIOTSChannelOptions.Types.NIOTSMinimumIncompleteReceiveLengthOption:
|
||||||
|
return self.minimumIncompleteReceiveLength as! Option.Value
|
||||||
|
case is NIOTSChannelOptions.Types.NIOTSMaximumReceiveLengthOption:
|
||||||
|
return self.maximumReceiveLength as! Option.Value
|
||||||
default:
|
default:
|
||||||
// watchOS 6.0 availability is covered by the @available on this extension.
|
// watchOS 6.0 availability is covered by the @available on this extension.
|
||||||
if #available(OSX 10.15, iOS 13.0, tvOS 13.0, *) {
|
if #available(OSX 10.15, iOS 13.0, tvOS 13.0, *) {
|
||||||
|
|
|
||||||
|
|
@ -139,5 +139,45 @@ class NIOTSChannelOptionsTests: XCTestCase {
|
||||||
XCTAssertEqual(listenerValue, .handover)
|
XCTAssertEqual(listenerValue, .handover)
|
||||||
XCTAssertEqual(connectionValue, .interactive)
|
XCTAssertEqual(connectionValue, .interactive)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testMinimumIncompleteReceiveLength() throws {
|
||||||
|
let listener = try NIOTSListenerBootstrap(group: self.group)
|
||||||
|
.bind(host: "localhost", port: 0).wait()
|
||||||
|
defer {
|
||||||
|
XCTAssertNoThrow(try listener.close().wait())
|
||||||
|
}
|
||||||
|
|
||||||
|
let connection = try NIOTSConnectionBootstrap(group: self.group)
|
||||||
|
.channelOption(NIOTSChannelOptions.minimumIncompleteReceiveLength, value: 1)
|
||||||
|
.connect(to: listener.localAddress!)
|
||||||
|
.wait()
|
||||||
|
defer {
|
||||||
|
XCTAssertNoThrow(try connection.close().wait())
|
||||||
|
}
|
||||||
|
|
||||||
|
let connectionValue = try assertNoThrowWithValue(connection.getOption(NIOTSChannelOptions.minimumIncompleteReceiveLength).wait())
|
||||||
|
|
||||||
|
XCTAssertEqual(connectionValue, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testMaximumReceiveLength() throws {
|
||||||
|
let listener = try NIOTSListenerBootstrap(group: self.group)
|
||||||
|
.bind(host: "localhost", port: 0).wait()
|
||||||
|
defer {
|
||||||
|
XCTAssertNoThrow(try listener.close().wait())
|
||||||
|
}
|
||||||
|
|
||||||
|
let connection = try NIOTSConnectionBootstrap(group: self.group)
|
||||||
|
.channelOption(NIOTSChannelOptions.maximumReceiveLength, value: 8192)
|
||||||
|
.connect(to: listener.localAddress!)
|
||||||
|
.wait()
|
||||||
|
defer {
|
||||||
|
XCTAssertNoThrow(try connection.close().wait())
|
||||||
|
}
|
||||||
|
|
||||||
|
let connectionValue = try assertNoThrowWithValue(connection.getOption(NIOTSChannelOptions.maximumReceiveLength).wait())
|
||||||
|
|
||||||
|
XCTAssertEqual(connectionValue, 8192)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue