Motivation:
Channel.getOption(...) should return an EventLoopFuture to ensure we not end up with a deadlock.
Modifications:
Change getOption(...) to return EventLoopFuture.
Result:
No deadlocks and more consistent API.
Motivation:
Out half-closure tests did not wait for the actual event to be received before trying to tear-down the Channel which could lead to test-failures if the event was received not fast enough. We need to ensure we wait until we receive the event before closing the Channel and assert the received events.
Modifications:
Ensure we wait for the events before we try to close the Channel and assert the received events.
Result:
Less flaky tests.
Motivation:
Previously we required the `ByteBuffer.set/write` methods to be a
`Collection` of `UInt8` but a `Sequence` is really enough.
Modifications:
Implemented `ByteBuffer.write/set` for `Sequence`s of `UInt8`
Result:
More stuff can be used with `ByteBuffer`
Motivation:
We have multiple reasons why flush promises weren't great, for example:
- writeAndFlush sounds like it's a write + flush optimisation but in
reality it was more expensive (2 extra promises)
- the semantics were never quite clear
- lots of implementation complexity, especially for the datagram channel
Modifications:
- removed the flush promises in the API
- this deliberately doesn't do the PendingWritesManager simplifications
that this unlocks
Result:
flush doesn't have a promise anymore.
Motivation:
Max Moiseev had some good suggestions on how to clean up some APIs, this
implements those.
Modifications:
- remove `IOData.isFileRegion` (not necessary or used)
- offer an optional `as: T.Type` parameter for the integer reading methods
- remove one unnecessary method in `StaticString`'s `Collection` conformance
Result:
nicer
Motivation:
Except for blocking methods (which shouldn't be used on the event loop),
there aren't that many error cases that we should just send through the
pipeline automatically. Best proof for that is that nothing in the code
base did that. Therefore these methods shouldn't be throwing.
If the user does indeed want to catch and fire an error through the
pipeline that's still super simple `ctx.fireErrorCaught(error)`.
Modifications:
removed `throws` from the `ChannelInboundHandler` methods.
Result:
better
Motivation:
ByteToMessageDecoder implementations can potentially have usage
patterns that never reclaim memory. This is problematic when used
for a long time, as they can be holding on to large chunks of memory
they don't need.
Modifications:
Gave ByteToMessageDecoder a new protocol method,
shouldReclaimBytes(buffer:), and a default implementation.
Result:
ByteToMessageDecoders will not be able to hold on to more than 2kB
of unreachable memory under any circumstances, and will often hold
less memory than that.
Motivation:
There were a couple of places in the Channel implementations that just
weren't thread-safe at all, namely:
- localAddress
- remoetAddress
- parent
those are now fixed. I also re-ordered the code so it should be easier
to maintain in the future (the `// MARK` markers were totally
incorrect).
Modifications:
- made Channel.{local,remote}Address return a future
- made Channel.parent a `let`
- unified more of `SocketChannel` and `DatagramSocketChannel`
- fixed the `// MARK`s by reordering code
- annotated methods/properties that are in the Channel API and need to
be thread-safe
Result:
slightly more thread-safety :)
Motivation:
We used a bool to signal if we should continue decoding or not. Using an enum is more self-documenting.
Modifications:
Add DecodingState and use.
Result:
Code is more self-documenting.
motivation: bring documentation generation closer to what it will look like on oss
changes:
* make cacheable steps conditional
* use absolute path for source-kitten generated index files
Motivation:
Don't make the system fall over under slowloris-style attacks.
Modifications:
Remove the quadratic copy loop from ByteToMessageDecoder.
Result:
NIO goes from 🚂 to 🚄
Motivation:
Foundation is problematic for a few reasons:
- its implementation is different on Linux and on macOS which means our
macOS tests might be inaccurate
- on macOS it uses ObjC Foundation which means the autorelease pool
might get populated
- it links the world on Linux which means we can't do static
binaries at all
Modifications:
removed the last bits of Foundation dependency
Result:
no Foundation dependency
Motivation:
Previously in `flushNow()` we had an odd case: A loop that could never
loop. Also `flushNow()` returns a boolean with a complicated meaning:
- `true`: We wrote everything, so we don't need to be registered for
writing
- `false`: We couldn't write everything, write notification necessary
Modifications:
Removed the non-loop & made the odd bool an enum.
Result:
code easier to read.
Motivation:
The SNI handler used Foundation for something that can be done fairly
easily without. Also avoids going through Data.
Modifications:
Removed Foundation method and implemented directly on Swift stdlib's
String encoding methods.
Result:
one less Foundation import
Motivation:
For HTTP parsing, we used Foundation to trim whitespace which is not
needed.
Modifications:
Implemented whitespace trimming in Swift.
Result:
less Foundation
to not return a value
Motivation:
We recently had a bug where we had `EventLoopFuture<EventLoopFuture<()>>` which didn't make any sense. The compiler couldn't catch that problem because we just ignored a closure's argument like this:
future.then { _ in
...
}
which is dangerous. For closures that take an empty tuple, the `_ in`
isn't actually required and the others should state the type they want
to ignore.
And most whenComplete calls can be better (and often shorter) expressed
by other combinators.
Modifications:
remove pretty much all closures which just blanket ignore their
parameter.
Result:
- no closures which just ignore their parameter without at least stating
its type.
- rewrote all whenCompletes that actually used the value
Motivation:
We had a few return statements that could be removed and some places where trailing closure syntax could be used.
Modifications:
- Remove returns
- Use trailing closures
Result:
Cleaner code.
* Expose BlockingIOThreadPool
Motivation:
Sometimes we need to execute some blocking IO. For this we should expose the BlockingIOThreadPool that can be used.
Modifications:
- Factor out BlockingIOThreadPool
- Added tests
- Correctly start threadpool before execute NonBlockingIO tests.
Result:
Possible to do blocking IO.
* Corrys comment
* Correctly start pool before using it
Motivation:
We do not need to use return in the closures used in the examples.
Modifications:
- Remove return
- Remove bug where we set the same channel option two times in one example
Result:
Cleaner code.
Motivation:
After the previous change to the channel writes, the datagram and the
stream PWMs behaved differently and there was code duplication.
Modifications:
Removed different behaviour & reduced code duplication
Result:
Less code and hopefully less bugs.
Motivation:
Channel writes are a complex matter and it was even more
complex when `FileRegion` and `ByteBuffer` were completely
different kinds of objects. Now that they're more in line we can
simplify a lot of things.
Modifications:
Rewrote the inner layers of channel writes to make them more readable
and hopefully more correct.
Result:
hopefully fewer bugs.
Motivation:
We should allow to use a custom Resolver for the ClientBootstrap as users may want to use different strategies then using a DNS based approach.
Beside this GetaddrinfoResolver should not keep any state and should be more rebust as at the moment it only will ever complee the future for the A query if also an AAAA query was sent.
Modifications:
- Make Resolver protocol public
- Remove state in GetaddrinfoResolver and so allow to use it multiple times. Now it is also more conform to the protocol itself.
Result:
Allow to use custom Resolver
Motivation:
The bootstraps are important objects that everybody will use and I think
the best way to explain them is a simple example.
Modifications:
Added examples in the doc comments.
Result:
hopefully easier to use.
Motivation:
Previously `FileRegion` was a special snow flake, a bit like
`ByteBuffer` but also totally different. That caused surprise and made
`PendingWritesManager` even harder. It was also used to manage the
lifetime of a file descriptor but only sort of.
Modifications:
We now have a `FileHandle` which is a one-to-one mapping with a file
descriptor and its lifetime must be managed appropriately.
Result:
hopefully less bugs and fd leaks.
* Add a chat server / client example
Motivation:
We should add some more complex examples.
Modifications:
Add a chat server and client example.
Result:
More examples.
* Comments
* More comments
Motivation:
Lots of our most important operations had redundant labels like
func write(data: NIOAny)
the `data: ` label doesn't add anything meaningful and therefore it
should be removed.
Modifications:
removed lots of redundant labels
Result:
less redundant labels
Motivation:
The code to filter out ChannelError.eof when reading from the socket and not call fireErrorCaught(...) was broken and so the error was propagated through the pipeline.
Modifications:
- Correctly filter out .eof
- Added testcase
Result:
Correct handling of .eof
Motiviation:
We already include an echo server as example but not a client portion. This example sends a message to the server and once it received back the message it will close the connection and exit.
Modification:
Add NIOEchoClient example.
Result:
More examples.
Motivation:
In ClientBootstrap we use Int to represent the port but in ServerBootstrap we use Int32. As swift usually always use Int we should just use Int everywhere to represent the port.
Modifications:
Change Int32 to Int for port
Result:
More consistent API
Motivation:
We should better allow access to pthread_t via an withUnsafe function which is more swift-like.
Modifications:
- Add withUnsafePthread and use it
- mark pthread_t as private in Thread.
Result:
More swifty code.
Motivation:
We sometimes used fatalError(...) where we really could just use precondation(...). Beside this we can also consolidate the #if #else code for handling Darwin and Linux differently and so make the code easier to maintain.
Modifications:
- Use precondation
- Consoldate #if #else blocks for Thread
Result:
Cleaner and easier to maintain code.