Coverage Report

Created: 2026-02-11 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/grpc-swift/Sources/GRPC/GRPCChannel/GRPCChannel.swift
Line
Count
Source
1
/*
2
 * Copyright 2020, gRPC Authors All rights reserved.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
import NIOCore
17
import NIOHTTP2
18
import SwiftProtobuf
19
20
public protocol GRPCChannel: GRPCPreconcurrencySendable {
21
  /// Makes a gRPC call on the channel with requests and responses conforming to
22
  /// `SwiftProtobuf.Message`.
23
  ///
24
  /// Note: this is a lower-level construct that any of ``UnaryCall``, ``ClientStreamingCall``,
25
  /// ``ServerStreamingCall`` or ``BidirectionalStreamingCall`` and does not have an API to protect
26
  /// users against protocol violations (such as sending to requests on a unary call).
27
  ///
28
  /// After making the ``Call``, users must ``Call/invoke(onError:onResponsePart:)`` the call with a callback which is invoked
29
  /// for each response part (or error) received. Any call to ``Call/send(_:)`` prior to calling
30
  /// ``Call/invoke(onError:onResponsePart:)`` will fail and not be sent. Users are also responsible for closing the request stream
31
  /// by sending the `.end` request part.
32
  ///
33
  /// - Parameters:
34
  ///   - path: The path of the RPC, e.g. "/echo.Echo/get".
35
  ///   - type: The type of the RPC, e.g. ``GRPCCallType/unary``.
36
  ///   - callOptions: Options for the RPC.
37
  ///   - interceptors: A list of interceptors to intercept the request and response stream with.
38
  func makeCall<Request: SwiftProtobuf.Message, Response: SwiftProtobuf.Message>(
39
    path: String,
40
    type: GRPCCallType,
41
    callOptions: CallOptions,
42
    interceptors: [ClientInterceptor<Request, Response>]
43
  ) -> Call<Request, Response>
44
45
  /// Makes a gRPC call on the channel with requests and responses conforming to ``GRPCPayload``.
46
  ///
47
  /// Note: this is a lower-level construct that any of ``UnaryCall``, ``ClientStreamingCall``,
48
  /// ``ServerStreamingCall`` or ``BidirectionalStreamingCall`` and does not have an API to protect
49
  /// users against protocol violations (such as sending to requests on a unary call).
50
  ///
51
  /// After making the ``Call``, users must ``Call/invoke(onError:onResponsePart:)`` the call with a callback which is invoked
52
  /// for each response part (or error) received. Any call to ``Call/send(_:)`` prior to calling
53
  /// ``Call/invoke(onError:onResponsePart:)`` will fail and not be sent. Users are also responsible for closing the request stream
54
  /// by sending the `.end` request part.
55
  ///
56
  /// - Parameters:
57
  ///   - path: The path of the RPC, e.g. "/echo.Echo/get".
58
  ///   - type: The type of the RPC, e.g. ``GRPCCallType/unary``.
59
  ///   - callOptions: Options for the RPC.
60
  ///   - interceptors: A list of interceptors to intercept the request and response stream with.
61
  func makeCall<Request: GRPCPayload, Response: GRPCPayload>(
62
    path: String,
63
    type: GRPCCallType,
64
    callOptions: CallOptions,
65
    interceptors: [ClientInterceptor<Request, Response>]
66
  ) -> Call<Request, Response>
67
68
  /// Close the channel, and any connections associated with it. Any ongoing RPCs may fail.
69
  ///
70
  /// - Returns: Returns a future which will be resolved when shutdown has completed.
71
  func close() -> EventLoopFuture<Void>
72
73
  /// Close the channel, and any connections associated with it. Any ongoing RPCs may fail.
74
  ///
75
  /// - Parameter promise: A promise which will be completed when shutdown has completed.
76
  func close(promise: EventLoopPromise<Void>)
77
78
  /// Attempt to gracefully shutdown the channel. New RPCs will be failed immediately and existing
79
  /// RPCs may continue to run until they complete.
80
  ///
81
  /// - Parameters:
82
  ///   - deadline: A point in time by which the graceful shutdown must have completed. If the
83
  ///       deadline passes and RPCs are still active then the connection will be closed forcefully
84
  ///       and any remaining in-flight RPCs may be failed.
85
  ///   - promise: A promise which will be completed when shutdown has completed.
86
  func closeGracefully(deadline: NIODeadline, promise: EventLoopPromise<Void>)
87
}
88
89
// Default implementations to avoid breaking API. Implementations provided by GRPC override these.
90
extension GRPCChannel {
91
0
  public func close(promise: EventLoopPromise<Void>) {
92
0
    promise.completeWith(self.close())
93
0
  }
94
95
0
  public func closeGracefully(deadline: NIODeadline, promise: EventLoopPromise<Void>) {
96
0
    promise.completeWith(self.close())
97
0
  }
98
}
99
100
extension GRPCChannel {
101
  /// Make a unary gRPC call.
102
  ///
103
  /// - Parameters:
104
  ///   - path: Path of the RPC, e.g. "/echo.Echo/Get"
105
  ///   - request: The request to send.
106
  ///   - callOptions: Options for the RPC.
107
  ///   - interceptors: A list of interceptors to intercept the request and response stream with.
108
  public func makeUnaryCall<Request: Message, Response: Message>(
109
    path: String,
110
    request: Request,
111
    callOptions: CallOptions,
112
    interceptors: [ClientInterceptor<Request, Response>] = []
113
0
  ) -> UnaryCall<Request, Response> {
114
0
    let unary: UnaryCall<Request, Response> = UnaryCall(
115
0
      call: self.makeCall(
116
0
        path: path,
117
0
        type: .unary,
118
0
        callOptions: callOptions,
119
0
        interceptors: interceptors
120
0
      )
121
0
    )
122
0
    unary.invoke(request)
123
0
    return unary
124
0
  }
125
126
  /// Make a unary gRPC call.
127
  ///
128
  /// - Parameters:
129
  ///   - path: Path of the RPC, e.g. "/echo.Echo/Get"
130
  ///   - request: The request to send.
131
  ///   - callOptions: Options for the RPC.
132
  ///   - interceptors: A list of interceptors to intercept the request and response stream with.
133
  public func makeUnaryCall<Request: GRPCPayload, Response: GRPCPayload>(
134
    path: String,
135
    request: Request,
136
    callOptions: CallOptions,
137
    interceptors: [ClientInterceptor<Request, Response>] = []
138
0
  ) -> UnaryCall<Request, Response> {
139
0
    let rpc: UnaryCall<Request, Response> = UnaryCall(
140
0
      call: self.makeCall(
141
0
        path: path,
142
0
        type: .unary,
143
0
        callOptions: callOptions,
144
0
        interceptors: interceptors
145
0
      )
146
0
    )
147
0
    rpc.invoke(request)
148
0
    return rpc
149
0
  }
150
151
  /// Makes a client-streaming gRPC call.
152
  ///
153
  /// - Parameters:
154
  ///   - path: Path of the RPC, e.g. "/echo.Echo/Get"
155
  ///   - callOptions: Options for the RPC.
156
  ///   - interceptors: A list of interceptors to intercept the request and response stream with.
157
  public func makeClientStreamingCall<Request: Message, Response: Message>(
158
    path: String,
159
    callOptions: CallOptions,
160
    interceptors: [ClientInterceptor<Request, Response>] = []
161
0
  ) -> ClientStreamingCall<Request, Response> {
162
0
    let rpc: ClientStreamingCall<Request, Response> = ClientStreamingCall(
163
0
      call: self.makeCall(
164
0
        path: path,
165
0
        type: .clientStreaming,
166
0
        callOptions: callOptions,
167
0
        interceptors: interceptors
168
0
      )
169
0
    )
170
0
    rpc.invoke()
171
0
    return rpc
172
0
  }
173
174
  /// Makes a client-streaming gRPC call.
175
  ///
176
  /// - Parameters:
177
  ///   - path: Path of the RPC, e.g. "/echo.Echo/Get"
178
  ///   - callOptions: Options for the RPC.
179
  ///   - interceptors: A list of interceptors to intercept the request and response stream with.
180
  public func makeClientStreamingCall<Request: GRPCPayload, Response: GRPCPayload>(
181
    path: String,
182
    callOptions: CallOptions,
183
    interceptors: [ClientInterceptor<Request, Response>] = []
184
0
  ) -> ClientStreamingCall<Request, Response> {
185
0
    let rpc: ClientStreamingCall<Request, Response> = ClientStreamingCall(
186
0
      call: self.makeCall(
187
0
        path: path,
188
0
        type: .clientStreaming,
189
0
        callOptions: callOptions,
190
0
        interceptors: interceptors
191
0
      )
192
0
    )
193
0
    rpc.invoke()
194
0
    return rpc
195
0
  }
196
197
  /// Make a server-streaming gRPC call.
198
  ///
199
  /// - Parameters:
200
  ///   - path: Path of the RPC, e.g. "/echo.Echo/Get"
201
  ///   - request: The request to send.
202
  ///   - callOptions: Options for the RPC.
203
  ///   - interceptors: A list of interceptors to intercept the request and response stream with.
204
  ///   - handler: Response handler; called for every response received from the server.
205
  public func makeServerStreamingCall<Request: Message, Response: Message>(
206
    path: String,
207
    request: Request,
208
    callOptions: CallOptions,
209
    interceptors: [ClientInterceptor<Request, Response>] = [],
210
    handler: @escaping (Response) -> Void
211
0
  ) -> ServerStreamingCall<Request, Response> {
212
0
    let rpc: ServerStreamingCall<Request, Response> = ServerStreamingCall(
213
0
      call: self.makeCall(
214
0
        path: path,
215
0
        type: .serverStreaming,
216
0
        callOptions: callOptions,
217
0
        interceptors: interceptors
218
0
      ),
219
0
      callback: handler
220
0
    )
221
0
    rpc.invoke(request)
222
0
    return rpc
223
0
  }
224
225
  /// Make a server-streaming gRPC call.
226
  ///
227
  /// - Parameters:
228
  ///   - path: Path of the RPC, e.g. "/echo.Echo/Get"
229
  ///   - request: The request to send.
230
  ///   - callOptions: Options for the RPC.
231
  ///   - interceptors: A list of interceptors to intercept the request and response stream with.
232
  ///   - handler: Response handler; called for every response received from the server.
233
  public func makeServerStreamingCall<Request: GRPCPayload, Response: GRPCPayload>(
234
    path: String,
235
    request: Request,
236
    callOptions: CallOptions,
237
    interceptors: [ClientInterceptor<Request, Response>] = [],
238
    handler: @escaping (Response) -> Void
239
0
  ) -> ServerStreamingCall<Request, Response> {
240
0
    let rpc: ServerStreamingCall<Request, Response> = ServerStreamingCall(
241
0
      call: self.makeCall(
242
0
        path: path,
243
0
        type: .serverStreaming,
244
0
        callOptions: callOptions,
245
0
        interceptors: []
246
0
      ),
247
0
      callback: handler
248
0
    )
249
0
    rpc.invoke(request)
250
0
    return rpc
251
0
  }
252
253
  /// Makes a bidirectional-streaming gRPC call.
254
  ///
255
  /// - Parameters:
256
  ///   - path: Path of the RPC, e.g. "/echo.Echo/Get"
257
  ///   - callOptions: Options for the RPC.
258
  ///   - interceptors: A list of interceptors to intercept the request and response stream with.
259
  ///   - handler: Response handler; called for every response received from the server.
260
  public func makeBidirectionalStreamingCall<Request: Message, Response: Message>(
261
    path: String,
262
    callOptions: CallOptions,
263
    interceptors: [ClientInterceptor<Request, Response>] = [],
264
    handler: @escaping (Response) -> Void
265
0
  ) -> BidirectionalStreamingCall<Request, Response> {
266
0
    let rpc: BidirectionalStreamingCall<Request, Response> = BidirectionalStreamingCall(
267
0
      call: self.makeCall(
268
0
        path: path,
269
0
        type: .bidirectionalStreaming,
270
0
        callOptions: callOptions,
271
0
        interceptors: interceptors
272
0
      ),
273
0
      callback: handler
274
0
    )
275
0
    rpc.invoke()
276
0
    return rpc
277
0
  }
278
279
  /// Makes a bidirectional-streaming gRPC call.
280
  ///
281
  /// - Parameters:
282
  ///   - path: Path of the RPC, e.g. "/echo.Echo/Get"
283
  ///   - callOptions: Options for the RPC.
284
  ///   - interceptors: A list of interceptors to intercept the request and response stream with.
285
  ///   - handler: Response handler; called for every response received from the server.
286
  public func makeBidirectionalStreamingCall<Request: GRPCPayload, Response: GRPCPayload>(
287
    path: String,
288
    callOptions: CallOptions,
289
    interceptors: [ClientInterceptor<Request, Response>] = [],
290
    handler: @escaping (Response) -> Void
291
0
  ) -> BidirectionalStreamingCall<Request, Response> {
292
0
    let rpc: BidirectionalStreamingCall<Request, Response> = BidirectionalStreamingCall(
293
0
      call: self.makeCall(
294
0
        path: path,
295
0
        type: .bidirectionalStreaming,
296
0
        callOptions: callOptions,
297
0
        interceptors: interceptors
298
0
      ),
299
0
      callback: handler
300
0
    )
301
0
    rpc.invoke()
302
0
    return rpc
303
0
  }
304
}