1*cc02d7e2SAndroid Build Coastguard Worker/* 2*cc02d7e2SAndroid Build Coastguard Worker * 3*cc02d7e2SAndroid Build Coastguard Worker * Copyright 2019 gRPC authors. 4*cc02d7e2SAndroid Build Coastguard Worker * 5*cc02d7e2SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 6*cc02d7e2SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 7*cc02d7e2SAndroid Build Coastguard Worker * You may obtain a copy of the License at 8*cc02d7e2SAndroid Build Coastguard Worker * 9*cc02d7e2SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 10*cc02d7e2SAndroid Build Coastguard Worker * 11*cc02d7e2SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 12*cc02d7e2SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 13*cc02d7e2SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*cc02d7e2SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 15*cc02d7e2SAndroid Build Coastguard Worker * limitations under the License. 16*cc02d7e2SAndroid Build Coastguard Worker * 17*cc02d7e2SAndroid Build Coastguard Worker */ 18*cc02d7e2SAndroid Build Coastguard Worker 19*cc02d7e2SAndroid Build Coastguard Worker#import <Foundation/Foundation.h> 20*cc02d7e2SAndroid Build Coastguard Worker 21*cc02d7e2SAndroid Build Coastguard Worker#import "GRPCInterceptor.h" 22*cc02d7e2SAndroid Build Coastguard Worker#import "private/GRPCTransport+Private.h" 23*cc02d7e2SAndroid Build Coastguard Worker 24*cc02d7e2SAndroid Build Coastguard Worker@interface GRPCInterceptorManager () <GRPCInterceptorInterface, GRPCResponseHandler> 25*cc02d7e2SAndroid Build Coastguard Worker 26*cc02d7e2SAndroid Build Coastguard Worker@end 27*cc02d7e2SAndroid Build Coastguard Worker 28*cc02d7e2SAndroid Build Coastguard Worker@implementation GRPCInterceptorManager { 29*cc02d7e2SAndroid Build Coastguard Worker id<GRPCInterceptorInterface> _nextInterceptor; 30*cc02d7e2SAndroid Build Coastguard Worker id<GRPCResponseHandler> _previousInterceptor; 31*cc02d7e2SAndroid Build Coastguard Worker GRPCInterceptor *_thisInterceptor; 32*cc02d7e2SAndroid Build Coastguard Worker dispatch_queue_t _dispatchQueue; 33*cc02d7e2SAndroid Build Coastguard Worker NSArray<id<GRPCInterceptorFactory>> *_factories; 34*cc02d7e2SAndroid Build Coastguard Worker GRPCTransportID _transportID; 35*cc02d7e2SAndroid Build Coastguard Worker BOOL _shutDown; 36*cc02d7e2SAndroid Build Coastguard Worker} 37*cc02d7e2SAndroid Build Coastguard Worker 38*cc02d7e2SAndroid Build Coastguard Worker- (instancetype)initWithFactories:(NSArray<id<GRPCInterceptorFactory>> *)factories 39*cc02d7e2SAndroid Build Coastguard Worker previousInterceptor:(id<GRPCResponseHandler>)previousInterceptor 40*cc02d7e2SAndroid Build Coastguard Worker transportID:(nonnull GRPCTransportID)transportID { 41*cc02d7e2SAndroid Build Coastguard Worker if ((self = [super init])) { 42*cc02d7e2SAndroid Build Coastguard Worker if (factories.count == 0) { 43*cc02d7e2SAndroid Build Coastguard Worker [NSException raise:NSInternalInconsistencyException 44*cc02d7e2SAndroid Build Coastguard Worker format:@"Interceptor manager must have factories"]; 45*cc02d7e2SAndroid Build Coastguard Worker } 46*cc02d7e2SAndroid Build Coastguard Worker _thisInterceptor = [factories[0] createInterceptorWithManager:self]; 47*cc02d7e2SAndroid Build Coastguard Worker if (_thisInterceptor == nil) { 48*cc02d7e2SAndroid Build Coastguard Worker return nil; 49*cc02d7e2SAndroid Build Coastguard Worker } 50*cc02d7e2SAndroid Build Coastguard Worker _previousInterceptor = previousInterceptor; 51*cc02d7e2SAndroid Build Coastguard Worker _factories = factories; 52*cc02d7e2SAndroid Build Coastguard Worker // Generate interceptor 53*cc02d7e2SAndroid Build Coastguard Worker#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 54*cc02d7e2SAndroid Build Coastguard Worker if (@available(iOS 8.0, macOS 10.10, *)) { 55*cc02d7e2SAndroid Build Coastguard Worker _dispatchQueue = dispatch_queue_create( 56*cc02d7e2SAndroid Build Coastguard Worker NULL, 57*cc02d7e2SAndroid Build Coastguard Worker dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); 58*cc02d7e2SAndroid Build Coastguard Worker } else { 59*cc02d7e2SAndroid Build Coastguard Worker#else 60*cc02d7e2SAndroid Build Coastguard Worker { 61*cc02d7e2SAndroid Build Coastguard Worker#endif 62*cc02d7e2SAndroid Build Coastguard Worker _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); 63*cc02d7e2SAndroid Build Coastguard Worker } 64*cc02d7e2SAndroid Build Coastguard Worker dispatch_set_target_queue(_dispatchQueue, _thisInterceptor.dispatchQueue); 65*cc02d7e2SAndroid Build Coastguard Worker _transportID = transportID; 66*cc02d7e2SAndroid Build Coastguard Worker } 67*cc02d7e2SAndroid Build Coastguard Worker return self; 68*cc02d7e2SAndroid Build Coastguard Worker} 69*cc02d7e2SAndroid Build Coastguard Worker 70*cc02d7e2SAndroid Build Coastguard Worker- (void)shutDown { 71*cc02d7e2SAndroid Build Coastguard Worker // immediately releases reference; should not queue to dispatch queue. 72*cc02d7e2SAndroid Build Coastguard Worker _nextInterceptor = nil; 73*cc02d7e2SAndroid Build Coastguard Worker _previousInterceptor = nil; 74*cc02d7e2SAndroid Build Coastguard Worker _thisInterceptor = nil; 75*cc02d7e2SAndroid Build Coastguard Worker _shutDown = YES; 76*cc02d7e2SAndroid Build Coastguard Worker} 77*cc02d7e2SAndroid Build Coastguard Worker 78*cc02d7e2SAndroid Build Coastguard Worker- (void)createNextInterceptor { 79*cc02d7e2SAndroid Build Coastguard Worker NSAssert(_nextInterceptor == nil, @"Starting the next interceptor more than once"); 80*cc02d7e2SAndroid Build Coastguard Worker NSAssert(_factories.count > 0, @"Interceptor manager of transport cannot start next interceptor"); 81*cc02d7e2SAndroid Build Coastguard Worker if (_nextInterceptor != nil) { 82*cc02d7e2SAndroid Build Coastguard Worker NSLog(@"Starting the next interceptor more than once"); 83*cc02d7e2SAndroid Build Coastguard Worker return; 84*cc02d7e2SAndroid Build Coastguard Worker } 85*cc02d7e2SAndroid Build Coastguard Worker NSMutableArray<id<GRPCInterceptorFactory>> *interceptorFactories = [NSMutableArray 86*cc02d7e2SAndroid Build Coastguard Worker arrayWithArray:[_factories subarrayWithRange:NSMakeRange(1, _factories.count - 1)]]; 87*cc02d7e2SAndroid Build Coastguard Worker while (_nextInterceptor == nil) { 88*cc02d7e2SAndroid Build Coastguard Worker if (interceptorFactories.count == 0) { 89*cc02d7e2SAndroid Build Coastguard Worker _nextInterceptor = [[GRPCTransportManager alloc] initWithTransportID:_transportID 90*cc02d7e2SAndroid Build Coastguard Worker previousInterceptor:self]; 91*cc02d7e2SAndroid Build Coastguard Worker break; 92*cc02d7e2SAndroid Build Coastguard Worker } else { 93*cc02d7e2SAndroid Build Coastguard Worker _nextInterceptor = [[GRPCInterceptorManager alloc] initWithFactories:interceptorFactories 94*cc02d7e2SAndroid Build Coastguard Worker previousInterceptor:self 95*cc02d7e2SAndroid Build Coastguard Worker transportID:_transportID]; 96*cc02d7e2SAndroid Build Coastguard Worker if (_nextInterceptor == nil) { 97*cc02d7e2SAndroid Build Coastguard Worker [interceptorFactories removeObjectAtIndex:0]; 98*cc02d7e2SAndroid Build Coastguard Worker } 99*cc02d7e2SAndroid Build Coastguard Worker } 100*cc02d7e2SAndroid Build Coastguard Worker } 101*cc02d7e2SAndroid Build Coastguard Worker NSAssert(_nextInterceptor != nil, @"Failed to create interceptor or transport."); 102*cc02d7e2SAndroid Build Coastguard Worker if (_nextInterceptor == nil) { 103*cc02d7e2SAndroid Build Coastguard Worker NSLog(@"Failed to create interceptor or transport."); 104*cc02d7e2SAndroid Build Coastguard Worker } 105*cc02d7e2SAndroid Build Coastguard Worker} 106*cc02d7e2SAndroid Build Coastguard Worker 107*cc02d7e2SAndroid Build Coastguard Worker- (void)startNextInterceptorWithRequest:(GRPCRequestOptions *)requestOptions 108*cc02d7e2SAndroid Build Coastguard Worker callOptions:(GRPCCallOptions *)callOptions { 109*cc02d7e2SAndroid Build Coastguard Worker if (_nextInterceptor == nil && !_shutDown) { 110*cc02d7e2SAndroid Build Coastguard Worker [self createNextInterceptor]; 111*cc02d7e2SAndroid Build Coastguard Worker } 112*cc02d7e2SAndroid Build Coastguard Worker if (_nextInterceptor == nil) { 113*cc02d7e2SAndroid Build Coastguard Worker return; 114*cc02d7e2SAndroid Build Coastguard Worker } 115*cc02d7e2SAndroid Build Coastguard Worker id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor; 116*cc02d7e2SAndroid Build Coastguard Worker dispatch_async(copiedNextInterceptor.dispatchQueue, ^{ 117*cc02d7e2SAndroid Build Coastguard Worker [copiedNextInterceptor startWithRequestOptions:requestOptions callOptions:callOptions]; 118*cc02d7e2SAndroid Build Coastguard Worker }); 119*cc02d7e2SAndroid Build Coastguard Worker} 120*cc02d7e2SAndroid Build Coastguard Worker 121*cc02d7e2SAndroid Build Coastguard Worker- (void)writeNextInterceptorWithData:(id)data { 122*cc02d7e2SAndroid Build Coastguard Worker if (_nextInterceptor == nil && !_shutDown) { 123*cc02d7e2SAndroid Build Coastguard Worker [self createNextInterceptor]; 124*cc02d7e2SAndroid Build Coastguard Worker } 125*cc02d7e2SAndroid Build Coastguard Worker if (_nextInterceptor == nil) { 126*cc02d7e2SAndroid Build Coastguard Worker return; 127*cc02d7e2SAndroid Build Coastguard Worker } 128*cc02d7e2SAndroid Build Coastguard Worker id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor; 129*cc02d7e2SAndroid Build Coastguard Worker dispatch_async(copiedNextInterceptor.dispatchQueue, ^{ 130*cc02d7e2SAndroid Build Coastguard Worker [copiedNextInterceptor writeData:data]; 131*cc02d7e2SAndroid Build Coastguard Worker }); 132*cc02d7e2SAndroid Build Coastguard Worker} 133*cc02d7e2SAndroid Build Coastguard Worker 134*cc02d7e2SAndroid Build Coastguard Worker- (void)finishNextInterceptor { 135*cc02d7e2SAndroid Build Coastguard Worker if (_nextInterceptor == nil && !_shutDown) { 136*cc02d7e2SAndroid Build Coastguard Worker [self createNextInterceptor]; 137*cc02d7e2SAndroid Build Coastguard Worker } 138*cc02d7e2SAndroid Build Coastguard Worker if (_nextInterceptor == nil) { 139*cc02d7e2SAndroid Build Coastguard Worker return; 140*cc02d7e2SAndroid Build Coastguard Worker } 141*cc02d7e2SAndroid Build Coastguard Worker id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor; 142*cc02d7e2SAndroid Build Coastguard Worker dispatch_async(copiedNextInterceptor.dispatchQueue, ^{ 143*cc02d7e2SAndroid Build Coastguard Worker [copiedNextInterceptor finish]; 144*cc02d7e2SAndroid Build Coastguard Worker }); 145*cc02d7e2SAndroid Build Coastguard Worker} 146*cc02d7e2SAndroid Build Coastguard Worker 147*cc02d7e2SAndroid Build Coastguard Worker- (void)cancelNextInterceptor { 148*cc02d7e2SAndroid Build Coastguard Worker if (_nextInterceptor == nil && !_shutDown) { 149*cc02d7e2SAndroid Build Coastguard Worker [self createNextInterceptor]; 150*cc02d7e2SAndroid Build Coastguard Worker } 151*cc02d7e2SAndroid Build Coastguard Worker if (_nextInterceptor == nil) { 152*cc02d7e2SAndroid Build Coastguard Worker return; 153*cc02d7e2SAndroid Build Coastguard Worker } 154*cc02d7e2SAndroid Build Coastguard Worker id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor; 155*cc02d7e2SAndroid Build Coastguard Worker dispatch_async(copiedNextInterceptor.dispatchQueue, ^{ 156*cc02d7e2SAndroid Build Coastguard Worker [copiedNextInterceptor cancel]; 157*cc02d7e2SAndroid Build Coastguard Worker }); 158*cc02d7e2SAndroid Build Coastguard Worker} 159*cc02d7e2SAndroid Build Coastguard Worker 160*cc02d7e2SAndroid Build Coastguard Worker/** Notify the next interceptor in the chain to receive more messages */ 161*cc02d7e2SAndroid Build Coastguard Worker- (void)receiveNextInterceptorMessages:(NSUInteger)numberOfMessages { 162*cc02d7e2SAndroid Build Coastguard Worker if (_nextInterceptor == nil && !_shutDown) { 163*cc02d7e2SAndroid Build Coastguard Worker [self createNextInterceptor]; 164*cc02d7e2SAndroid Build Coastguard Worker } 165*cc02d7e2SAndroid Build Coastguard Worker if (_nextInterceptor == nil) { 166*cc02d7e2SAndroid Build Coastguard Worker return; 167*cc02d7e2SAndroid Build Coastguard Worker } 168*cc02d7e2SAndroid Build Coastguard Worker id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor; 169*cc02d7e2SAndroid Build Coastguard Worker dispatch_async(copiedNextInterceptor.dispatchQueue, ^{ 170*cc02d7e2SAndroid Build Coastguard Worker [copiedNextInterceptor receiveNextMessages:numberOfMessages]; 171*cc02d7e2SAndroid Build Coastguard Worker }); 172*cc02d7e2SAndroid Build Coastguard Worker} 173*cc02d7e2SAndroid Build Coastguard Worker 174*cc02d7e2SAndroid Build Coastguard Worker// Methods to forward GRPCResponseHandler callbacks to the previous object 175*cc02d7e2SAndroid Build Coastguard Worker 176*cc02d7e2SAndroid Build Coastguard Worker/** Forward initial metadata to the previous interceptor in the chain */ 177*cc02d7e2SAndroid Build Coastguard Worker- (void)forwardPreviousInterceptorWithInitialMetadata:(NSDictionary *)initialMetadata { 178*cc02d7e2SAndroid Build Coastguard Worker if (_previousInterceptor == nil) { 179*cc02d7e2SAndroid Build Coastguard Worker return; 180*cc02d7e2SAndroid Build Coastguard Worker } 181*cc02d7e2SAndroid Build Coastguard Worker id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor; 182*cc02d7e2SAndroid Build Coastguard Worker dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{ 183*cc02d7e2SAndroid Build Coastguard Worker [copiedPreviousInterceptor didReceiveInitialMetadata:initialMetadata]; 184*cc02d7e2SAndroid Build Coastguard Worker }); 185*cc02d7e2SAndroid Build Coastguard Worker} 186*cc02d7e2SAndroid Build Coastguard Worker 187*cc02d7e2SAndroid Build Coastguard Worker/** Forward a received message to the previous interceptor in the chain */ 188*cc02d7e2SAndroid Build Coastguard Worker- (void)forwardPreviousInterceptorWithData:(id)data { 189*cc02d7e2SAndroid Build Coastguard Worker if (_previousInterceptor == nil) { 190*cc02d7e2SAndroid Build Coastguard Worker return; 191*cc02d7e2SAndroid Build Coastguard Worker } 192*cc02d7e2SAndroid Build Coastguard Worker id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor; 193*cc02d7e2SAndroid Build Coastguard Worker dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{ 194*cc02d7e2SAndroid Build Coastguard Worker [copiedPreviousInterceptor didReceiveData:data]; 195*cc02d7e2SAndroid Build Coastguard Worker }); 196*cc02d7e2SAndroid Build Coastguard Worker} 197*cc02d7e2SAndroid Build Coastguard Worker 198*cc02d7e2SAndroid Build Coastguard Worker/** Forward call close and trailing metadata to the previous interceptor in the chain */ 199*cc02d7e2SAndroid Build Coastguard Worker- (void)forwardPreviousInterceptorCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata 200*cc02d7e2SAndroid Build Coastguard Worker error:(NSError *)error { 201*cc02d7e2SAndroid Build Coastguard Worker if (_previousInterceptor == nil) { 202*cc02d7e2SAndroid Build Coastguard Worker return; 203*cc02d7e2SAndroid Build Coastguard Worker } 204*cc02d7e2SAndroid Build Coastguard Worker id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor; 205*cc02d7e2SAndroid Build Coastguard Worker // no more callbacks should be issued to the previous interceptor 206*cc02d7e2SAndroid Build Coastguard Worker _previousInterceptor = nil; 207*cc02d7e2SAndroid Build Coastguard Worker dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{ 208*cc02d7e2SAndroid Build Coastguard Worker [copiedPreviousInterceptor didCloseWithTrailingMetadata:trailingMetadata error:error]; 209*cc02d7e2SAndroid Build Coastguard Worker }); 210*cc02d7e2SAndroid Build Coastguard Worker} 211*cc02d7e2SAndroid Build Coastguard Worker 212*cc02d7e2SAndroid Build Coastguard Worker/** Forward write completion to the previous interceptor in the chain */ 213*cc02d7e2SAndroid Build Coastguard Worker- (void)forwardPreviousInterceptorDidWriteData { 214*cc02d7e2SAndroid Build Coastguard Worker if (_previousInterceptor == nil) { 215*cc02d7e2SAndroid Build Coastguard Worker return; 216*cc02d7e2SAndroid Build Coastguard Worker } 217*cc02d7e2SAndroid Build Coastguard Worker id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor; 218*cc02d7e2SAndroid Build Coastguard Worker dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{ 219*cc02d7e2SAndroid Build Coastguard Worker [copiedPreviousInterceptor didWriteData]; 220*cc02d7e2SAndroid Build Coastguard Worker }); 221*cc02d7e2SAndroid Build Coastguard Worker} 222*cc02d7e2SAndroid Build Coastguard Worker 223*cc02d7e2SAndroid Build Coastguard Worker- (dispatch_queue_t)dispatchQueue { 224*cc02d7e2SAndroid Build Coastguard Worker return _dispatchQueue; 225*cc02d7e2SAndroid Build Coastguard Worker} 226*cc02d7e2SAndroid Build Coastguard Worker 227*cc02d7e2SAndroid Build Coastguard Worker- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions 228*cc02d7e2SAndroid Build Coastguard Worker callOptions:(GRPCCallOptions *)callOptions { 229*cc02d7e2SAndroid Build Coastguard Worker // retain this interceptor until the method exit to prevent deallocation of the interceptor within 230*cc02d7e2SAndroid Build Coastguard Worker // the interceptor's method 231*cc02d7e2SAndroid Build Coastguard Worker GRPCInterceptor *thisInterceptor = _thisInterceptor; 232*cc02d7e2SAndroid Build Coastguard Worker [thisInterceptor startWithRequestOptions:requestOptions callOptions:callOptions]; 233*cc02d7e2SAndroid Build Coastguard Worker} 234*cc02d7e2SAndroid Build Coastguard Worker 235*cc02d7e2SAndroid Build Coastguard Worker- (void)writeData:(id)data { 236*cc02d7e2SAndroid Build Coastguard Worker // retain this interceptor until the method exit to prevent deallocation of the interceptor within 237*cc02d7e2SAndroid Build Coastguard Worker // the interceptor's method 238*cc02d7e2SAndroid Build Coastguard Worker GRPCInterceptor *thisInterceptor = _thisInterceptor; 239*cc02d7e2SAndroid Build Coastguard Worker [thisInterceptor writeData:data]; 240*cc02d7e2SAndroid Build Coastguard Worker} 241*cc02d7e2SAndroid Build Coastguard Worker 242*cc02d7e2SAndroid Build Coastguard Worker- (void)finish { 243*cc02d7e2SAndroid Build Coastguard Worker // retain this interceptor until the method exit to prevent deallocation of the interceptor within 244*cc02d7e2SAndroid Build Coastguard Worker // the interceptor's method 245*cc02d7e2SAndroid Build Coastguard Worker GRPCInterceptor *thisInterceptor = _thisInterceptor; 246*cc02d7e2SAndroid Build Coastguard Worker [thisInterceptor finish]; 247*cc02d7e2SAndroid Build Coastguard Worker} 248*cc02d7e2SAndroid Build Coastguard Worker 249*cc02d7e2SAndroid Build Coastguard Worker- (void)cancel { 250*cc02d7e2SAndroid Build Coastguard Worker // retain this interceptor until the method exit to prevent deallocation of the interceptor within 251*cc02d7e2SAndroid Build Coastguard Worker // the interceptor's method 252*cc02d7e2SAndroid Build Coastguard Worker GRPCInterceptor *thisInterceptor = _thisInterceptor; 253*cc02d7e2SAndroid Build Coastguard Worker [thisInterceptor cancel]; 254*cc02d7e2SAndroid Build Coastguard Worker} 255*cc02d7e2SAndroid Build Coastguard Worker 256*cc02d7e2SAndroid Build Coastguard Worker- (void)receiveNextMessages:(NSUInteger)numberOfMessages { 257*cc02d7e2SAndroid Build Coastguard Worker // retain this interceptor until the method exit to prevent deallocation of the interceptor within 258*cc02d7e2SAndroid Build Coastguard Worker // the interceptor's method 259*cc02d7e2SAndroid Build Coastguard Worker GRPCInterceptor *thisInterceptor = _thisInterceptor; 260*cc02d7e2SAndroid Build Coastguard Worker [thisInterceptor receiveNextMessages:numberOfMessages]; 261*cc02d7e2SAndroid Build Coastguard Worker} 262*cc02d7e2SAndroid Build Coastguard Worker 263*cc02d7e2SAndroid Build Coastguard Worker- (void)didReceiveInitialMetadata:(nullable NSDictionary *)initialMetadata { 264*cc02d7e2SAndroid Build Coastguard Worker if ([_thisInterceptor respondsToSelector:@selector(didReceiveInitialMetadata:)]) { 265*cc02d7e2SAndroid Build Coastguard Worker // retain this interceptor until the method exit to prevent deallocation of the interceptor 266*cc02d7e2SAndroid Build Coastguard Worker // within the interceptor's method 267*cc02d7e2SAndroid Build Coastguard Worker GRPCInterceptor *thisInterceptor = _thisInterceptor; 268*cc02d7e2SAndroid Build Coastguard Worker [thisInterceptor didReceiveInitialMetadata:initialMetadata]; 269*cc02d7e2SAndroid Build Coastguard Worker } 270*cc02d7e2SAndroid Build Coastguard Worker} 271*cc02d7e2SAndroid Build Coastguard Worker 272*cc02d7e2SAndroid Build Coastguard Worker- (void)didReceiveData:(id)data { 273*cc02d7e2SAndroid Build Coastguard Worker if ([_thisInterceptor respondsToSelector:@selector(didReceiveData:)]) { 274*cc02d7e2SAndroid Build Coastguard Worker // retain this interceptor until the method exit to prevent deallocation of the interceptor 275*cc02d7e2SAndroid Build Coastguard Worker // within the interceptor's method 276*cc02d7e2SAndroid Build Coastguard Worker GRPCInterceptor *thisInterceptor = _thisInterceptor; 277*cc02d7e2SAndroid Build Coastguard Worker [thisInterceptor didReceiveData:data]; 278*cc02d7e2SAndroid Build Coastguard Worker } 279*cc02d7e2SAndroid Build Coastguard Worker} 280*cc02d7e2SAndroid Build Coastguard Worker 281*cc02d7e2SAndroid Build Coastguard Worker- (void)didCloseWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata 282*cc02d7e2SAndroid Build Coastguard Worker error:(nullable NSError *)error { 283*cc02d7e2SAndroid Build Coastguard Worker if ([_thisInterceptor respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) { 284*cc02d7e2SAndroid Build Coastguard Worker // retain this interceptor until the method exit to prevent deallocation of the interceptor 285*cc02d7e2SAndroid Build Coastguard Worker // within the interceptor's method 286*cc02d7e2SAndroid Build Coastguard Worker GRPCInterceptor *thisInterceptor = _thisInterceptor; 287*cc02d7e2SAndroid Build Coastguard Worker [thisInterceptor didCloseWithTrailingMetadata:trailingMetadata error:error]; 288*cc02d7e2SAndroid Build Coastguard Worker } 289*cc02d7e2SAndroid Build Coastguard Worker} 290*cc02d7e2SAndroid Build Coastguard Worker 291*cc02d7e2SAndroid Build Coastguard Worker- (void)didWriteData { 292*cc02d7e2SAndroid Build Coastguard Worker if ([_thisInterceptor respondsToSelector:@selector(didWriteData)]) { 293*cc02d7e2SAndroid Build Coastguard Worker // retain this interceptor until the method exit to prevent deallocation of the interceptor 294*cc02d7e2SAndroid Build Coastguard Worker // within the interceptor's method 295*cc02d7e2SAndroid Build Coastguard Worker GRPCInterceptor *thisInterceptor = _thisInterceptor; 296*cc02d7e2SAndroid Build Coastguard Worker [thisInterceptor didWriteData]; 297*cc02d7e2SAndroid Build Coastguard Worker } 298*cc02d7e2SAndroid Build Coastguard Worker} 299*cc02d7e2SAndroid Build Coastguard Worker 300*cc02d7e2SAndroid Build Coastguard Worker@end 301*cc02d7e2SAndroid Build Coastguard Worker 302*cc02d7e2SAndroid Build Coastguard Worker@implementation GRPCInterceptor { 303*cc02d7e2SAndroid Build Coastguard Worker GRPCInterceptorManager *_manager; 304*cc02d7e2SAndroid Build Coastguard Worker dispatch_queue_t _dispatchQueue; 305*cc02d7e2SAndroid Build Coastguard Worker} 306*cc02d7e2SAndroid Build Coastguard Worker 307*cc02d7e2SAndroid Build Coastguard Worker- (instancetype)initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager 308*cc02d7e2SAndroid Build Coastguard Worker dispatchQueue:(dispatch_queue_t)dispatchQueue { 309*cc02d7e2SAndroid Build Coastguard Worker if ((self = [super init])) { 310*cc02d7e2SAndroid Build Coastguard Worker _manager = interceptorManager; 311*cc02d7e2SAndroid Build Coastguard Worker _dispatchQueue = dispatchQueue; 312*cc02d7e2SAndroid Build Coastguard Worker } 313*cc02d7e2SAndroid Build Coastguard Worker 314*cc02d7e2SAndroid Build Coastguard Worker return self; 315*cc02d7e2SAndroid Build Coastguard Worker} 316*cc02d7e2SAndroid Build Coastguard Worker 317*cc02d7e2SAndroid Build Coastguard Worker- (dispatch_queue_t)dispatchQueue { 318*cc02d7e2SAndroid Build Coastguard Worker return _dispatchQueue; 319*cc02d7e2SAndroid Build Coastguard Worker} 320*cc02d7e2SAndroid Build Coastguard Worker 321*cc02d7e2SAndroid Build Coastguard Worker- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions 322*cc02d7e2SAndroid Build Coastguard Worker callOptions:(GRPCCallOptions *)callOptions { 323*cc02d7e2SAndroid Build Coastguard Worker [_manager startNextInterceptorWithRequest:requestOptions callOptions:callOptions]; 324*cc02d7e2SAndroid Build Coastguard Worker} 325*cc02d7e2SAndroid Build Coastguard Worker 326*cc02d7e2SAndroid Build Coastguard Worker- (void)writeData:(id)data { 327*cc02d7e2SAndroid Build Coastguard Worker [_manager writeNextInterceptorWithData:data]; 328*cc02d7e2SAndroid Build Coastguard Worker} 329*cc02d7e2SAndroid Build Coastguard Worker 330*cc02d7e2SAndroid Build Coastguard Worker- (void)finish { 331*cc02d7e2SAndroid Build Coastguard Worker [_manager finishNextInterceptor]; 332*cc02d7e2SAndroid Build Coastguard Worker} 333*cc02d7e2SAndroid Build Coastguard Worker 334*cc02d7e2SAndroid Build Coastguard Worker- (void)cancel { 335*cc02d7e2SAndroid Build Coastguard Worker [_manager cancelNextInterceptor]; 336*cc02d7e2SAndroid Build Coastguard Worker [_manager 337*cc02d7e2SAndroid Build Coastguard Worker forwardPreviousInterceptorCloseWithTrailingMetadata:nil 338*cc02d7e2SAndroid Build Coastguard Worker error:[NSError 339*cc02d7e2SAndroid Build Coastguard Worker errorWithDomain:kGRPCErrorDomain 340*cc02d7e2SAndroid Build Coastguard Worker code:GRPCErrorCodeCancelled 341*cc02d7e2SAndroid Build Coastguard Worker userInfo:@{ 342*cc02d7e2SAndroid Build Coastguard Worker NSLocalizedDescriptionKey : 343*cc02d7e2SAndroid Build Coastguard Worker @"Canceled" 344*cc02d7e2SAndroid Build Coastguard Worker }]]; 345*cc02d7e2SAndroid Build Coastguard Worker [_manager shutDown]; 346*cc02d7e2SAndroid Build Coastguard Worker} 347*cc02d7e2SAndroid Build Coastguard Worker 348*cc02d7e2SAndroid Build Coastguard Worker- (void)receiveNextMessages:(NSUInteger)numberOfMessages { 349*cc02d7e2SAndroid Build Coastguard Worker [_manager receiveNextInterceptorMessages:numberOfMessages]; 350*cc02d7e2SAndroid Build Coastguard Worker} 351*cc02d7e2SAndroid Build Coastguard Worker 352*cc02d7e2SAndroid Build Coastguard Worker- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata { 353*cc02d7e2SAndroid Build Coastguard Worker [_manager forwardPreviousInterceptorWithInitialMetadata:initialMetadata]; 354*cc02d7e2SAndroid Build Coastguard Worker} 355*cc02d7e2SAndroid Build Coastguard Worker 356*cc02d7e2SAndroid Build Coastguard Worker- (void)didReceiveRawMessage:(id)message { 357*cc02d7e2SAndroid Build Coastguard Worker NSAssert(NO, 358*cc02d7e2SAndroid Build Coastguard Worker @"The method didReceiveRawMessage is deprecated and cannot be used with interceptor"); 359*cc02d7e2SAndroid Build Coastguard Worker NSLog(@"The method didReceiveRawMessage is deprecated and cannot be used with interceptor"); 360*cc02d7e2SAndroid Build Coastguard Worker abort(); 361*cc02d7e2SAndroid Build Coastguard Worker} 362*cc02d7e2SAndroid Build Coastguard Worker 363*cc02d7e2SAndroid Build Coastguard Worker- (void)didReceiveData:(id)data { 364*cc02d7e2SAndroid Build Coastguard Worker [_manager forwardPreviousInterceptorWithData:data]; 365*cc02d7e2SAndroid Build Coastguard Worker} 366*cc02d7e2SAndroid Build Coastguard Worker 367*cc02d7e2SAndroid Build Coastguard Worker- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { 368*cc02d7e2SAndroid Build Coastguard Worker [_manager forwardPreviousInterceptorCloseWithTrailingMetadata:trailingMetadata error:error]; 369*cc02d7e2SAndroid Build Coastguard Worker [_manager shutDown]; 370*cc02d7e2SAndroid Build Coastguard Worker} 371*cc02d7e2SAndroid Build Coastguard Worker 372*cc02d7e2SAndroid Build Coastguard Worker- (void)didWriteData { 373*cc02d7e2SAndroid Build Coastguard Worker [_manager forwardPreviousInterceptorDidWriteData]; 374*cc02d7e2SAndroid Build Coastguard Worker} 375*cc02d7e2SAndroid Build Coastguard Worker 376*cc02d7e2SAndroid Build Coastguard Worker@end 377