Skip to content

Commit fc2d640

Browse files
authored
Generate async echo client and server, add async server implementation and basic tests (#1260)
Motivation: In #1259 code generation was added for async client and servers. We should generate the echo service and have tests exercising the generated async code. Modifications: Switch on async code generation for echo Implement an async echo service and add some basic tests Results: We run tests with an async client and server
1 parent ea595b5 commit fc2d640

File tree

4 files changed

+422
-5
lines changed

4 files changed

+422
-5
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ ${ECHO_GRPC}: ${ECHO_PROTO} ${PROTOC_GEN_GRPC_SWIFT}
7878
protoc $< \
7979
--proto_path=$(dir $<) \
8080
--plugin=${PROTOC_GEN_GRPC_SWIFT} \
81-
--grpc-swift_opt=Visibility=Public,TestClient=true \
81+
--grpc-swift_opt=Visibility=Public,TestClient=true,ExperimentalAsyncClient=true,ExperimentalAsyncServer=true \
8282
--grpc-swift_out=$(dir $<)
8383

8484
# Generates protobufs and gRPC client and server for the Echo example
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright 2021, 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+
#if compiler(>=5.5)
17+
import EchoModel
18+
import GRPC
19+
20+
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
21+
public final class EchoAsyncProvider: Echo_EchoAsyncProvider {
22+
public let interceptors: Echo_EchoServerInterceptorFactoryProtocol?
23+
24+
public init(interceptors: Echo_EchoServerInterceptorFactoryProtocol? = nil) {
25+
self.interceptors = interceptors
26+
}
27+
28+
public func get(
29+
request: Echo_EchoRequest,
30+
context: GRPCAsyncServerCallContext
31+
) async throws -> Echo_EchoResponse {
32+
return .with {
33+
$0.text = "Swift echo get: " + request.text
34+
}
35+
}
36+
37+
public func expand(
38+
request: Echo_EchoRequest,
39+
responseStream: GRPCAsyncResponseStreamWriter<Echo_EchoResponse>,
40+
context: GRPCAsyncServerCallContext
41+
) async throws {
42+
for (i, part) in request.text.components(separatedBy: " ").lazy.enumerated() {
43+
try await responseStream.send(.with { $0.text = "Swift echo expand (\(i)): \(part)" })
44+
}
45+
}
46+
47+
public func collect(
48+
requests: GRPCAsyncRequestStream<Echo_EchoRequest>,
49+
context: GRPCAsyncServerCallContext
50+
) async throws -> Echo_EchoResponse {
51+
let text = try await requests.reduce(into: "Swift echo collect:") { result, request in
52+
result += " \(request.text)"
53+
}
54+
55+
return .with { $0.text = text }
56+
}
57+
58+
public func update(
59+
requests: GRPCAsyncRequestStream<Echo_EchoRequest>,
60+
responseStream: GRPCAsyncResponseStreamWriter<Echo_EchoResponse>,
61+
context: GRPCAsyncServerCallContext
62+
) async throws {
63+
var counter = 0
64+
for try await request in requests {
65+
let text = "Swift echo update (\(counter)): \(request.text)"
66+
try await responseStream.send(.with { $0.text = text })
67+
counter += 1
68+
}
69+
}
70+
}
71+
72+
#endif // compiler(>=5.5)

Sources/Examples/Echo/Model/echo.grpc.swift

Lines changed: 193 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,101 @@ public final class Echo_EchoClient: Echo_EchoClientProtocol {
172172
}
173173
}
174174

