| /* |
| * |
| * 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 |