Coverage Report

Created: 2026-03-11 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/grpc-swift/Sources/GRPC/GRPCClient.swift
Line
Count
Source
1
/*
2
 * Copyright 2019, 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 NIOConcurrencyHelpers
17
import NIOCore
18
import NIOHTTP2
19
import SwiftProtobuf
20
21
/// A gRPC client.
22
public protocol GRPCClient: GRPCPreconcurrencySendable {
23
  /// The gRPC channel over which RPCs are sent and received. Note that this is distinct
24
  /// from `NIO.Channel`.
25
  var channel: GRPCChannel { get }
26
27
  /// The call options to use should the user not provide per-call options.
28
  var defaultCallOptions: CallOptions { get set }
29
}
30
31
// MARK: Convenience methods
32
33
extension GRPCClient {
34
  public func makeUnaryCall<Request: SwiftProtobuf.Message, Response: SwiftProtobuf.Message>(
35
    path: String,
36
    request: Request,
37
    callOptions: CallOptions? = nil,
38
    interceptors: [ClientInterceptor<Request, Response>] = [],
39
    responseType: Response.Type = Response.self
40
0
  ) -> UnaryCall<Request, Response> {
41
0
    return self.channel.makeUnaryCall(
42
0
      path: path,
43
0
      request: request,
44
0
      callOptions: callOptions ?? self.defaultCallOptions,
45
0
      interceptors: interceptors
46
0
    )
47
0
  }
48
49
  public func makeUnaryCall<Request: GRPCPayload, Response: GRPCPayload>(
50
    path: String,
51
    request: Request,
52
    callOptions: CallOptions? = nil,
53
    interceptors: [ClientInterceptor<Request, Response>] = [],
54
    responseType: Response.Type = Response.self
55
0
  ) -> UnaryCall<Request, Response> {
56
0
    return self.channel.makeUnaryCall(
57
0
      path: path,
58
0
      request: request,
59
0
      callOptions: callOptions ?? self.defaultCallOptions,
60
0
      interceptors: interceptors
61
0
    )
62
0
  }
63
64
  public func makeServerStreamingCall<
65
    Request: SwiftProtobuf.Message,
66
    Response: SwiftProtobuf.Message
67
  >(
68
    path: String,
69
    request: Request,
70
    callOptions: CallOptions? = nil,
71
    interceptors: [ClientInterceptor<Request, Response>] = [],
72
    responseType: Response.Type = Response.self,
73
    handler: @escaping (Response) -> Void
74
0
  ) -> ServerStreamingCall<Request, Response> {
75
0
    return self.channel.makeServerStreamingCall(
76
0
      path: path,
77
0
      request: request,
78
0
      callOptions: callOptions ?? self.defaultCallOptions,
79
0
      interceptors: interceptors,
80
0
      handler: handler
81
0
    )
82
0
  }
83
84
  public func makeServerStreamingCall<Request: GRPCPayload, Response: GRPCPayload>(
85
    path: String,
86
    request: Request,
87
    callOptions: CallOptions? = nil,
88
    interceptors: [ClientInterceptor<Request, Response>] = [],
89
    responseType: Response.Type = Response.self,
90
    handler: @escaping (Response) -> Void
91
0
  ) -> ServerStreamingCall<Request, Response> {
92
0
    return self.channel.makeServerStreamingCall(
93
0
      path: path,
94
0
      request: request,
95
0
      callOptions: callOptions ?? self.defaultCallOptions,
96
0
      interceptors: interceptors,
97
0
      handler: handler
98
0
    )
99
0
  }
100
101
  public func makeClientStreamingCall<
102
    Request: SwiftProtobuf.Message,
103
    Response: SwiftProtobuf.Message
104
  >(
105
    path: String,
106
    callOptions: CallOptions? = nil,
107
    interceptors: [ClientInterceptor<Request, Response>] = [],
108
    requestType: Request.Type = Request.self,
109
    responseType: Response.Type = Response.self
110
0
  ) -> ClientStreamingCall<Request, Response> {
111
0
    return self.channel.makeClientStreamingCall(
112
0
      path: path,
113
0
      callOptions: callOptions ?? self.defaultCallOptions,
114
0
      interceptors: interceptors
115
0
    )
116
0
  }
117
118
  public func makeClientStreamingCall<Request: GRPCPayload, Response: GRPCPayload>(
119
    path: String,
120
    callOptions: CallOptions? = nil,
121
    interceptors: [ClientInterceptor<Request, Response>] = [],
122
    requestType: Request.Type = Request.self,
123
    responseType: Response.Type = Response.self
124
0
  ) -> ClientStreamingCall<Request, Response> {
125
0
    return self.channel.makeClientStreamingCall(
126
0
      path: path,
127
0
      callOptions: callOptions ?? self.defaultCallOptions,
128
0
      interceptors: interceptors
129
0
    )
130
0
  }
131
132
  public func makeBidirectionalStreamingCall<
133
    Request: SwiftProtobuf.Message,
134
    Response: SwiftProtobuf.Message
135
  >(
136
    path: String,
137
    callOptions: CallOptions? = nil,
138
    interceptors: [ClientInterceptor<Request, Response>] = [],
139
    requestType: Request.Type = Request.self,
140
    responseType: Response.Type = Response.self,
141
    handler: @escaping (Response) -> Void
142
0
  ) -> BidirectionalStreamingCall<Request, Response> {
143
0
    return self.channel.makeBidirectionalStreamingCall(
144
0
      path: path,
145
0
      callOptions: callOptions ?? self.defaultCallOptions,
146
0
      interceptors: interceptors,
147
0
      handler: handler
148
0
    )
149
0
  }
150
151
  public func makeBidirectionalStreamingCall<Request: GRPCPayload, Response: GRPCPayload>(
152
    path: String,
153
    callOptions: CallOptions? = nil,
154
    interceptors: [ClientInterceptor<Request, Response>] = [],
155
    requestType: Request.Type = Request.self,
156
    responseType: Response.Type = Response.self,
157
    handler: @escaping (Response) -> Void
158
0
  ) -> BidirectionalStreamingCall<Request, Response> {
159
0
    return self.channel.makeBidirectionalStreamingCall(
160
0
      path: path,
161
0
      callOptions: callOptions ?? self.defaultCallOptions,
162
0
      interceptors: interceptors,
163
0
      handler: handler
164
0
    )
165
0
  }
166
}
167
168
/// A client which has no generated stubs and may be used to create gRPC calls manually.
169
/// See ``GRPCClient`` for details.
170
///
171
/// Example:
172
///
173
/// ```
174
/// let client = AnyServiceClient(channel: channel)
175
/// let rpc: UnaryCall<Request, Response> = client.makeUnaryCall(
176
///   path: "/serviceName/methodName",
177
///   request: .with { ... },
178
/// }
179
/// ```
180
@available(*, deprecated, renamed: "GRPCAnyServiceClient")
181
public final class AnyServiceClient: GRPCClient {
182
0
  private let lock = Lock()
183
  private var _defaultCallOptions: CallOptions
184
185
  /// The gRPC channel over which RPCs are sent and received.
186
  public let channel: GRPCChannel
187
188
  /// The default options passed to each RPC unless passed for each RPC.
189
  public var defaultCallOptions: CallOptions {
190
0
    get { return self.lock.withLock { self._defaultCallOptions } }
191
0
    set { self.lock.withLockVoid { self._defaultCallOptions = newValue } }
192
  }
193
194
  /// Creates a client which may be used to call any service.
195
  ///
196
  /// - Parameters:
197
  ///   - connection: ``ClientConnection`` to the service host.
198
  ///   - defaultCallOptions: Options to use for each service call if the user doesn't provide them.
199
0
  public init(channel: GRPCChannel, defaultCallOptions: CallOptions = CallOptions()) {
200
0
    self.channel = channel
201
0
    self._defaultCallOptions = defaultCallOptions
202
0
  }
203
}
204
205
// Unchecked because mutable state is protected by a lock.
206
@available(*, deprecated, renamed: "GRPCAnyServiceClient")
207
extension AnyServiceClient: @unchecked Sendable {}
208
209
/// A client which has no generated stubs and may be used to create gRPC calls manually.
210
/// See ``GRPCClient`` for details.
211
///
212
/// Example:
213
///
214
/// ```
215
/// let client = GRPCAnyServiceClient(channel: channel)
216
/// let rpc: UnaryCall<Request, Response> = client.makeUnaryCall(
217
///   path: "/serviceName/methodName",
218
///   request: .with { ... },
219
/// }
220
/// ```
221
public struct GRPCAnyServiceClient: GRPCClient {
222
  public let channel: GRPCChannel
223
224
  /// The default options passed to each RPC unless passed for each RPC.
225
  public var defaultCallOptions: CallOptions
226
227
  /// Creates a client which may be used to call any service.
228
  ///
229
  /// - Parameters:
230
  ///   - connection: ``ClientConnection`` to the service host.
231
  ///   - defaultCallOptions: Options to use for each service call if the user doesn't provide them.
232
0
  public init(channel: GRPCChannel, defaultCallOptions: CallOptions = CallOptions()) {
233
0
    self.channel = channel
234
0
    self.defaultCallOptions = defaultCallOptions
235
0
  }
236
}