175+
#if compiler(>=5.5)
176+
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
177+
public protocol Echo_EchoAsyncClientProtocol: GRPCClient {
178+
var serviceName: String { get }
179+
var interceptors: Echo_EchoClientInterceptorFactoryProtocol? { get }
180+
181+
func makeGetCall(
182+
_ request: Echo_EchoRequest,
183+
callOptions: CallOptions?
184+
) -> GRPCAsyncUnaryCall<Echo_EchoRequest, Echo_EchoResponse>
185+
186+
func makeExpandCall(
187+
_ request: Echo_EchoRequest,
188+
callOptions: CallOptions?
189+
) -> GRPCAsyncServerStreamingCall<Echo_EchoRequest, Echo_EchoResponse>
190+
191+
func makeCollectCall(
192+
callOptions: CallOptions?
193+
) -> GRPCAsyncClientStreamingCall<Echo_EchoRequest, Echo_EchoResponse>
194+
195+
func makeUpdateCall(
196+
callOptions: CallOptions?
197+
) -> GRPCAsyncBidirectionalStreamingCall<Echo_EchoRequest, Echo_EchoResponse>
198+
}
199+
200+
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
201+
extension Echo_EchoAsyncClientProtocol {
202+
public var serviceName: String {
203+
return "echo.Echo"
204+
}
205+
206+
public var interceptors: Echo_EchoClientInterceptorFactoryProtocol? {
207+
return nil
208+
}
209+
210+
public func makeGetCall(
211+
_ request: Echo_EchoRequest,
212+
callOptions: CallOptions? = nil
213+
) -> GRPCAsyncUnaryCall<Echo_EchoRequest, Echo_EchoResponse> {
214+
return self.makeAsyncUnaryCall(
215+
path: "/echo.Echo/Get",
216+
request: request,
217+
callOptions: callOptions ?? self.defaultCallOptions
218+
)
219+
}
220+
221+
public func makeExpandCall(
222+
_ request: Echo_EchoRequest,
223+
callOptions: CallOptions? = nil
224+
) -> GRPCAsyncServerStreamingCall<Echo_EchoRequest, Echo_EchoResponse> {
225+
return self.makeAsyncServerStreamingCall(
226+
path: "/echo.Echo/Expand",
227+
request: request,
228+
callOptions: callOptions ?? self.defaultCallOptions
229+
)
230+
}
231+
232+
public func makeCollectCall(
233+
callOptions: CallOptions? = nil
234+
) -> GRPCAsyncClientStreamingCall<Echo_EchoRequest, Echo_EchoResponse> {
235+
return self.makeAsyncClientStreamingCall(
236+
path: "/echo.Echo/Collect",
237+
callOptions: callOptions ?? self.defaultCallOptions
238+
)
239+
}
240+
241+
public func makeUpdateCall(
242+
callOptions: CallOptions? = nil
243+
) -> GRPCAsyncBidirectionalStreamingCall<Echo_EchoRequest, Echo_EchoResponse> {
244+
return self.makeAsyncBidirectionalStreamingCall(
245+
path: "/echo.Echo/Update",
246+
callOptions: callOptions ?? self.defaultCallOptions
247+
)
248+
}
249+
}
250+
251+
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
252+
public struct Echo_EchoAsyncClient: Echo_EchoAsyncClientProtocol {
253+
public var channel: GRPCChannel
254+
public var defaultCallOptions: CallOptions
255+
public var interceptors: Echo_EchoClientInterceptorFactoryProtocol?
256+
257+
public init(
258+
channel: GRPCChannel,
259+
defaultCallOptions: CallOptions = CallOptions(),
260+
interceptors: Echo_EchoClientInterceptorFactoryProtocol? = nil
261+
) {
262+
self.channel = channel
263+
self.defaultCallOptions = defaultCallOptions
264+
self.interceptors = interceptors
265+
}
266+
}
267+
268+
#endif // compiler(>=5.5)
269+
175270
public final class Echo_EchoTestClient: Echo_EchoClientProtocol {
176271
private let fakeChannel: FakeChannel
177272
public var defaultCallOptions: CallOptions
@@ -204,7 +299,7 @@ public final class Echo_EchoTestClient: Echo_EchoClientProtocol {
204299
public func enqueueGetResponse(
205300
_ response: Echo_EchoResponse,
206301
_ requestHandler: @escaping (FakeRequestPart<Echo_EchoRequest>) -> () = { _ in }
207-
) {
302+
) {
208303
let stream = self.makeGetResponseStream(requestHandler)
209304
// This is the only operation on the stream; try! is fine.
210305
try! stream.sendMessage(response)
@@ -228,7 +323,7 @@ public final class Echo_EchoTestClient: Echo_EchoClientProtocol {
228323
public func enqueueExpandResponses(
229324
_ responses: [Echo_EchoResponse],
230325
_ requestHandler: @escaping (FakeRequestPart<Echo_EchoRequest>) -> () = { _ in }
231-
) {
326+
) {
232327
let stream = self.makeExpandResponseStream(requestHandler)
233328
// These are the only operation on the stream; try! is fine.
234329
responses.forEach { try! stream.sendMessage($0) }
@@ -253,7 +348,7 @@ public final class Echo_EchoTestClient: Echo_EchoClientProtocol {
253348
public func enqueueCollectResponse(
254349
_ response: Echo_EchoResponse,
255350
_ requestHandler: @escaping (FakeRequestPart<Echo_EchoRequest>) -> () = { _ in }
256-
) {
351+
) {
257352
let stream = self.makeCollectResponseStream(requestHandler)
258353
// This is the only operation on the stream; try! is fine.
259354
try! stream.sendMessage(response)
@@ -277,7 +372,7 @@ public final class Echo_EchoTestClient: Echo_EchoClientProtocol {
277372
public func enqueueUpdateResponses(
278373
_ responses: [Echo_EchoResponse],
279374
_ requestHandler: @escaping (FakeRequestPart<Echo_EchoRequest>) -> () = { _ in }
280-
) {
375+
) {
281376
let stream = self.makeUpdateResponseStream(requestHandler)
282377
// These are the only operation on the stream; try! is fine.
283378
responses.forEach { try! stream.sendMessage($0) }
@@ -377,3 +472,97 @@ public protocol Echo_EchoServerInterceptorFactoryProtocol {
377472
/// Defaults to calling `self.makeInterceptors()`.
378473
func makeUpdateInterceptors() -> [ServerInterceptor<Echo_EchoRequest, Echo_EchoResponse>]
379474
}
475+
476+
#if compiler(>=5.5)
477+
478+
/// To implement a server, implement an object which conforms to this protocol.
479+
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
480+
public protocol Echo_EchoAsyncProvider: CallHandlerProvider {
481+
var interceptors: Echo_EchoServerInterceptorFactoryProtocol? { get }
482+
483+
/// Immediately returns an echo of a request.
484+
@Sendable func get(
485+
request: Echo_EchoRequest,
486+
context: GRPCAsyncServerCallContext
487+
) async throws -> Echo_EchoResponse
488+
489+
/// Splits a request into words and returns each word in a stream of messages.
490+
@Sendable func expand(
491+
request: Echo_EchoRequest,
492+
responseStream: GRPCAsyncResponseStreamWriter<Echo_EchoResponse>,
493+
context: GRPCAsyncServerCallContext
494+
) async throws
495+
496+
/// Collects a stream of messages and returns them concatenated when the caller closes.
497+
@Sendable func collect(
498+
requests: GRPCAsyncRequestStream<Echo_EchoRequest>,
499+
context: GRPCAsyncServerCallContext
500+
) async throws -> Echo_EchoResponse
501+
502+
/// Streams back messages as they are received in an input stream.
503+
@Sendable func update(
504+
requests: GRPCAsyncRequestStream<Echo_EchoRequest>,
505+
responseStream: GRPCAsyncResponseStreamWriter<Echo_EchoResponse>,
506+
context: GRPCAsyncServerCallContext
507+
) async throws
508+
}
509+
510+
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
511+
extension Echo_EchoAsyncProvider {
512+
public var serviceName: Substring {
513+
return "echo.Echo"
514+
}
515+
516+
public var interceptors: Echo_EchoServerInterceptorFactoryProtocol? {
517+
return nil
518+
}
519+
520+
public func handle(
521+
method name: Substring,
522+
context: CallHandlerContext
523+
) -> GRPCServerHandlerProtocol? {
524+
switch name {
525+
case "Get":
526+
return GRPCAsyncServerHandler(
527+
context: context,
528+
requestDeserializer: ProtobufDeserializer<Echo_EchoRequest>(),
529+
responseSerializer: ProtobufSerializer<Echo_EchoResponse>(),
530+
interceptors: self.interceptors?.makeGetInterceptors() ?? [],
531+
wrapping: self.get(request:context:)
532+
)
533+
534+
case "Expand":
535+
return GRPCAsyncServerHandler(
536+
context: context,
537+
requestDeserializer: ProtobufDeserializer<Echo_EchoRequest>(),
538+
responseSerializer: ProtobufSerializer<Echo_EchoResponse>(),
539+
interceptors: self.interceptors?.makeExpandInterceptors() ?? [],
540+
wrapping: self.expand(request:responseStream:context:)
541+
)
542+
543+
case "Collect":
544+
return GRPCAsyncServerHandler(
545+
context: context,
546+
requestDeserializer: ProtobufDeserializer<Echo_EchoRequest>(),
547+
responseSerializer: ProtobufSerializer<Echo_EchoResponse>(),
548+
interceptors: self.interceptors?.makeCollectInterceptors() ?? [],
549+
wrapping: self.collect(requests:context:)
550+
)
551+
552+
case "Update":
553+
return GRPCAsyncServerHandler(
554+
context: context,
555+
requestDeserializer: ProtobufDeserializer<Echo_EchoRequest>(),
556+
responseSerializer: ProtobufSerializer<Echo_EchoResponse>(),
557+
interceptors: self.interceptors?.makeUpdateInterceptors() ?? [],
558+
wrapping: self.update(requests:responseStream:context:)
559+
)
560+
561+
default:
562+
return nil
563+
}
564+
}
565+
}
566+
567+
#endif // compiler(>=5.5)
568+

0 commit comments

Comments
 (0)