Skip to content

Commit

Permalink
Split the Echo example into model, implementation and runtime
Browse files Browse the repository at this point in the history
Motivation:

The generated code and implementation for the Echo example is used as
part of the example and as well as in the test suite. To make the
example more obvious we should split it into its constituent parts: the
model (i.e. the definition and generated code), the implementation (of
the server), and the runtime (CLI for client and server).

Modifications:

- Split the Echo example into three modules: `EchoModel` (generated code),
  `EchoImplementation` (server implementation), and `EchoRuntime` (CLI for
  client and server).
- Update the `Makefile` to target the updated paths
- Add missing imports in tests
- Make the generated code `public` (instead of `internal`) since we're
  no longer symlinking into the same module for tests

Result:

- No more symlinks for Echo
- Structure of example is more straightforward
  • Loading branch information
glbrntt committed Aug 27, 2019
1 parent c5dc8f5 commit d39cced
Show file tree
Hide file tree
Showing 17 changed files with 91 additions and 74 deletions.
17 changes: 10 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@ generate-linuxmain:

# Generates protobufs and gRPC client and server for the Echo example
generate-echo: plugins
protoc Sources/Examples/Echo/echo.proto \
--proto_path=Sources/Examples/Echo \
protoc Sources/Examples/Echo/Model/echo.proto \
--proto_path=Sources/Examples/Echo/Model \
--plugin=${SWIFT_BUILD_PATH}/${SWIFT_BUILD_CONFIGURATION}/protoc-gen-swift \
--plugin=${SWIFT_BUILD_PATH}/${SWIFT_BUILD_CONFIGURATION}/protoc-gen-swiftgrpc \
--swift_out=Sources/Examples/Echo/Generated \
--swiftgrpc_out=Sources/Examples/Echo/Generated
--swift_opt=Visibility=Public \
--swift_out=Sources/Examples/Echo/Model/Generated \
--swiftgrpc_opt=Visibility=Public \
--swiftgrpc_out=Sources/Examples/Echo/Model/Generated

### Testing ####################################################################

Expand All @@ -68,12 +70,13 @@ test-generate-linuxmain: generate-linuxmain

# Generates code for the Echo server and client and tests them against 'golden' data.
test-plugin: plugins
protoc Sources/Examples/Echo/echo.proto \
--proto_path=Sources/Examples/Echo \
protoc Sources/Examples/Echo/Model/echo.proto \
--proto_path=Sources/Examples/Echo/Model \
--plugin=${SWIFT_BUILD_PATH}/${SWIFT_BUILD_CONFIGURATION}/protoc-gen-swift \
--plugin=${SWIFT_BUILD_PATH}/${SWIFT_BUILD_CONFIGURATION}/protoc-gen-swiftgrpc \
--swiftgrpc_opt=Visibility=Public \
--swiftgrpc_out=/tmp
diff -u /tmp/echo.grpc.swift Sources/Examples/Echo/Generated/echo.grpc.swift
diff -u /tmp/echo.grpc.swift Sources/Examples/Echo/Model/Generated/echo.grpc.swift

### Misc. ######################################################################

Expand Down
31 changes: 29 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ let package = Package(
name: "GRPCPerformanceTests",
dependencies: [
"GRPC",
"EchoModel",
"EchoImplementation",
"NIO",
"NIOSSL",
"Commander",
Expand All @@ -137,16 +139,41 @@ let package = Package(
dependencies: ["NIOSSL"]
),

// Echo example.
// Echo example CLI.
.target(
name: "Echo",
dependencies: [
"EchoModel",
"EchoImplementation",
"GRPC",
"GRPCSampleData",
"SwiftProtobuf",
"Commander"
],
path: "Sources/Examples/Echo"
path: "Sources/Examples/Echo/Runtime"
),

// Echo example service implementation.
.target(
name: "EchoImplementation",
dependencies: [
"EchoModel",
"GRPC",
"SwiftProtobuf"
],
path: "Sources/Examples/Echo/Implementation"
),

// Model for Echo example.
.target(
name: "EchoModel",
dependencies: [
"GRPC",
"NIO",
"NIOHTTP1",
"SwiftProtobuf"
],
path: "Sources/Examples/Echo/Model"
),
]
)
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,18 @@
import Foundation
import NIO
import GRPC
import EchoModel

