Quellcode durchsuchen

Make server CallHandlers more internal (#657)

Motivation:

To avoid breaking API changes in the future we should keep our public
API surface as small as possible.

Modifications:

Make the server `BaseCallHandler` underscore-internal.

Result:

Smaller public API.
George Barnett vor 6 Jahren
Ursprung
Commit
9590c9ca2a

+ 11 - 5
Sources/GRPC/CallHandlers/BidirectionalStreamingCallHandler.swift

@@ -25,7 +25,10 @@ import Logging
 ///   If the framework user wants to return a call error (e.g. in case of authentication failure),
 ///   they can fail the observer block future.
 /// - To close the call and send the status, complete `context.statusPromise`.
-public class BidirectionalStreamingCallHandler<RequestMessage: Message, ResponseMessage: Message>: BaseCallHandler<RequestMessage, ResponseMessage> {
+public class BidirectionalStreamingCallHandler<
+  RequestMessage: Message,
+  ResponseMessage: Message
+>: _BaseCallHandler<RequestMessage, ResponseMessage> {
   public typealias Context = StreamingResponseCallContext<ResponseMessage>
   public typealias EventObserver = (StreamEvent<RequestMessage>) -> Void
   public typealias EventObserverFactory = (Context) -> EventLoopFuture<EventObserver>
@@ -39,7 +42,10 @@ public class BidirectionalStreamingCallHandler<RequestMessage: Message, Response
 
   // We ask for a future of type `EventObserver` to allow the framework user to e.g. asynchronously authenticate a call.
   // If authentication fails, they can simply fail the observer future, which causes the call to be terminated.
-  public init(callHandlerContext: CallHandlerContext, eventObserverFactory: @escaping (StreamingResponseCallContext<ResponseMessage>) -> EventLoopFuture<EventObserver>) {
+  public init(
+    callHandlerContext: CallHandlerContext,
+    eventObserverFactory: @escaping (StreamingResponseCallContext<ResponseMessage>) -> EventLoopFuture<EventObserver>
+  ) {
     // Delay the creation of the event observer until `handlerAdded(context:)`, otherwise it is
     // possible for the service to write into the pipeline (by fulfilling the status promise
     // of the call context outside of the observer) before it has been configured.
@@ -80,7 +86,7 @@ public class BidirectionalStreamingCallHandler<RequestMessage: Message, Response
     eventObserver.cascadeFailure(to: callContext.statusPromise)
   }
 
-  public override func processMessage(_ message: RequestMessage) {
+  internal override func processMessage(_ message: RequestMessage) {
     guard case .created(let eventObserver) = self.observerState else {
       self.logger.warning("expecting observerState to be .created but was \(self.observerState), ignoring message \(message)")
       return
@@ -90,7 +96,7 @@ public class BidirectionalStreamingCallHandler<RequestMessage: Message, Response
     }
   }
 
-  public override func endOfStreamReceived() throws {
+  internal override func endOfStreamReceived() throws {
     guard case .created(let eventObserver) = self.observerState else {
       self.logger.warning("expecting observerState to be .created but was \(self.observerState), ignoring end-of-stream call")
       return
@@ -100,7 +106,7 @@ public class BidirectionalStreamingCallHandler<RequestMessage: Message, Response
     }
   }
 
-  override func sendErrorStatus(_ status: GRPCStatus) {
+  internal override func sendErrorStatus(_ status: GRPCStatus) {
     self.callContext?.statusPromise.fail(status)
   }
 }

+ 7 - 4
Sources/GRPC/CallHandlers/ClientStreamingCallHandler.swift

@@ -33,7 +33,10 @@ enum ClientStreamingHandlerObserverState<Factory, Observer> {
 ///   If the framework user wants to return a call error (e.g. in case of authentication failure),
 ///   they can fail the observer block future.
 /// - To close the call and send the response, complete `context.responsePromise`.
-public class ClientStreamingCallHandler<RequestMessage: Message, ResponseMessage: Message>: BaseCallHandler<RequestMessage, ResponseMessage> {
+public final class ClientStreamingCallHandler<
+  RequestMessage: Message,
+  ResponseMessage: Message
+>: _BaseCallHandler<RequestMessage, ResponseMessage> {
   public typealias Context = UnaryResponseCallContext<ResponseMessage>
   public typealias EventObserver = (StreamEvent<RequestMessage>) -> Void
   public typealias EventObserverFactory = (Context) -> EventLoopFuture<EventObserver>
@@ -88,7 +91,7 @@ public class ClientStreamingCallHandler<RequestMessage: Message, ResponseMessage
     eventObserver.cascadeFailure(to: callContext.responsePromise)
   }
 
-  public override func processMessage(_ message: RequestMessage) {
+  internal override func processMessage(_ message: RequestMessage) {
     guard case .created(let eventObserver) = self.observerState else {
       self.logger.warning("expecting observerState to be .created but was \(self.observerState), ignoring message \(message)")
       return
@@ -98,7 +101,7 @@ public class ClientStreamingCallHandler<RequestMessage: Message, ResponseMessage
     }
   }
 
-  public override func endOfStreamReceived() throws {
+  internal override func endOfStreamReceived() throws {
     guard case .created(let eventObserver) = self.observerState else {
       self.logger.warning("expecting observerState to be .created but was \(self.observerState), ignoring end-of-stream call")
       return
@@ -108,7 +111,7 @@ public class ClientStreamingCallHandler<RequestMessage: Message, ResponseMessage
     }
   }
 
-  override func sendErrorStatus(_ status: GRPCStatus) {
+  internal override func sendErrorStatus(_ status: GRPCStatus) {
     self.callContext?.responsePromise.fail(status)
   }
 }

+ 13 - 7
Sources/GRPC/CallHandlers/ServerStreamingCallHandler.swift

@@ -23,13 +23,19 @@ import Logging
 ///
 /// - The observer block is implemented by the framework user and calls `context.sendResponse` as needed.
 /// - To close the call and send the status, complete the status future returned by the observer block.
-public class ServerStreamingCallHandler<RequestMessage: Message, ResponseMessage: Message>: BaseCallHandler<RequestMessage, ResponseMessage> {
+public final class ServerStreamingCallHandler<
+  RequestMessage: Message,
+  ResponseMessage: Message
+>: _BaseCallHandler<RequestMessage, ResponseMessage> {
   public typealias EventObserver = (RequestMessage) -> EventLoopFuture<GRPCStatus>
-  private var eventObserver: EventObserver?
 
+  private var eventObserver: EventObserver?
   private var callContext: StreamingResponseCallContext<ResponseMessage>?
 
-  public init(callHandlerContext: CallHandlerContext, eventObserverFactory: (StreamingResponseCallContext<ResponseMessage>) -> EventObserver) {
+  public init(
+    callHandlerContext: CallHandlerContext,
+    eventObserverFactory: (StreamingResponseCallContext<ResponseMessage>) -> EventObserver
+  ) {
     super.init(callHandlerContext: callHandlerContext)
     let callContext = StreamingResponseCallContextImpl<ResponseMessage>(
       channel: self.callHandlerContext.channel,
@@ -47,7 +53,7 @@ public class ServerStreamingCallHandler<RequestMessage: Message, ResponseMessage
     }
   }
 
-  public override func processMessage(_ message: RequestMessage) throws {
+  override internal func processMessage(_ message: RequestMessage) throws {
     guard let eventObserver = self.eventObserver,
       let callContext = self.callContext else {
         self.logger.error("processMessage(_:) called before the call started or after the call completed")
@@ -56,18 +62,18 @@ public class ServerStreamingCallHandler<RequestMessage: Message, ResponseMessage
 
     let resultFuture = eventObserver(message)
     resultFuture
-      // Fulfill the status promise with whatever status the framework user has provided.
+      // Fulfil the status promise with whatever status the framework user has provided.
       .cascade(to: callContext.statusPromise)
     self.eventObserver = nil
   }
 
-  public override func endOfStreamReceived() throws {
+  override internal func endOfStreamReceived() throws {
     if self.eventObserver != nil {
       throw GRPCError.server(.noRequestsButOneExpected)
     }
   }
 
-  override func sendErrorStatus(_ status: GRPCStatus) {
+  override internal func sendErrorStatus(_ status: GRPCStatus) {
     self.callContext?.statusPromise.fail(status)
   }
 }

+ 12 - 7
Sources/GRPC/CallHandlers/UnaryCallHandler.swift

@@ -24,13 +24,18 @@ import Logging
 /// - The observer block is implemented by the framework user and returns a future containing the call result.
 /// - To return a response to the client, the framework user should complete that future
 ///   (similar to e.g. serving regular HTTP requests in frameworks such as Vapor).
-public class UnaryCallHandler<RequestMessage: Message, ResponseMessage: Message>: BaseCallHandler<RequestMessage, ResponseMessage> {
+public final class UnaryCallHandler<
+  RequestMessage: Message,
+  ResponseMessage: Message
+>: _BaseCallHandler<RequestMessage, ResponseMessage> {
   public typealias EventObserver = (RequestMessage) -> EventLoopFuture<ResponseMessage>
   private var eventObserver: EventObserver?
-
   private var callContext: UnaryResponseCallContext<ResponseMessage>?
 
-  public init(callHandlerContext: CallHandlerContext, eventObserverFactory: (UnaryResponseCallContext<ResponseMessage>) -> EventObserver) {
+  public init(
+    callHandlerContext: CallHandlerContext,
+    eventObserverFactory: (UnaryResponseCallContext<ResponseMessage>) -> EventObserver
+  ) {
     super.init(callHandlerContext: callHandlerContext)
     let callContext = UnaryResponseCallContextImpl<ResponseMessage>(
       channel: self.callHandlerContext.channel,
@@ -48,7 +53,7 @@ public class UnaryCallHandler<RequestMessage: Message, ResponseMessage: Message>
     }
   }
 
-  public override func processMessage(_ message: RequestMessage) throws {
+  internal override func processMessage(_ message: RequestMessage) throws {
     guard let eventObserver = self.eventObserver,
       let context = self.callContext else {
       self.logger.error("processMessage(_:) called before the call started or after the call completed")
@@ -57,18 +62,18 @@ public class UnaryCallHandler<RequestMessage: Message, ResponseMessage: Message>
 
     let resultFuture = eventObserver(message)
     resultFuture
-      // Fulfill the response promise with whatever response (or error) the framework user has provided.
+      // Fulfil the response promise with whatever response (or error) the framework user has provided.
       .cascade(to: context.responsePromise)
     self.eventObserver = nil
   }
 
-  public override func endOfStreamReceived() throws {
+  internal override func endOfStreamReceived() throws {
     if self.eventObserver != nil {
       throw GRPCError.server(.noRequestsButOneExpected)
     }
   }
 
-  override func sendErrorStatus(_ status: GRPCStatus) {
+  internal override func sendErrorStatus(_ status: GRPCStatus) {
     callContext?.responsePromise.fail(status)
   }
 }

+ 24 - 22
Sources/GRPC/CallHandlers/BaseCallHandler.swift → Sources/GRPC/CallHandlers/_BaseCallHandler.swift

@@ -22,34 +22,36 @@ import Logging
 /// Provides a means for decoding incoming gRPC messages into protobuf objects.
 ///
 /// Calls through to `processMessage` for individual messages it receives, which needs to be implemented by subclasses.
-public class BaseCallHandler<RequestMessage: Message, ResponseMessage: Message>: GRPCCallHandler {
-  public func makeGRPCServerCodec() -> ChannelHandler { return GRPCServerCodec<RequestMessage, ResponseMessage>() }
+/// - Important: This is **NOT** part of the public API.
+public class _BaseCallHandler<RequestMessage: Message, ResponseMessage: Message>: GRPCCallHandler {
+  public func makeGRPCServerCodec() -> ChannelHandler {
+    return GRPCServerCodec<RequestMessage, ResponseMessage>()
+  }
 
   /// Called whenever a message has been received.
   ///
   /// Overridden by subclasses.
-  public func processMessage(_ message: RequestMessage) throws {
+  internal func processMessage(_ message: RequestMessage) throws {
     fatalError("needs to be overridden")
   }
 
-  /// Needs to be implemented by this class so that subclasses can override it.
-  ///
-  /// Otherwise, the subclass's implementation will simply never be called (probably because the protocol's default
-  /// implementation in an extension is being used instead).
-  public func handlerAdded(context: ChannelHandlerContext) { }
-
   /// Called when the client has half-closed the stream, indicating that they won't send any further data.
   ///
   /// Overridden by subclasses if the "end-of-stream" event is relevant.
-  public func endOfStreamReceived() throws { }
+  internal func endOfStreamReceived() throws { }
+
+  /// Sends an error status to the client while ensuring that all call context promises are fulfilled.
+  /// Because only the concrete call subclass knows which promises need to be fulfilled, this method needs to be overridden.
+  internal func sendErrorStatus(_ status: GRPCStatus) {
+    fatalError("needs to be overridden")
+  }
 
   /// Whether this handler can still write messages to the client.
   private var serverCanWrite = true
 
   internal let callHandlerContext: CallHandlerContext
 
-  /// Called for each error received in `errorCaught(context:error:)`.
-  private var errorDelegate: ServerErrorDelegate? {
+  internal var errorDelegate: ServerErrorDelegate? {
     return self.callHandlerContext.errorDelegate
   }
 
@@ -57,27 +59,27 @@ public class BaseCallHandler<RequestMessage: Message, ResponseMessage: Message>:
     return self.callHandlerContext.logger
   }
 
-  public init(callHandlerContext: CallHandlerContext) {
+  internal init(callHandlerContext: CallHandlerContext) {
     self.callHandlerContext = callHandlerContext
   }
 
-  /// Sends an error status to the client while ensuring that all call context promises are fulfilled.
-  /// Because only the concrete call subclass knows which promises need to be fulfilled, this method needs to be overridden.
-  func sendErrorStatus(_ status: GRPCStatus) {
-    fatalError("needs to be overridden")
-  }
+  /// Needs to be implemented by this class so that subclasses can override it.
+  ///
+  /// Otherwise, the subclass's implementation will simply never be called (probably because the protocol's default
+  /// implementation in an extension is being used instead).
+  public func handlerAdded(context: ChannelHandlerContext) { }
 }
 
-extension BaseCallHandler: ChannelInboundHandler {
+extension _BaseCallHandler: ChannelInboundHandler {
   public typealias InboundIn = GRPCServerRequestPart<RequestMessage>
 
   /// Passes errors to the user-provided `errorHandler`. After an error has been received an
   /// appropriate status is written. Errors which don't conform to `GRPCStatusTransformable`
   /// return a status with code `.internalError`.
   public func errorCaught(context: ChannelHandlerContext, error: Error) {
-    errorDelegate?.observeLibraryError(error)
+    self.errorDelegate?.observeLibraryError(error)
 
-    let status = errorDelegate?.transformLibraryError(error)
+    let status = self.errorDelegate?.transformLibraryError(error)
       ?? (error as? GRPCStatusTransformable)?.asGRPCStatus()
       ?? .processingError
     self.sendErrorStatus(status)
@@ -109,7 +111,7 @@ extension BaseCallHandler: ChannelInboundHandler {
   }
 }
 
-extension BaseCallHandler: ChannelOutboundHandler {
+extension _BaseCallHandler: ChannelOutboundHandler {
   public typealias OutboundIn = GRPCServerResponsePart<ResponseMessage>
   public typealias OutboundOut = GRPCServerResponsePart<ResponseMessage>