-
Notifications
You must be signed in to change notification settings - Fork 644
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create a ClientBootstrap protocol #1253
Create a ClientBootstrap protocol #1253
Conversation
Can one of the admins verify this patch? |
8 similar comments
Can one of the admins verify this patch? |
Can one of the admins verify this patch? |
Can one of the admins verify this patch? |
Can one of the admins verify this patch? |
Can one of the admins verify this patch? |
Can one of the admins verify this patch? |
Can one of the admins verify this patch? |
Can one of the admins verify this patch? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This mostly looks really good, thanks! In general I think this is a good idea, but we'd need to add some unit testing for this as well to confirm that it is possible to actually use this protocol correctly.
Sources/NIO/Bootstrap.swift
Outdated
/// | ||
/// - parameters: | ||
/// - group: The `EventLoopGroup` to use. | ||
init(group: EventLoopGroup) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In an ideal world we'd have a proper type here, but I am really struggling to come up with a way to do it. I'm going to think on it some more and maybe an idea will come to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, please take your time 🙇♂️
I was wondering if we could use an associated type and force something, but I don't think that's correct. I'm hoping to figure out how to save folks from accidentally using a MultiThreadedEventLoopGroup
with `NIOTSConnectionBootstrap. 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should remove the init
here and instead add a public static func makeTCPClientBootstrap() -> NIOClientTransportBootstrap
to EventLoopGroup
.
Sure, for API compatibility we need to implement a default implementation for this which would be
extension EventLoopGroup {
public static func makeTCPClientBootstrap() -> NIOClientTransportBootstrap {
struct CannotBootstrap: NIOClientTransportBootstrap {
// fail everything with a good error
}
return CannotBootstrap()
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason for removing the init
is because there's less room for error. The new way would basically be to choose your favourite EventLoopGroup
and from there you could peel off a TCP client bootstrap.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We would then just implement this for SelectableEventLoop
, MultiThreadedEventLoopGroup
, EmbeddedEventLoop
, and NIOTSEventLoop(Group)
which is 99.999% of the actual use-cases so nobody will ever see the error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At a certain point though I wonder if we're over-solving this. For now it may be sufficient to exclude everything but TCP clients and servers and to solve those cases today. We can try to generalise further later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Lukasa agreed. We could just fly with basically what's there and name it accordingly leaving the more general name available for the next version?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would however remove the init
and make users peel off the bootstrap from the ELG maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with users peeling off from the ELG for now. Let's go down that road and worry about the best possible ergonomics later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good to me! @Yasumoto are you okay with this and does this make sense?
Sources/NIO/Bootstrap.swift
Outdated
@@ -325,6 +325,47 @@ private extension Channel { | |||
} | |||
} | |||
|
|||
/// `ClientTransportBootstrap` is implemented by various underlying transport mechanisms. Typically, | |||
/// this will be the BSD Sockets API implemented by `ClientBootstrap`. | |||
public protocol ClientTransportBootstrap { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would need to be called NIOClientTransportBootstrap
to meet our API naming guidelines.
Tests/NIOTests/BootstrapTest.swift
Outdated
@@ -205,4 +205,38 @@ class BootstrapTest: XCTestCase { | |||
XCTAssertNoThrow(try childChannelDone.futureResult.wait()) | |||
XCTAssertNoThrow(try serverChannelDone.futureResult.wait()) | |||
} | |||
|
|||
func testClientTransportBootstrapAllowsConformanceCorrectly() throws { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was inspired by ChannelTests.testBasicLifecycle
, happy to add more/different test cases if anyone has other ideas.
Tests/NIOTests/BootstrapTest.swift
Outdated
defer { | ||
XCTAssertNoThrow(try group.syncShutdownGracefully()) | ||
} | ||
let clientBootstrap: NIOClientTransportBootstrap = ClientBootstrap(group: group) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be nicer to write a function that takes the bootstrap generically and write the test in that function. That way it's much harder to accidentally break this test by changing only one line in a seemingly-innocuous way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a really good idea to start with a simple TCP client bootstrapping protocol. We can always improve.
Sources/NIO/Bootstrap.swift
Outdated
/// | ||
/// - parameters: | ||
/// - group: The `EventLoopGroup` to use. | ||
init(group: EventLoopGroup) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason for removing the init
is because there's less room for error. The new way would basically be to choose your favourite EventLoopGroup
and from there you could peel off a TCP client bootstrap.
Sources/NIO/Bootstrap.swift
Outdated
@@ -325,6 +325,47 @@ private extension Channel { | |||
} | |||
} | |||
|
|||
/// `NIOClientTransportBootstrap` is implemented by various underlying transport mechanisms. Typically, | |||
/// this will be the BSD Sockets API implemented by `ClientBootstrap`. | |||
public protocol NIOClientTransportBootstrap { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
naming nit: maybe NIOTCPClientBootstrap
? Because this bootstrap will only work for TCP stuff. But not strong on this one, @Lukasa ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might prefer NIOStreamClientBootstrap, to enable the possibility of encapsulating other things.
Sources/NIO/Bootstrap.swift
Outdated
/// | ||
/// - parameters: | ||
/// - group: The `EventLoopGroup` to use. | ||
init(group: EventLoopGroup) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We would then just implement this for SelectableEventLoop
, MultiThreadedEventLoopGroup
, EmbeddedEventLoop
, and NIOTSEventLoop(Group)
which is 99.999% of the actual use-cases so nobody will ever see the error.
Naming
I assumed this meant go with Default ImplementationI'm not sure the proposal for a default extension EventLoopGroup {
public static func makeTCPClientBootstrap() -> NIOTCPStreamBootstrap {
struct CannotBootstrap: NIOTCPStreamBootstrap {
func channelInitializer(_ handler: @escaping (Channel) -> EventLoopFuture<Void>) -> CannotBootstrap {
return self
}
func channelOption<Option>(_ option: Option, value: Option.Value) -> CannotBootstrap where Option : ChannelOption {
return self
}
func connectTimeout(_ timeout: TimeAmount) -> CannotBootstrap {
return self
}
func connect(host: String, port: Int) -> EventLoopFuture<Channel> {
/* return ???? */
}
}
return CannotBootstrap()
}
} StaticI also thought we do not want this to be Where to implement
|
Thanks for looking into this!!
Right now, it only supports TCP so I think it should be
I'd return a failed future here
should do it.
Agreed, shouldn't be static.
First, declare it in the
We can also do that in the github UI at the very end. |
|
How is this going? Im desperately looking forward to this for https://github.com/apple/swift-nio-transport-services |
5744ee6
to
79a4479
Compare
Thanks for the nudge, @kylebrowning ! 😅 Went through the feedback again, and I believe I've incorporated it, so this should be ready for a fresh look. |
@Yasumoto I'm happy taking this if we make it The reason we can't use this as-is is because it doesn't support TLS at all. That would mean that we have a very easy to use and compatible version for plain text (which nobody should ever use) and if you need TLS, you need to go back to the old, |
Works for me! |
This allows other EventLoopGroup implementations to swap in other bootstrap implementations. By default, it is unimplemented and will throw an error once `connect` is called on the returned Bootstrap. Support is implemented for `MultiThreadedEventLoopGroup`, `SelectableEventLoop` and `EmbeddedEventLoop`.
79a4479
to
69f2dd4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks so much @Yasumoto !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's ship this.
@swift-nio-bot test this please |
Create a simple protocol for Client-side bootstrap implementations to conform to.
Motivation:
As described in #674, we want to make it easier to switch between
ClientBootstrap
andNIOTSConnectionBootstrap
.This is one approach that I'm intrigued by, but not necessarily overly fond of. We're still allowing folks to use the wrong type of
EventLoopGroup
with the bootstrap they choose. However, this simplifies the ability to use both types of bootstrap objects, and at the least serves as a strawman proposal.Modifications:
Created a
ClientTransportBootstrap
protocol. I think it makes sense to separate out a client vs. server since the usecases and surface area are so different.Result:
Users will be able to choose between either
ClientBootstrap
orNIOTSConnectionBootstrap
much more easily.