123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- import Foundation
- import NIO
- import NIOHTTP1
- struct JSONTestResponse: Encodable {
- let message = "Hello, World!"
- }
- enum Constants {
- static let httpVersion = HTTPVersion(major: 1, minor: 1)
- static let serverName = "SwiftNIO"
- static let plainTextResponse: StaticString = "Hello, World!"
- static let plainTextResponseLength = plainTextResponse.utf8CodeUnitCount
- static let plainTextResponseLengthString = String(plainTextResponseLength)
- static let jsonResponseLength = try! JSONEncoder().encode(JSONTestResponse()).count
- static let jsonResponseLengthString = String(jsonResponseLength)
- }
- private final class HTTPHandler: ChannelInboundHandler {
- public typealias InboundIn = HTTPServerRequestPart
- public typealias OutboundOut = HTTPServerResponsePart
- let dateFormatter = RFC1123DateFormatter()
- let jsonEncoder = JSONEncoder()
- var plaintextBuffer: ByteBuffer!
- var jsonBuffer: ByteBuffer!
- init() {
- let allocator = ByteBufferAllocator()
- plaintextBuffer = allocator.buffer(capacity: Constants.plainTextResponseLength)
- plaintextBuffer.writeStaticString(Constants.plainTextResponse)
- jsonBuffer = allocator.buffer(capacity: Constants.jsonResponseLength)
- }
- func channelRead(context: ChannelHandlerContext, data: NIOAny) {
- let reqPart = self.unwrapInboundIn(data)
- switch reqPart {
- case .head(let request):
- switch request.uri {
- case "/plaintext":
- processPlaintext(context: context)
- case "/json":
- processJSON(context: context)
- default:
- _ = context.close()
- }
- case .body:
- break
- case .end:
- _ = context.write(self.wrapOutboundOut(.end(nil)))
- }
- }
- func channelReadComplete(context: ChannelHandlerContext) {
- context.flush()
- context.fireChannelReadComplete()
- }
- private func processPlaintext(context: ChannelHandlerContext) {
- let responseHead = plainTextResponseHead(contentLength: Constants.plainTextResponseLengthString)
- context.write(self.wrapOutboundOut(.head(responseHead)), promise: nil)
- context.write(self.wrapOutboundOut(.body(.byteBuffer(plaintextBuffer))), promise: nil)
- }
- private func processJSON(context: ChannelHandlerContext) {
- let responseHead = jsonResponseHead(contentLength: Constants.jsonResponseLengthString)
- context.write(self.wrapOutboundOut(.head(responseHead)), promise: nil)
- let responseData = try! jsonEncoder.encode(JSONTestResponse())
- jsonBuffer.clear()
- jsonBuffer.writeBytes(responseData)
- context.write(self.wrapOutboundOut(.body(.byteBuffer(jsonBuffer))), promise: nil)
- }
- private func jsonResponseHead(contentLength: String) -> HTTPResponseHead {
- return responseHead(contentType: "application/json", contentLength: contentLength)
- }
- private func plainTextResponseHead(contentLength: String) -> HTTPResponseHead {
- return responseHead(contentType: "text/plain", contentLength: contentLength)
- }
- private func responseHead(contentType: String, contentLength: String) -> HTTPResponseHead {
- var headers = HTTPHeaders()
- headers.add(name: "content-type", value: contentType)
- headers.add(name: "content-length", value: contentLength)
- headers.add(name: "server", value: Constants.serverName)
- headers.add(name: "date", value: dateFormatter.getDate())
- return HTTPResponseHead(version: Constants.httpVersion,
- status: .ok,
- headers: headers)
- }
- }
- let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
- let bootstrap = ServerBootstrap(group: group)
- .serverChannelOption(ChannelOptions.backlog, value: 8192)
- .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
- .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_TCP), TCP_NODELAY), value: 1)
- .childChannelInitializer { channel in
- channel.pipeline.configureHTTPServerPipeline(withPipeliningAssistance: false).flatMap {
- channel.pipeline.addHandler(HTTPHandler())
- }
- }
- .childChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
- .childChannelOption(ChannelOptions.maxMessagesPerRead, value: 16)
- .childChannelOption(ChannelOptions.recvAllocator, value: AdaptiveRecvByteBufferAllocator())
- defer {
- try! group.syncShutdownGracefully()
- }
- let channel = try! bootstrap.bind(host: "0.0.0.0", port: 8080).wait()
- try! channel.closeFuture.wait()
|