| /* |
| * |
| * Copyright 2019 gRPC authors. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| /** |
| * \file GRPCInterceptor.h |
| * API for interceptors implementation. This feature is currently EXPERIMENTAL and is subject to |
| * breaking changes without prior notice. |
| * |
| * The interceptors in the gRPC system forms a chain. When a call is made by the user, each |
| * interceptor on the chain has chances to react to events of the call and make necessary |
| * modifications to the call's parameters, data, metadata, or flow. |
| * |
| * \verbatim |
| ----------- |
| | GRPCCall2 | |
| ----------- |
| | |
| | |
| -------------------------- |
| | GRPCInterceptorManager 1 | |
| -------------------------- |
| | GRPCInterceptor 1 | |
| -------------------------- |
| | |
| ... |
| | |
| -------------------------- |
| | GRPCInterceptorManager N | |
| -------------------------- |
| | GRPCInterceptor N | |
| -------------------------- |
| | |
| | |
| ------------------ |
| | GRPCCallInternal | |
| ------------------ |
| \endverbatim |
| * |
| * The chain of interceptors is initialized when the corresponding GRPCCall2 object or proto call |
| * object (GRPCUnaryProtoCall and GRPCStreamingProtoCall) is initialized. The initialization of the |
| * chain is controlled by the property interceptorFactories in the callOptions parameter of the |
| * corresponding call object. Property interceptorFactories is an array of |
| * id<GRPCInterceptorFactory> objects provided by the user. When a call object is initialized, each |
| * interceptor factory generates an interceptor object for the call. gRPC internally links the |
| * interceptors with each other and with the actual call object. The order of the interceptors in |
| * the chain is exactly the same as the order of factory objects in interceptorFactories property. |
| * All requests (start, write, finish, cancel, receive next) initiated by the user will be processed |
| * in the order of interceptors, and all responses (initial metadata, data, trailing metadata, write |
| * data done) are processed in the reverse order. |
| * |
| * Each interceptor in the interceptor chain should behave as a user of the next interceptor, and at |
| * the same time behave as a call to the previous interceptor. Therefore interceptor implementations |
| * must follow the state transition of gRPC calls and must also forward events that are consistent |
| * with the current state of the next/previous interceptor. They should also make sure that the |
| * events they forwarded to the next and previous interceptors will, in the end, make the neighbour |
| * interceptor terminate correctly and reaches "finished" state. The diagram below shows the state |
| * transitions. Any event not appearing on the diagram means the event is not permitted for that |
| * particular state. |
| * |
| * \verbatim |
| writeData |
| receiveNextMessages |
| didReceiveInitialMetadata |
| didReceiveData |
| didWriteData receiveNextmessages |
| writeData ----- ----- ---- didReceiveInitialMetadata |
| receiveNextMessages | | | | | | didReceiveData |
| | V | V | V didWriteData |
| ------------- start --------- finish ------------ |
| | initialized | -----> | started | --------> | half-close | |
| ------------- --------- ------------ |
| | | | |
| | | didClose | didClose |
| |cancel | cancel | cancel |
| | V | |
| | ---------- | |
| --------------> | finished | <-------------- |
| ---------- |
| | ^ writeData |
| | | finish |
| ------ cancel |
| receiveNextMessages |
| \endverbatim |
| * |
| * An interceptor must forward responses to its previous interceptor in the order of initial |
| * metadata, message(s), and trailing metadata. Forwarding responses out of this order (e.g. |
| * forwarding a message before initial metadata) is not allowed. |
| * |
| * Events of requests and responses are dispatched to interceptor objects using the interceptor's |
| * dispatch queue. The dispatch queue should be serial queue to make sure the events are processed |
| * in order. Interceptor implementations must derive from GRPCInterceptor class. The class makes |
| * some basic implementation of all methods responding to an event of a call. If an interceptor does |
| * not care about a particular event, it can use the basic implementation of the GRPCInterceptor |
| * class, which simply forward the event to the next or previous interceptor in the chain. |
| * |
| * The interceptor object should be unique for each call since the call context is not passed to the |
| * interceptor object in a call event. However, the interceptors can be implemented to share states |
| * by receiving state sharing object from the factory upon construction. |
| */ |
| |
| #import "GRPCCall.h" |
| #import "GRPCDispatchable.h" |
| |
| NS_ASSUME_NONNULL_BEGIN |
| |
| @class GRPCInterceptorManager; |
| @class GRPCInterceptor; |
| @class GRPCRequestOptions; |
| @class GRPCCallOptions; |
| @protocol GRPCResponseHandler; |
| |
| /** |
| * The GRPCInterceptorInterface defines the request events that can occur to an interceptor. |
| */ |
| @protocol GRPCInterceptorInterface<NSObject, GRPCDispatchable> |
| |
| /** |
| * To start the call. This method will only be called once for each instance. |
| */ |
| - (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions |
| callOptions:(GRPCCallOptions *)callOptions; |
| |
| /** |
| * To write data to the call. |
| */ |
| - (void)writeData:(id)data; |
| |
| /** |
| * To finish the stream of requests. |
| */ |
| - (void)finish; |
| |
| /** |
| * To cancel the call. |
| */ |
| - (void)cancel; |
| |
| /** |
| * To indicate the call that the previous interceptor is ready to receive more messages. |
| */ |
| - (void)receiveNextMessages:(NSUInteger)numberOfMessages; |
| |
| @end |
| |
| /** |
| * An interceptor factory object is used to create interceptor object for the call at the call |
| * start time. |
| */ |
| @protocol GRPCInterceptorFactory |
| |
| /** |
| * Create an interceptor object. gRPC uses the returned object as the interceptor for the current |
| * call |
| */ |
| - (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager; |
| |
| @end |
| |
| /** |
| * GRPCInterceptorManager is a helper class to forward messages between the interceptors. The |
| * interceptor manager object retains reference to the next and previous interceptor object in the |
| * interceptor chain, and forward corresponding events to them. |
| * |
| * All methods except the initializer of the class can only be called on the manager's dispatch |
| * queue. Since the manager's dispatch queue targets corresponding interceptor's dispatch queue, it |
| * is also safe to call the manager's methods in the corresponding interceptor instance's methods |
| * that implement GRPCInterceptorInterface. |
| * |
| * When an interceptor is shutting down, it must invoke -shutDown method of its corresponding |
| * manager so that references to other interceptors can be released and proper clean-up is made. |
| */ |
| @interface GRPCInterceptorManager : NSObject<GRPCInterceptorInterface, GRPCResponseHandler> |
| |
| - (instancetype)init NS_UNAVAILABLE; |
| |
| + (instancetype) new NS_UNAVAILABLE; |
| |
| - (nullable instancetype)initWithFactories:(nullable NSArray<id<GRPCInterceptorFactory>> *)factories |
| previousInterceptor:(nullable id<GRPCResponseHandler>)previousInterceptor |
| transportID:(GRPCTransportID)transportID; |
| |
| /** |
| * Notify the manager that the interceptor has shut down and the manager should release references |
| * to other interceptors and stop forwarding requests/responses. |
| */ |
| - (void)shutDown; |
| |
| // Methods to forward GRPCInterceptorInterface calls to the next interceptor |
| |
| /** Notify the next interceptor in the chain to start the call and pass arguments */ |
| - (void)startNextInterceptorWithRequest:(GRPCRequestOptions *)requestOptions |
| callOptions:(GRPCCallOptions *)callOptions; |
| |
| /** Pass a message to be sent to the next interceptor in the chain */ |
| - (void)writeNextInterceptorWithData:(id)data; |
| |
| /** Notify the next interceptor in the chain to finish the call */ |
| - (void)finishNextInterceptor; |
| |
| /** Notify the next interceptor in the chain to cancel the call */ |
| - (void)cancelNextInterceptor; |
| |
| /** Notify the next interceptor in the chain to receive more messages */ |
| - (void)receiveNextInterceptorMessages:(NSUInteger)numberOfMessages; |
| |
| // Methods to forward GRPCResponseHandler callbacks to the previous object |
| |
| /** Forward initial metadata to the previous interceptor in the chain */ |
| - (void)forwardPreviousInterceptorWithInitialMetadata:(nullable NSDictionary *)initialMetadata; |
| |
| /** Forward a received message to the previous interceptor in the chain */ |
| - (void)forwardPreviousInterceptorWithData:(nullable id)data; |
| |
| /** Forward call close and trailing metadata to the previous interceptor in the chain */ |
| - (void)forwardPreviousInterceptorCloseWithTrailingMetadata: |
| (nullable NSDictionary *)trailingMetadata |
| error:(nullable NSError *)error; |
| |
| /** Forward write completion to the previous interceptor in the chain */ |
| - (void)forwardPreviousInterceptorDidWriteData; |
| |
| @end |
| |
| /** |
| * Base class for a gRPC interceptor. The implementation of the base class provides default behavior |
| * of an interceptor, which is simply forward a request/callback to the next/previous interceptor in |
| * the chain. The base class implementation uses the same dispatch queue for both requests and |
| * callbacks. |
| * |
| * An interceptor implementation should inherit from this base class and initialize the base class |
| * with [super initWithInterceptorManager:dispatchQueue:] for the default implementation to function |
| * properly. |
| */ |
| @interface GRPCInterceptor : NSObject<GRPCInterceptorInterface, GRPCResponseHandler> |
| |
| - (instancetype)init NS_UNAVAILABLE; |
| + (instancetype) new NS_UNAVAILABLE; |
| |
| /** |
| * Initialize the interceptor with the next interceptor in the chain, and provide the dispatch queue |
| * that this interceptor's methods are dispatched onto. |
| */ |
| - (nullable instancetype)initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager |
| dispatchQueue:(dispatch_queue_t)dispatchQueue; |
| |
| // Default implementation of GRPCInterceptorInterface |
| |
| - (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions |
| callOptions:(GRPCCallOptions *)callOptions; |
| - (void)writeData:(id)data; |
| - (void)finish; |
| - (void)cancel; |
| - (void)receiveNextMessages:(NSUInteger)numberOfMessages; |
| |
| // Default implementation of GRPCResponeHandler |
| |
| - (void)didReceiveInitialMetadata:(nullable NSDictionary *)initialMetadata; |
| - (void)didReceiveData:(id)data; |
| - (void)didCloseWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata |
| error:(nullable NSError *)error; |
| - (void)didWriteData; |
| |
| @end |
| |
| NS_ASSUME_NONNULL_END |