| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 | /* * * 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. * *//** * 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. * * *                                   ----------- *                                  | GRPCCall2 | *                                   ----------- *                                        | *                                        | *                           -------------------------- *                          | GRPCInterceptorManager 1 | *                           -------------------------- *                          | GRPCInterceptor 1        | *                           -------------------------- *                                        | *                                       ... *                                        | *                           -------------------------- *                          | GRPCInterceptorManager N | *                           -------------------------- *                          | GRPCInterceptor N        | *                           -------------------------- *                                        | *                                        | *                               ------------------ *                              | GRPCCallInternal | *                               ------------------ * * 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. * *                                      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 * * 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"NS_ASSUME_NONNULL_BEGIN@class GRPCInterceptorManager;@class GRPCInterceptor;/** * The GRPCInterceptorInterface defines the request events that can occur to an interceptr. */@protocol GRPCInterceptorInterface<NSObject>/** * The queue on which all methods of this interceptor should be dispatched on. The queue must be a * serial queue. */@property(readonly) dispatch_queue_t requestDispatchQueue;/** * 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 should be 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/** * The interceptor manager object retains reference to the next and previous interceptor object in * the interceptor chain, and forward corresponding events to them. When a call terminates, it must * invoke shutDown method of its corresponding manager so that references to other interceptors can * be released. */@interface GRPCInterceptorManager : NSObject- (instancetype)init NS_UNAVAILABLE;+ (instancetype) new NS_UNAVAILABLE;- (nullable instancetype)initWithNextInterceptor:(id<GRPCInterceptorInterface>)nextInterceptor    NS_DESIGNATED_INITIALIZER;/** Set the previous interceptor in the chain. Can only be set once. */- (void)setPreviousInterceptor:(id<GRPCResponseHandler>)previousInterceptor;/** Indicate shutdown of the interceptor; release the reference to other interceptors */- (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                               requestDispatchQueue:(dispatch_queue_t)requestDispatchQueue                              responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue    NS_DESIGNATED_INITIALIZER;// 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
 |