GRPCServer.swift 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. import Foundation
  2. import NIO
  3. import NIOHTTP1
  4. import NIOHTTP2
  5. /// Wrapper object to manage the lifecycle of a gRPC server.
  6. public final class GRPCServer {
  7. /// Starts up a server that serves the given providers.
  8. ///
  9. /// - Returns: A future that is completed when the server has successfully started up.
  10. public static func start(
  11. hostname: String,
  12. port: Int,
  13. eventLoopGroup: EventLoopGroup,
  14. serviceProviders: [CallHandlerProvider]) -> EventLoopFuture<GRPCServer> {
  15. let servicesByName = Dictionary(uniqueKeysWithValues: serviceProviders.map { ($0.serviceName, $0) })
  16. let bootstrap = ServerBootstrap(group: eventLoopGroup)
  17. // Specify a backlog to avoid overloading the server.
  18. .serverChannelOption(ChannelOptions.backlog, value: 256)
  19. // Enable `SO_REUSEADDR` to avoid "address already in use" error.
  20. .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
  21. // Set the handlers that are applied to the accepted Channels
  22. .childChannelInitializer { channel in
  23. //! FIXME: Add an option for gRPC-via-HTTP1 (pPRC).
  24. return channel.pipeline.add(handler: HTTP2Parser(mode: .server)).then {
  25. let multiplexer = HTTP2StreamMultiplexer { (channel, streamID) -> EventLoopFuture<Void> in
  26. return channel.pipeline.add(handler: HTTP2ToHTTP1ServerCodec(streamID: streamID))
  27. .then { channel.pipeline.add(handler: HTTP1ToRawGRPCServerCodec()) }
  28. .then { channel.pipeline.add(handler: GRPCChannelHandler(servicesByName: servicesByName)) }
  29. }
  30. return channel.pipeline.add(handler: multiplexer)
  31. }
  32. }
  33. // Enable TCP_NODELAY and SO_REUSEADDR for the accepted Channels
  34. .childChannelOption(ChannelOptions.socket(IPPROTO_TCP, TCP_NODELAY), value: 1)
  35. .childChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
  36. return bootstrap.bind(host: hostname, port: port)
  37. .map { GRPCServer(channel: $0) }
  38. }
  39. private let channel: Channel
  40. private init(channel: Channel) {
  41. self.channel = channel
  42. }
  43. /// Fired when the server shuts down.
  44. public var onClose: EventLoopFuture<Void> {
  45. return channel.closeFuture
  46. }
  47. public func close() -> EventLoopFuture<Void> {
  48. return channel.close(mode: .all)
  49. }
  50. }