feat: Initial echo server
This commit is contained in:
72
Sources/NioEcho/main.swift
Normal file
72
Sources/NioEcho/main.swift
Normal file
@@ -0,0 +1,72 @@
|
||||
// The Swift Programming Language
|
||||
// https://docs.swift.org/swift-book
|
||||
import NIOCore
|
||||
import NIOPosix
|
||||
|
||||
private final class EchoHandler: ChannelInboundHandler {
|
||||
typealias InboundIn = ByteBuffer
|
||||
typealias OutboundOut = BackPressureHandler
|
||||
|
||||
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
|
||||
context.write(data, promise: nil)
|
||||
}
|
||||
|
||||
func channelReadComplete(context: ChannelHandlerContext) {
|
||||
context.flush()
|
||||
}
|
||||
|
||||
func errorCaught(context: ChannelHandlerContext, error: any Error) {
|
||||
print("error: \(error)")
|
||||
context.close(promise: nil)
|
||||
}
|
||||
}
|
||||
|
||||
let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
|
||||
let bootstrap = ServerBootstrap(group: group)
|
||||
.serverChannelOption(.backlog, value: 256)
|
||||
.serverChannelOption(.socketOption(.so_reuseaddr), value: 1)
|
||||
// set the handlers that are applied.
|
||||
.childChannelInitializer { channel in
|
||||
channel.eventLoop.makeCompletedFuture {
|
||||
try channel.pipeline.syncOperations.addHandler(BackPressureHandler())
|
||||
try channel.pipeline.syncOperations.addHandler(EchoHandler())
|
||||
}
|
||||
}
|
||||
.childChannelOption(.socketOption(.so_reuseaddr), value: 1)
|
||||
.childChannelOption(.maxMessagesPerRead, value: 16)
|
||||
.childChannelOption(.recvAllocator, value: AdaptiveRecvByteBufferAllocator())
|
||||
|
||||
defer { try? group.syncShutdownGracefully() }
|
||||
|
||||
// First argument is the program path
|
||||
let arguments = CommandLine.arguments
|
||||
let arg1 = arguments.dropFirst().first
|
||||
let arg2 = arguments.dropFirst(2).first
|
||||
|
||||
let defaultHost = "::1"
|
||||
let defaultPort = 9999
|
||||
|
||||
struct BindTo {
|
||||
let host: String
|
||||
let port: Int
|
||||
}
|
||||
|
||||
let bindTarget: BindTo
|
||||
switch (arg1, arg1.flatMap(Int.init), arg2.flatMap(Int.init)) {
|
||||
case let (_, .some(port), _):
|
||||
bindTarget = .init(host: defaultHost, port: port)
|
||||
case let (.some(host), _, .some(port)):
|
||||
bindTarget = .init(host: host, port: port)
|
||||
case let (.some(host), .none, .none):
|
||||
bindTarget = .init(host: host, port: defaultPort)
|
||||
default:
|
||||
bindTarget = .init(host: defaultHost, port: defaultPort)
|
||||
}
|
||||
|
||||
let channel = try bootstrap.bind(host: bindTarget.host, port: bindTarget.port).wait()
|
||||
|
||||
print("Server started and listening on: \(channel.localAddress!)")
|
||||
|
||||
try channel.closeFuture.wait()
|
||||
|
||||
print("Server closed!")
|
||||
Reference in New Issue
Block a user