| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 
 | //===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
/// Allows users to invoke an "outbound" operation related to a `Channel` that will flow through the `ChannelPipeline` until
/// it will finally be executed by the the `ChannelCore` implementation.
public protocol ChannelOutboundInvoker {
    /// Register on an `EventLoop` and so have all its IO handled.
    ///
    /// - parameters:
    ///     - promise: the `EventLoopPromise` that will be notified once the operation completes,
    ///                or `nil` if not interested in the outcome of the operation.
    func register(promise: EventLoopPromise<Void>?)
    /// Bind to a `SocketAddress`.
    /// - parameters:
    ///     - to: the `SocketAddress` to which we should bind the `Channel`.
    ///     - promise: the `EventLoopPromise` that will be notified once the operation completes,
    ///                or `nil` if not interested in the outcome of the operation.
    func bind(to: SocketAddress, promise: EventLoopPromise<Void>?)
    /// Connect to a `SocketAddress`.
    /// - parameters:
    ///     - to: the `SocketAddress` to which we should connect the `Channel`.
    ///     - promise: the `EventLoopPromise` that will be notified once the operation completes,
    ///                or `nil` if not interested in the outcome of the operation.
    func connect(to: SocketAddress, promise: EventLoopPromise<Void>?)
    /// Write data to the remote peer.
    ///
    /// Be aware that to be sure that data is really written to the remote peer you need to call `flush` or use `writeAndFlush`.
    /// Calling `write` multiple times and then `flush` may allow the `Channel` to `write` multiple data objects to the remote peer with one syscall.
    ///
    /// - parameters:
    ///     - data: the data to write
    ///     - promise: the `EventLoopPromise` that will be notified once the operation completes,
    ///                or `nil` if not interested in the outcome of the operation.
    func write(_ data: NIOAny, promise: EventLoopPromise<Void>?)
    /// Flush data that was previously written via `write` to the remote peer.
    func flush()
    /// Shortcut for calling `write` and `flush`.
    ///
    /// - parameters:
    ///     - data: the data to write
    ///     - promise: the `EventLoopPromise` that will be notified once the `write` operation completes,
    ///                or `nil` if not interested in the outcome of the operation.
    func writeAndFlush(_ data: NIOAny, promise: EventLoopPromise<Void>?)
    /// Signal that we want to read from the `Channel` once there is data ready.
    ///
    /// If `ChannelOptions.autoRead` is set for a `Channel` (which is the default) this method is automatically invoked by the transport implementation,
    /// otherwise it's the user's responsibility to call this method manually once new data should be read and processed.
    ///
    func read()
    /// Close the `Channel` and so the connection if one exists.
    ///
    /// - parameters:
    ///     - mode: the `CloseMode` that is used
    ///     - promise: the `EventLoopPromise` that will be notified once the operation completes,
    ///                or `nil` if not interested in the outcome of the operation.
    func close(mode: CloseMode, promise: EventLoopPromise<Void>?)
    /// Trigger a custom user outbound event which will flow through the `ChannelPipeline`.
    ///
    /// - parameters:
    ///     - promise: the `EventLoopPromise` that will be notified once the operation completes,
    ///                or `nil` if not interested in the outcome of the operation.
    func triggerUserOutboundEvent(_ event: Any, promise: EventLoopPromise<Void>?)
    /// The `EventLoop` which is used by this `ChannelOutboundInvoker` for execution.
    var eventLoop: EventLoop { get }
}
/// Extra `ChannelOutboundInvoker` methods. Each method that returns a `EventLoopFuture` will just do the following:
///     - create a new `EventLoopPromise<Void>`
///     - call the corresponding method that takes a `EventLoopPromise<Void>`
///     - return `EventLoopPromise.futureResult`
extension ChannelOutboundInvoker {
    /// Register on an `EventLoop` and so have all its IO handled.
    ///
    /// - returns: the future which will be notified once the operation completes.
    public func register(file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Void> {
        let promise = makePromise(file: file, line: line)
        register(promise: promise)
        return promise.futureResult
    }
    /// Bind to a `SocketAddress`.
    /// - parameters:
    ///     - to: the `SocketAddress` to which we should bind the `Channel`.
    /// - returns: the future which will be notified once the operation completes.
    public func bind(to address: SocketAddress, file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Void> {
        let promise = makePromise(file: file, line: line)
        bind(to: address, promise: promise)
        return promise.futureResult
    }
    /// Connect to a `SocketAddress`.
    /// - parameters:
    ///     - to: the `SocketAddress` to which we should connect the `Channel`.
    /// - returns: the future which will be notified once the operation completes.
    public func connect(to address: SocketAddress, file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Void> {
        let promise = makePromise(file: file, line: line)
        connect(to: address, promise: promise)
        return promise.futureResult
    }
    /// Write data to the remote peer.
    ///
    /// Be aware that to be sure that data is really written to the remote peer you need to call `flush` or use `writeAndFlush`.
    /// Calling `write` multiple times and then `flush` may allow the `Channel` to `write` multiple data objects to the remote peer with one syscall.
    ///
    /// - parameters:
    ///     - data: the data to write
    /// - returns: the future which will be notified once the operation completes.
    public func write(_ data: NIOAny, file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Void> {
        let promise = makePromise(file: file, line: line)
        write(data, promise: promise)
        return promise.futureResult
    }
    /// Shortcut for calling `write` and `flush`.
    ///
    /// - parameters:
    ///     - data: the data to write
    /// - returns: the future which will be notified once the `write` operation completes.
    public func writeAndFlush(_ data: NIOAny, file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Void> {
        let promise = makePromise(file: file, line: line)
        writeAndFlush(data, promise: promise)
        return promise.futureResult
    }
    /// Close the `Channel` and so the connection if one exists.
    ///
    /// - parameters:
    ///     - mode: the `CloseMode` that is used
    /// - returns: the future which will be notified once the operation completes.
    public func close(mode: CloseMode = .all, file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Void> {
        let promise = makePromise(file: file, line: line)
        close(mode: mode, promise: promise)
        return promise.futureResult
    }
    /// Trigger a custom user outbound event which will flow through the `ChannelPipeline`.
    ///
    /// - parameters:
    ///     - event: the event itself.
    /// - returns: the future which will be notified once the operation completes.
    public func triggerUserOutboundEvent(_ event: Any, file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Void> {
        let promise = makePromise(file: file, line: line)
        triggerUserOutboundEvent(event, promise: promise)
        return promise.futureResult
    }
    private func makePromise(file: StaticString = #fileID, line: UInt = #line) -> EventLoopPromise<Void> {
        return eventLoop.makePromise(file: file, line: line)
    }
}
/// Fire inbound events related to a `Channel` through the `ChannelPipeline` until its end is reached or it's consumed by a `ChannelHandler`.
public protocol ChannelInboundInvoker {
    /// Called once a `Channel` was registered to its `EventLoop` and so IO will be processed.
    func fireChannelRegistered()
    /// Called once a `Channel` was unregistered from its `EventLoop` which means no IO will be handled for a `Channel` anymore.
    func fireChannelUnregistered()
    /// Called once a `Channel` becomes active.
    ///
    /// What active means depends on the `Channel` implementation and semantics.
    /// For example for TCP it means the `Channel` is connected to the remote peer.
    func fireChannelActive()
    /// Called once a `Channel` becomes inactive.
    ///
    /// What inactive means depends on the `Channel` implementation and semantics.
    /// For example for TCP it means the `Channel` was disconnected from the remote peer and closed.
    func fireChannelInactive()
    /// Called once there is some data read for a `Channel` that needs processing.
    ///
    /// - parameters:
    ///     - data: the data that was read and is ready to be processed.
    func fireChannelRead(_ data: NIOAny)
    /// Called once there is no more data to read immediately on a `Channel`. Any new data received will be handled later.
    func fireChannelReadComplete()
    /// Called when a `Channel`'s writable state changes.
    ///
    /// The writability state of a Channel depends on watermarks that can be set via `Channel.setOption` and how much data
    /// is still waiting to be transferred to the remote peer.
    /// You should take care to enforce some kind of backpressure if the channel becomes unwritable which means `Channel.isWritable`
    /// will return `false` to ensure you do not consume too much memory due to queued writes. What exactly you should do here depends on the
    /// protocol and other semantics. But for example you may want to stop writing to the `Channel` until `Channel.writable` becomes
    /// `true` again or stop reading at all.
    func fireChannelWritabilityChanged()
    /// Called when an inbound operation `Error` was caught.
    ///
    /// Be aware that for inbound operations this method is called while for outbound operations defined in `ChannelOutboundInvoker`
    /// the `EventLoopFuture` or `EventLoopPromise` will be notified.
    ///
    /// - parameters:
    ///     - error: the error we encountered.
    func fireErrorCaught(_ error: Error)
    /// Trigger a custom user inbound event which will flow through the `ChannelPipeline`.
    ///
    /// - parameters:
    ///     - event: the event itself.
    func fireUserInboundEventTriggered(_ event: Any)
}
/// A protocol that signals that outbound and inbound events are triggered by this invoker.
public protocol ChannelInvoker: ChannelOutboundInvoker, ChannelInboundInvoker { }
/// Specify what kind of close operation is requested.
public enum CloseMode: Sendable {
    /// Close the output (writing) side of the `Channel` without closing the actual file descriptor.
    /// This is an optional mode which means it may not be supported by all `Channel` implementations.
    case output
    /// Close the input (reading) side of the `Channel` without closing the actual file descriptor.
    /// This is an optional mode which means it may not be supported by all `Channel` implementations.
    case input
    /// Close the whole `Channel (file descriptor).
    case all
}
 |