main.swift 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import Foundation
  2. import NIO
  3. import NIOHTTP1
  4. struct JSONTestResponse: Encodable {
  5. let message = "Hello, World!"
  6. }
  7. enum Constants {
  8. static let httpVersion = HTTPVersion(major: 1, minor: 1)
  9. static let serverName = "SwiftNIO"
  10. static let plainTextResponse: StaticString = "Hello, World!"
  11. static let plainTextResponseLength = plainTextResponse.utf8CodeUnitCount
  12. static let plainTextResponseLengthString = String(plainTextResponseLength)
  13. static let jsonResponseLength = try! JSONEncoder().encode(JSONTestResponse()).count
  14. static let jsonResponseLengthString = String(jsonResponseLength)
  15. }
  16. private final class HTTPHandler: ChannelInboundHandler {
  17. public typealias InboundIn = HTTPServerRequestPart
  18. public typealias OutboundOut = HTTPServerResponsePart
  19. let dateFormatter = RFC1123DateFormatter()
  20. let jsonEncoder = JSONEncoder()
  21. var plaintextBuffer: ByteBuffer!
  22. var jsonBuffer: ByteBuffer!
  23. init() {
  24. let allocator = ByteBufferAllocator()
  25. plaintextBuffer = allocator.buffer(capacity: Constants.plainTextResponseLength)
  26. plaintextBuffer.writeStaticString(Constants.plainTextResponse)
  27. jsonBuffer = allocator.buffer(capacity: Constants.jsonResponseLength)
  28. }
  29. func channelRead(context: ChannelHandlerContext, data: NIOAny) {
  30. let reqPart = self.unwrapInboundIn(data)
  31. switch reqPart {
  32. case .head(let request):
  33. switch request.uri {
  34. case "/plaintext":
  35. processPlaintext(context: context)
  36. case "/json":
  37. processJSON(context: context)
  38. default:
  39. _ = context.close()
  40. }
  41. case .body:
  42. break
  43. case .end:
  44. _ = context.write(self.wrapOutboundOut(.end(nil)))
  45. }
  46. }
  47. func channelReadComplete(context: ChannelHandlerContext) {
  48. context.flush()
  49. context.fireChannelReadComplete()
  50. }
  51. private func processPlaintext(context: ChannelHandlerContext) {
  52. let responseHead = plainTextResponseHead(contentLength: Constants.plainTextResponseLengthString)
  53. context.write(self.wrapOutboundOut(.head(responseHead)), promise: nil)
  54. context.write(self.wrapOutboundOut(.body(.byteBuffer(plaintextBuffer))), promise: nil)
  55. }
  56. private func processJSON(context: ChannelHandlerContext) {
  57. let responseHead = jsonResponseHead(contentLength: Constants.jsonResponseLengthString)
  58. context.write(self.wrapOutboundOut(.head(responseHead)), promise: nil)
  59. let responseData = try! jsonEncoder.encode(JSONTestResponse())
  60. jsonBuffer.clear()
  61. jsonBuffer.writeBytes(responseData)
  62. context.write(self.wrapOutboundOut(.body(.byteBuffer(jsonBuffer))), promise: nil)
  63. }
  64. private func jsonResponseHead(contentLength: String) -> HTTPResponseHead {
  65. return responseHead(contentType: "application/json", contentLength: contentLength)
  66. }
  67. private func plainTextResponseHead(contentLength: String) -> HTTPResponseHead {
  68. return responseHead(contentType: "text/plain", contentLength: contentLength)
  69. }
  70. private func responseHead(contentType: String, contentLength: String) -> HTTPResponseHead {
  71. var headers = HTTPHeaders()
  72. headers.add(name: "content-type", value: contentType)
  73. headers.add(name: "content-length", value: contentLength)
  74. headers.add(name: "server", value: Constants.serverName)
  75. headers.add(name: "date", value: dateFormatter.getDate())
  76. return HTTPResponseHead(version: Constants.httpVersion,
  77. status: .ok,
  78. headers: headers)
  79. }
  80. }
  81. let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
  82. let bootstrap = ServerBootstrap(group: group)
  83. .serverChannelOption(ChannelOptions.backlog, value: 8192)
  84. .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
  85. .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_TCP), TCP_NODELAY), value: 1)
  86. .childChannelInitializer { channel in
  87. channel.pipeline.configureHTTPServerPipeline(withPipeliningAssistance: false).flatMap {
  88. channel.pipeline.addHandler(HTTPHandler())
  89. }
  90. }
  91. .childChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
  92. .childChannelOption(ChannelOptions.maxMessagesPerRead, value: 16)
  93. .childChannelOption(ChannelOptions.recvAllocator, value: AdaptiveRecvByteBufferAllocator())
  94. defer {
  95. try! group.syncShutdownGracefully()
  96. }
  97. let channel = try! bootstrap.bind(host: "0.0.0.0", port: 8080).wait()
  98. try! channel.closeFuture.wait()