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