feat: Initial echo server
This commit is contained in:
7
.editorconfig
Normal file
7
.editorconfig
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*.swift]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
tab_width = 2
|
||||||
|
trim_trailing_whitespace = true
|
||||||
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.DS_Store
|
||||||
|
/.build
|
||||||
|
/Packages
|
||||||
|
xcuserdata/
|
||||||
|
DerivedData/
|
||||||
|
.swiftpm/configuration/registries.json
|
||||||
|
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||||
|
.netrc
|
||||||
11
.swiftformat
Normal file
11
.swiftformat
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
--self init-only
|
||||||
|
--indent 2
|
||||||
|
--ifdef indent
|
||||||
|
--trimwhitespace always
|
||||||
|
--wraparguments before-first
|
||||||
|
--wrapparameters before-first
|
||||||
|
--wrapcollections preserve
|
||||||
|
--wrapconditions after-first
|
||||||
|
--typeblanklines preserve
|
||||||
|
--commas inline
|
||||||
|
--stripunusedargs closure-only
|
||||||
9
.swiftlint.yml
Normal file
9
.swiftlint.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
disabled_rules:
|
||||||
|
- closing_brace
|
||||||
|
- fuction_body_length
|
||||||
|
|
||||||
|
included:
|
||||||
|
- Sources
|
||||||
|
- Tests
|
||||||
|
|
||||||
|
ignore_multiline_statement_conditions: true
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1610"
|
||||||
|
version = "1.7">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "nio-echo"
|
||||||
|
BuildableName = "nio-echo"
|
||||||
|
BlueprintName = "nio-echo"
|
||||||
|
ReferencedContainer = "container:">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "nio-echo"
|
||||||
|
BuildableName = "nio-echo"
|
||||||
|
BlueprintName = "nio-echo"
|
||||||
|
ReferencedContainer = "container:">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "nio-echo"
|
||||||
|
BuildableName = "nio-echo"
|
||||||
|
BlueprintName = "nio-echo"
|
||||||
|
ReferencedContainer = "container:">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
42
Package.resolved
Normal file
42
Package.resolved
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"originHash" : "20f1c21ae87f9bea31b5f7dfef662b3911d92dc048f13b9fb09d350230df3c34",
|
||||||
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "swift-atomics",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-atomics.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "cd142fd2f64be2100422d658e7411e39489da985",
|
||||||
|
"version" : "1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-collections",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-collections.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "671108c96644956dddcd89dd59c203dcdb36cec7",
|
||||||
|
"version" : "1.1.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-nio",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-nio.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "914081701062b11e3bb9e21accc379822621995e",
|
||||||
|
"version" : "2.76.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-system",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-system.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "c8a44d836fe7913603e246acab7c528c2e780168",
|
||||||
|
"version" : "1.4.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 3
|
||||||
|
}
|
||||||
25
Package.swift
Normal file
25
Package.swift
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// swift-tools-version: 6.0
|
||||||
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||||
|
|
||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
let package = Package(
|
||||||
|
name: "swift-nio-echo",
|
||||||
|
platforms: [
|
||||||
|
.macOS(.v15)
|
||||||
|
],
|
||||||
|
products: [
|
||||||
|
.executable(name: "nio-echo", targets: ["NIOEcho"])
|
||||||
|
],
|
||||||
|
dependencies: [
|
||||||
|
.package(url: "https://github.com/apple/swift-nio.git", from: "2.76.1")
|
||||||
|
],
|
||||||
|
targets: [
|
||||||
|
.executableTarget(
|
||||||
|
name: "NIOEcho",
|
||||||
|
dependencies: [
|
||||||
|
.product(name: "NIO", package: "swift-nio")
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
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