2
0

GRPCServer.swift 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  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],
  15. errorDelegate: ServerErrorDelegate? = LoggingServerErrorDelegate()
  16. ) -> EventLoopFuture<GRPCServer> {
  17. let servicesByName = Dictionary(uniqueKeysWithValues: serviceProviders.map { ($0.serviceName, $0) })
  18. let bootstrap = ServerBootstrap(group: eventLoopGroup)
  19. // Specify a backlog to avoid overloading the server.
  20. .serverChannelOption(ChannelOptions.backlog, value: 256)
  21. // Enable `SO_REUSEADDR` to avoid "address already in use" error.
  22. .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
  23. // Set the handlers that are applied to the accepted Channels
  24. .childChannelInitializer { channel in
  25. return channel.pipeline.add(handler: HTTPProtocolSwitcher {
  26. channel -> EventLoopFuture<Void> in
  27. return channel.pipeline.add(handler: HTTP1ToRawGRPCServerCodec())
  28. .then { channel.pipeline.add(handler: GRPCChannelHandler(servicesByName: servicesByName, errorDelegate: errorDelegate)) }
  29. })
  30. }
  31. // Enable TCP_NODELAY and SO_REUSEADDR for the accepted Channels
  32. .childChannelOption(ChannelOptions.socket(IPPROTO_TCP, TCP_NODELAY), value: 1)
  33. .childChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
  34. return bootstrap.bind(host: hostname, port: port)
  35. .map { GRPCServer(channel: $0, errorDelegate: errorDelegate) }
  36. }
  37. private let channel: Channel
  38. private var errorDelegate: ServerErrorDelegate?
  39. private init(channel: Channel, errorDelegate: ServerErrorDelegate?) {
  40. self.channel = channel
  41. // Maintain a strong reference to ensure it lives as long as the server.
  42. self.errorDelegate = errorDelegate
  43. // nil out errorDelegate to avoid retain cycles.
  44. onClose.whenComplete {
  45. self.errorDelegate = nil
  46. }
  47. }
  48. /// Fired when the server shuts down.
  49. public var onClose: EventLoopFuture<Void> {
  50. return channel.closeFuture
  51. }
  52. /// Shut down the server; this should be called to avoid leaking resources.
  53. public func close() -> EventLoopFuture<Void> {
  54. return channel.close(mode: .all)
  55. }
  56. }