class EchoProvider: Echo_EchoProvider {
func get(request: Echo_EchoRequest, context: StatusOnlyCallContext) -> EventLoopFuture<Echo_EchoResponse> {
public class EchoProvider: Echo_EchoProvider {
public init() {}

public func get(request: Echo_EchoRequest, context: StatusOnlyCallContext) -> EventLoopFuture<Echo_EchoResponse> {
var response = Echo_EchoResponse()
response.text = "Swift echo get: " + request.text
return context.eventLoop.makeSucceededFuture(response)
}

func expand(request: Echo_EchoRequest, context: StreamingResponseCallContext<Echo_EchoResponse>) -> EventLoopFuture<GRPCStatus> {
public func expand(request: Echo_EchoRequest, context: StreamingResponseCallContext<Echo_EchoResponse>) -> EventLoopFuture<GRPCStatus> {
var endOfSendOperationQueue = context.eventLoop.makeSucceededFuture(())
let parts = request.text.components(separatedBy: " ")
for (i, part) in parts.enumerated() {
Expand All @@ -35,7 +38,7 @@ class EchoProvider: Echo_EchoProvider {
return endOfSendOperationQueue.map { GRPCStatus.ok }
}

func collect(context: UnaryResponseCallContext<Echo_EchoResponse>) -> EventLoopFuture<(StreamEvent<Echo_EchoRequest>) -> Void> {
public func collect(context: UnaryResponseCallContext<Echo_EchoResponse>) -> EventLoopFuture<(StreamEvent<Echo_EchoRequest>) -> Void> {
var parts: [String] = []
return context.eventLoop.makeSucceededFuture({ event in
switch event {
Expand All @@ -50,7 +53,7 @@ class EchoProvider: Echo_EchoProvider {
})
}

func update(context: StreamingResponseCallContext<Echo_EchoResponse>) -> EventLoopFuture<(StreamEvent<Echo_EchoRequest>) -> Void> {
public func update(context: StreamingResponseCallContext<Echo_EchoResponse>) -> EventLoopFuture<(StreamEvent<Echo_EchoRequest>) -> Void> {
var endOfSendOperationQueue = context.eventLoop.makeSucceededFuture(())
var count = 0
return context.eventLoop.makeSucceededFuture({ event in
Expand Down
11 changes: 0 additions & 11 deletions Sources/Examples/Echo/Makefile

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,24 @@ import SwiftProtobuf


/// Usage: instantiate Echo_EchoServiceClient, then call methods of this protocol to make API calls.
internal protocol Echo_EchoService {
public protocol Echo_EchoService {
func get(_ request: Echo_EchoRequest, callOptions: CallOptions?) -> UnaryCall<Echo_EchoRequest, Echo_EchoResponse>
func expand(_ request: Echo_EchoRequest, callOptions: CallOptions?, handler: @escaping (Echo_EchoResponse) -> Void) -> ServerStreamingCall<Echo_EchoRequest, Echo_EchoResponse>
func collect(callOptions: CallOptions?) -> ClientStreamingCall<Echo_EchoRequest, Echo_EchoResponse>
func update(callOptions: CallOptions?, handler: @escaping (Echo_EchoResponse) -> Void) -> BidirectionalStreamingCall<Echo_EchoRequest, Echo_EchoResponse>
}

internal final class Echo_EchoServiceClient: GRPCServiceClient, Echo_EchoService {
internal let connection: ClientConnection
internal var serviceName: String { return "echo.Echo" }
internal var defaultCallOptions: CallOptions
public final class Echo_EchoServiceClient: GRPCServiceClient, Echo_EchoService {
public let connection: ClientConnection
public var serviceName: String { return "echo.Echo" }
public var defaultCallOptions: CallOptions

/// Creates a client for the echo.Echo service.
///
/// - Parameters:
/// - connection: `ClientConnection` to the service host.
/// - defaultCallOptions: Options to use for each service call if the user doesn't provide them.
internal init(connection: ClientConnection, defaultCallOptions: CallOptions = CallOptions()) {
public init(connection: ClientConnection, defaultCallOptions: CallOptions = CallOptions()) {
self.connection = connection
self.defaultCallOptions = defaultCallOptions
}
Expand All @@ -56,7 +56,7 @@ internal final class Echo_EchoServiceClient: GRPCServiceClient, Echo_EchoService
/// - request: Request to send to Get.
/// - callOptions: Call options; `self.defaultCallOptions` is used if `nil`.
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
internal func get(_ request: Echo_EchoRequest, callOptions: CallOptions? = nil) -> UnaryCall<Echo_EchoRequest, Echo_EchoResponse> {
public func get(_ request: Echo_EchoRequest, callOptions: CallOptions? = nil) -> UnaryCall<Echo_EchoRequest, Echo_EchoResponse> {
return self.makeUnaryCall(path: self.path(forMethod: "Get"),
request: request,
callOptions: callOptions ?? self.defaultCallOptions)
Expand All @@ -69,7 +69,7 @@ internal final class Echo_EchoServiceClient: GRPCServiceClient, Echo_EchoService
/// - callOptions: Call options; `self.defaultCallOptions` is used if `nil`.
/// - handler: A closure called when each response is received from the server.
/// - Returns: A `ServerStreamingCall` with futures for the metadata and status.
internal func expand(_ request: Echo_EchoRequest, callOptions: CallOptions? = nil, handler: @escaping (Echo_EchoResponse) -> Void) -> ServerStreamingCall<Echo_EchoRequest, Echo_EchoResponse> {
public func expand(_ request: Echo_EchoRequest, callOptions: CallOptions? = nil, handler: @escaping (Echo_EchoResponse) -> Void) -> ServerStreamingCall<Echo_EchoRequest, Echo_EchoResponse> {
return self.makeServerStreamingCall(path: self.path(forMethod: "Expand"),
request: request,
callOptions: callOptions ?? self.defaultCallOptions,
Expand All @@ -84,7 +84,7 @@ internal final class Echo_EchoServiceClient: GRPCServiceClient, Echo_EchoService
/// - Parameters:
/// - callOptions: Call options; `self.defaultCallOptions` is used if `nil`.
/// - Returns: A `ClientStreamingCall` with futures for the metadata, status and response.
internal func collect(callOptions: CallOptions? = nil) -> ClientStreamingCall<Echo_EchoRequest, Echo_EchoResponse> {
public func collect(callOptions: CallOptions? = nil) -> ClientStreamingCall<Echo_EchoRequest, Echo_EchoResponse> {
return self.makeClientStreamingCall(path: self.path(forMethod: "Collect"),
callOptions: callOptions ?? self.defaultCallOptions)
}
Expand All @@ -98,7 +98,7 @@ internal final class Echo_EchoServiceClient: GRPCServiceClient, Echo_EchoService
/// - callOptions: Call options; `self.defaultCallOptions` is used if `nil`.
/// - handler: A closure called when each response is received from the server.
/// - Returns: A `ClientStreamingCall` with futures for the metadata and status.
internal func update(callOptions: CallOptions? = nil, handler: @escaping (Echo_EchoResponse) -> Void) -> BidirectionalStreamingCall<Echo_EchoRequest, Echo_EchoResponse> {
public func update(callOptions: CallOptions? = nil, handler: @escaping (Echo_EchoResponse) -> Void) -> BidirectionalStreamingCall<Echo_EchoRequest, Echo_EchoResponse> {
return self.makeBidirectionalStreamingCall(path: self.path(forMethod: "Update"),
callOptions: callOptions ?? self.defaultCallOptions,
handler: handler)
Expand All @@ -107,19 +107,19 @@ internal final class Echo_EchoServiceClient: GRPCServiceClient, Echo_EchoService
}

/// To build a server, implement a class that conforms to this protocol.
internal protocol Echo_EchoProvider: CallHandlerProvider {
public protocol Echo_EchoProvider: CallHandlerProvider {
func get(request: Echo_EchoRequest, context: StatusOnlyCallContext) -> EventLoopFuture<Echo_EchoResponse>
func expand(request: Echo_EchoRequest, context: StreamingResponseCallContext<Echo_EchoResponse>) -> EventLoopFuture<GRPCStatus>
func collect(context: UnaryResponseCallContext<Echo_EchoResponse>) -> EventLoopFuture<(StreamEvent<Echo_EchoRequest>) -> Void>
func update(context: StreamingResponseCallContext<Echo_EchoResponse>) -> EventLoopFuture<(StreamEvent<Echo_EchoRequest>) -> Void>
}

extension Echo_EchoProvider {
internal var serviceName: String { return "echo.Echo" }
public var serviceName: String { return "echo.Echo" }

/// Determines, calls and returns the appropriate request handler, depending on the request's method.
/// Returns nil for methods not handled by this service.
internal func handleMethod(_ methodName: String, callHandlerContext: CallHandlerContext) -> GRPCCallHandler? {
public func handleMethod(_ methodName: String, callHandlerContext: CallHandlerContext) -> GRPCCallHandler? {
switch methodName {
case "Get":
return UnaryCallHandler(callHandlerContext: callHandlerContext) { context in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,43 +33,43 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
typealias Version = _2
}

struct Echo_EchoRequest {
public struct Echo_EchoRequest {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.

/// The text of a message to be echoed.
var text: String = String()
public var text: String = String()

var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()

init() {}
public init() {}
}

struct Echo_EchoResponse {
public struct Echo_EchoResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.

/// The text of an echo response.
var text: String = String()
public var text: String = String()

var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()

init() {}
public init() {}
}

// MARK: - Code below here is support for the SwiftProtobuf runtime.

fileprivate let _protobuf_package = "echo"

extension Echo_EchoRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".EchoRequest"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".EchoRequest"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "text"),
]

mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularStringField(value: &self.text)
Expand All @@ -78,27 +78,27 @@ extension Echo_EchoRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImpleme
}
}

func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.text.isEmpty {
try visitor.visitSingularStringField(value: self.text, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}

static func ==(lhs: Echo_EchoRequest, rhs: Echo_EchoRequest) -> Bool {
public static func ==(lhs: Echo_EchoRequest, rhs: Echo_EchoRequest) -> Bool {
if lhs.text != rhs.text {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

extension Echo_EchoResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".EchoResponse"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".EchoResponse"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "text"),
]

mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try decoder.decodeSingularStringField(value: &self.text)
Expand All @@ -107,14 +107,14 @@ extension Echo_EchoResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
}
}

func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.text.isEmpty {
try visitor.visitSingularStringField(value: self.text, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}

static func ==(lhs: Echo_EchoResponse, rhs: Echo_EchoResponse) -> Bool {
public static func ==(lhs: Echo_EchoResponse, rhs: Echo_EchoResponse) -> Bool {
if lhs.text != rhs.text {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
Expand Down
File renamed without changes.
14 changes: 9 additions & 5 deletions Sources/Examples/Echo/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# EchoNIO, a gRPC NIO Sample App
# Echo, a gRPC Sample App

This directory contains a simple echo server that demonstrates
all four gRPC API styles (Unary, Server Streaming, Client
Streaming, and Bidirectional Streaming) using the NIO based
Swift gRPC implementation.
This directory contains a simple echo server that demonstrates all four gRPC API
styles (Unary, Server Streaming, Client Streaming, and Bidirectional Streaming)
using the gRPC Swift.

There are three subdirectories:
* `Model` containing the service and model definitions and generated code,
* `Implementation` containing the server implementation of the generated model,
* `Runtime` containing a CLI for the server and client.
7 changes: 0 additions & 7 deletions Sources/Examples/Echo/RUNME

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import NIO
import NIOSSL
import GRPC
import GRPCSampleData
import EchoImplementation
import EchoModel

// Common flags and options
let sslFlag = Flag("ssl", description: "if true, use SSL for connections")
Expand Down
1 change: 0 additions & 1 deletion Sources/GRPCPerformanceTests/EchoProvider.swift

This file was deleted.

1 change: 0 additions & 1 deletion Sources/GRPCPerformanceTests/Generated/echo.grpc.swift

This file was deleted.

1 change: 0 additions & 1 deletion Sources/GRPCPerformanceTests/Generated/echo.pb.swift

This file was deleted.

2 changes: 2 additions & 0 deletions Sources/GRPCPerformanceTests/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import GRPC
import NIO
import NIOSSL
import Commander
import EchoImplementation
import EchoModel

struct ConnectionFactory {
var configuration: ClientConnection.Configuration
Expand Down
1 change: 0 additions & 1 deletion Tests/GRPCTests/EchoProvider.swift

This file was deleted.

1 change: 0 additions & 1 deletion Tests/GRPCTests/echo.grpc.swift

This file was deleted.

1 change: 0 additions & 1 deletion Tests/GRPCTests/echo.pb.swift

This file was deleted.

0 comments on commit d39cced

Please sign in to comment.