xref: /aosp_15_r20/external/grpc-grpc/src/objective-c/GRPCClient/private/GRPCTransport+Private.mm (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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 "GRPCTransport+Private.h"
20
21#import <GRPCClient/GRPCTransport.h>
22
23@implementation GRPCTransportManager {
24  GRPCTransportID _transportID;
25  GRPCTransport *_transport;
26  id<GRPCResponseHandler> _previousInterceptor;
27  dispatch_queue_t _dispatchQueue;
28}
29
30- (instancetype)initWithTransportID:(GRPCTransportID)transportID
31                previousInterceptor:(id<GRPCResponseHandler>)previousInterceptor {
32  if ((self = [super init])) {
33    id<GRPCTransportFactory> factory =
34        [[GRPCTransportRegistry sharedInstance] getTransportFactoryWithID:transportID];
35
36    _transport = [factory createTransportWithManager:self];
37    NSAssert(_transport != nil, @"Failed to create transport with id: %s", transportID);
38    if (_transport == nil) {
39      NSLog(@"Failed to create transport with id: %s", transportID);
40      return nil;
41    }
42    _previousInterceptor = previousInterceptor;
43    _dispatchQueue = _transport.dispatchQueue;
44    _transportID = transportID;
45  }
46  return self;
47}
48
49- (void)shutDown {
50  // immediately releases reference; should not queue to dispatch queue.
51  _transport = nil;
52  _previousInterceptor = nil;
53}
54
55- (dispatch_queue_t)dispatchQueue {
56  return _dispatchQueue;
57}
58
59- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
60                    callOptions:(GRPCCallOptions *)callOptions {
61  if (_transportID != callOptions.transport) {
62    [NSException raise:NSInvalidArgumentException
63                format:@"Interceptors cannot change the call option 'transport'"];
64    return;
65  }
66  // retain the transport instance until the method exit to prevent deallocation of the transport
67  // instance within the method
68  GRPCTransport *transport = _transport;
69  [transport startWithRequestOptions:requestOptions callOptions:callOptions];
70}
71
72- (void)writeData:(id)data {
73  // retain the transport instance until the method exit to prevent deallocation of the transport
74  // instance within the method
75  GRPCTransport *transport = _transport;
76  [transport writeData:data];
77}
78
79- (void)finish {
80  // retain the transport instance until the method exit to prevent deallocation of the transport
81  // instance within the method
82  GRPCTransport *transport = _transport;
83  [transport finish];
84}
85
86- (void)cancel {
87  // retain the transport instance until the method exit to prevent deallocation of the transport
88  // instance within the method
89  GRPCTransport *transport = _transport;
90  [transport cancel];
91}
92
93- (void)receiveNextMessages:(NSUInteger)numberOfMessages {
94  // retain the transport instance until the method exit to prevent deallocation of the transport
95  // instance within the method
96  GRPCTransport *transport = _transport;
97  [transport receiveNextMessages:numberOfMessages];
98}
99
100/** Forward initial metadata to the previous interceptor in the chain */
101- (void)forwardPreviousInterceptorWithInitialMetadata:(NSDictionary *)initialMetadata {
102  if (initialMetadata == nil || _previousInterceptor == nil) {
103    return;
104  }
105  id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
106  dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
107    [copiedPreviousInterceptor didReceiveInitialMetadata:initialMetadata];
108  });
109}
110
111/** Forward a received message to the previous interceptor in the chain */
112- (void)forwardPreviousInterceptorWithData:(id)data {
113  if (data == nil || _previousInterceptor == nil) {
114    return;
115  }
116  id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
117  dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
118    [copiedPreviousInterceptor didReceiveData:data];
119  });
120}
121
122/** Forward call close and trailing metadata to the previous interceptor in the chain */
123- (void)forwardPreviousInterceptorCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata
124                                                      error:(NSError *)error {
125  if (_previousInterceptor == nil) {
126    return;
127  }
128  id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
129  // no more callbacks should be issued to the previous interceptor
130  _previousInterceptor = nil;
131  dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
132    [copiedPreviousInterceptor didCloseWithTrailingMetadata:trailingMetadata error:error];
133  });
134}
135
136/** Forward write completion to the previous interceptor in the chain */
137- (void)forwardPreviousInterceptorDidWriteData {
138  if (_previousInterceptor == nil) {
139    return;
140  }
141  id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor;
142  dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{
143    [copiedPreviousInterceptor didWriteData];
144  });
145}
146
147@end
148