blob: 9a41c395148760d02586938fdb8af9c0fb26d1c0 [file] [log] [blame]
/*
*
* 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.
*
*/
#import <Foundation/Foundation.h>
#import "GRPCInterceptor.h"
#import "private/GRPCTransport+Private.h"
@interface GRPCInterceptorManager ()<GRPCInterceptorInterface, GRPCResponseHandler>
@end
@implementation GRPCInterceptorManager {
id<GRPCInterceptorInterface> _nextInterceptor;
id<GRPCResponseHandler> _previousInterceptor;
GRPCInterceptor *_thisInterceptor;
dispatch_queue_t _dispatchQueue;
NSArray<id<GRPCInterceptorFactory>> *_factories;
GRPCTransportId _transportId;
BOOL _shutDown;
}
- (instancetype)initWithFactories:(NSArray<id<GRPCInterceptorFactory>> *)factories
previousInterceptor:(id<GRPCResponseHandler>)previousInterceptor
transportId:(nonnull GRPCTransportId)transportId {
if ((self = [super init])) {
if (factories.count == 0) {
[NSException raise:NSInternalInconsistencyException
format:@"Interceptor manager must have factories"];
}
_thisInterceptor = [factories[0] createInterceptorWithManager:self];
if (_thisInterceptor == nil) {
return nil;
}
_previousInterceptor = previousInterceptor;
_factories = factories;
// Generate interceptor
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
if (@available(iOS 8.0, macOS 10.10, *)) {
_dispatchQueue = dispatch_queue_create(
NULL,
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0));
} else {
#else
{
#endif
_dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
}
dispatch_set_target_queue(_dispatchQueue, _thisInterceptor.dispatchQueue);
_transportId = transportId;
}
return self;
}
- (void)shutDown {
_nextInterceptor = nil;
_previousInterceptor = nil;
_thisInterceptor = nil;
_shutDown = YES;
}
- (void)createNextInterceptor {
NSAssert(_nextInterceptor == nil, @"Starting the next interceptor more than once");
NSAssert(_factories.count > 0, @"Interceptor manager of transport cannot start next interceptor");
if (_nextInterceptor != nil) {
NSLog(@"Starting the next interceptor more than once");
return;
}
NSMutableArray<id<GRPCInterceptorFactory>> *interceptorFactories = [NSMutableArray
arrayWithArray:[_factories subarrayWithRange:NSMakeRange(1, _factories.count - 1)]];
while (_nextInterceptor == nil) {
if (interceptorFactories.count == 0) {
_nextInterceptor =
[[GRPCTransportManager alloc] initWithTransportId:_transportId previousInterceptor:self];
break;
} else {
_nextInterceptor = [[GRPCInterceptorManager alloc] initWithFactories:interceptorFactories
previousInterceptor:self
transportId:_transportId];
if (_nextInterceptor == nil) {
[interceptorFactories removeObjectAtIndex:0];
}
}
}
NSAssert(_nextInterceptor != nil, @"Failed to create interceptor or transport.");
if (_nextInterceptor == nil) {
NSLog(@"Failed to create interceptor or transport.");
}
}
- (void)startNextInterceptorWithRequest:(GRPCRequestOptions *)requestOptions
callOptions:(GRPCCallOptions *)callOptions {
if (_nextInterceptor == nil && !_shutDown) {
[self createNextInterceptor];
}
if (_nextInterceptor == nil) {
return;
}
id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
dispatch_async(copiedNextInterceptor.dispatchQueue, ^{
[copiedNextInterceptor startWithRequestOptions:requestOptions callOptions:callOptions];
});
}
- (void)writeNextInterceptorWithData:(id)data {
if (_nextInterceptor == nil && !_shutDown) {
[self createNextInterceptor];
}
if (_nextInterceptor == nil) {
return;
}
id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
dispatch_async(copiedNextInterceptor.dispatchQueue, ^{
[copiedNextInterceptor writeData:data];
});
}
- (void)finishNextInterceptor {
if (_nextInterceptor == nil && !_shutDown) {
[self createNextInterceptor];
}
if (_nextInterceptor == nil) {
return;
}
id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
dispatch_async(copiedNextInterceptor.dispatchQueue, ^{
[copiedNextInterceptor finish];
});
}
- (void)cancelNextInterceptor {
if (_nextInterceptor == nil && !_shutDown) {
[self createNextInterceptor];
}
if (_nextInterceptor == nil) {
return;
}
id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
dispatch_async(copiedNextInterceptor.dispatchQueue, ^{
[copiedNextInterceptor cancel];
});
}
/** Notify the next interceptor in the chain to receive more messages */
- (void)receiveNextInterceptorMessages:(NSUInteger)numberOfMessages {
if (_nextInterceptor == nil && !_shutDown) {
[self createNextInterceptor];
}
if (_nextInterceptor == nil) {
return;
}
id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor;
dispatch_async(copiedNextInterceptor.dispatchQueue, ^{
[copiedNextInterceptor receiveNextMessages:numberOfMessages];
});
}
// Methods to forward GRPCResponseHandler callbacks to the previous object
/** Forward initial metadata to the previous interceptor in the chain */
- (void)forwardPreviousInterceptorWithInitialMetadata:(NSDictionary *)initialMetadata {
if (_previousInterceptor == nil) {
return;
}
id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
[copiedPreviousInterceptor didReceiveInitialMetadata:initialMetadata];
});
}
/** Forward a received message to the previous interceptor in the chain */
- (void)forwardPreviousInterceptorWithData:(id)data {
if (_previousInterceptor == nil) {
return;
}
id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
[copiedPreviousInterceptor didReceiveData:data];
});
}
/** Forward call close and trailing metadata to the previous interceptor in the chain */
- (void)forwardPreviousInterceptorCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata
error:(NSError *)error {
if (_previousInterceptor == nil) {
return;
}
id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
[copiedPreviousInterceptor didCloseWithTrailingMetadata:trailingMetadata error:error];
});
}
/** Forward write completion to the previous interceptor in the chain */
- (void)forwardPreviousInterceptorDidWriteData {
if (_previousInterceptor == nil) {
return;
}
id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
[copiedPreviousInterceptor didWriteData];
});
}
- (dispatch_queue_t)dispatchQueue {
return _dispatchQueue;
}
- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
callOptions:(GRPCCallOptions *)callOptions {
[_thisInterceptor startWithRequestOptions:requestOptions callOptions:callOptions];
}
- (void)writeData:(id)data {
[_thisInterceptor writeData:data];
}
- (void)finish {
[_thisInterceptor finish];
}
- (void)cancel {
[_thisInterceptor cancel];
}
- (void)receiveNextMessages:(NSUInteger)numberOfMessages {
[_thisInterceptor receiveNextMessages:numberOfMessages];
}
- (void)didReceiveInitialMetadata:(nullable NSDictionary *)initialMetadata {
if ([_thisInterceptor respondsToSelector:@selector(didReceiveInitialMetadata:)]) {
[_thisInterceptor didReceiveInitialMetadata:initialMetadata];
}
}
- (void)didReceiveData:(id)data {
if ([_thisInterceptor respondsToSelector:@selector(didReceiveData:)]) {
[_thisInterceptor didReceiveData:data];
}
}
- (void)didCloseWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata
error:(nullable NSError *)error {
if ([_thisInterceptor respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) {
[_thisInterceptor didCloseWithTrailingMetadata:trailingMetadata error:error];
}
}
- (void)didWriteData {
if ([_thisInterceptor respondsToSelector:@selector(didWriteData)]) {
[_thisInterceptor didWriteData];
}
}
@end
@implementation GRPCInterceptor {
GRPCInterceptorManager *_manager;
dispatch_queue_t _dispatchQueue;
}
- (instancetype)initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager
dispatchQueue:(dispatch_queue_t)dispatchQueue {
if ((self = [super init])) {
_manager = interceptorManager;
_dispatchQueue = dispatchQueue;
}
return self;
}
- (dispatch_queue_t)dispatchQueue {
return _dispatchQueue;
}
- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
callOptions:(GRPCCallOptions *)callOptions {
[_manager startNextInterceptorWithRequest:requestOptions callOptions:callOptions];
}
- (void)writeData:(id)data {
[_manager writeNextInterceptorWithData:data];
}
- (void)finish {
[_manager finishNextInterceptor];
}
- (void)cancel {
[_manager cancelNextInterceptor];
[_manager
forwardPreviousInterceptorCloseWithTrailingMetadata:nil
error:[NSError
errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeCancelled
userInfo:@{
NSLocalizedDescriptionKey :
@"Canceled"
}]];
[_manager shutDown];
}
- (void)receiveNextMessages:(NSUInteger)numberOfMessages {
[_manager receiveNextInterceptorMessages:numberOfMessages];
}
- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata {
[_manager forwardPreviousInterceptorWithInitialMetadata:initialMetadata];
}
- (void)didReceiveRawMessage:(id)message {
NSAssert(NO,
@"The method didReceiveRawMessage is deprecated and cannot be used with interceptor");
NSLog(@"The method didReceiveRawMessage is deprecated and cannot be used with interceptor");
abort();
}
- (void)didReceiveData:(id)data {
[_manager forwardPreviousInterceptorWithData:data];
}
- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
[_manager forwardPreviousInterceptorCloseWithTrailingMetadata:trailingMetadata error:error];
[_manager shutDown];
}
- (void)didWriteData {
[_manager forwardPreviousInterceptorDidWriteData];
}
@end