| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 | /* * * 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;@endNS_ASSUME_NONNULL_END
 |