Created
February 23, 2018 18:59
-
-
Save MrMage/cbd6277d3c4e51179cae2798e70b2112 to your computer and use it in GitHub Desktop.
Example for generated code without a package name set
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* DO NOT EDIT. | |
* | |
* Generated by the protocol buffer compiler. | |
* Source: echo.proto | |
* | |
*/ | |
/* | |
* Copyright 2018, gRPC Authors All rights reserved. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
import Foundation | |
import Dispatch | |
import gRPC | |
import SwiftProtobuf | |
/// Type for errors thrown from generated client code. | |
internal enum EchoClientError : Error { | |
case endOfStream | |
case invalidMessageReceived | |
case error(c: CallResult) | |
} | |
/// Get (Unary) | |
internal final class EchoGetCall { | |
private var call : Call | |
/// Create a call. | |
fileprivate init(_ channel: Channel) { | |
self.call = channel.makeCall("/Echo/Get") | |
} | |
/// Run the call. Blocks until the reply is received. | |
/// - Throws: `BinaryEncodingError` if encoding fails. `CallError` if fails to call. `EchoClientError` if receives no response. | |
fileprivate func run(request: EchoRequest, | |
metadata: Metadata) throws -> EchoResponse { | |
let sem = DispatchSemaphore(value: 0) | |
var returnCallResult : CallResult! | |
var returnResponse : EchoResponse? | |
_ = try start(request:request, metadata:metadata) {response, callResult in | |
returnResponse = response | |
returnCallResult = callResult | |
sem.signal() | |
} | |
_ = sem.wait(timeout: DispatchTime.distantFuture) | |
if let returnResponse = returnResponse { | |
return returnResponse | |
} else { | |
throw EchoClientError.error(c: returnCallResult) | |
} | |
} | |
/// Start the call. Nonblocking. | |
/// - Throws: `BinaryEncodingError` if encoding fails. `CallError` if fails to call. | |
fileprivate func start(request: EchoRequest, | |
metadata: Metadata, | |
completion: @escaping (EchoResponse?, CallResult)->()) | |
throws -> EchoGetCall { | |
let requestData = try request.serializedData() | |
try call.start(.unary, | |
metadata:metadata, | |
message:requestData) | |
{(callResult) in | |
if let responseData = callResult.resultData, | |
let response = try? EchoResponse(serializedData:responseData) { | |
completion(response, callResult) | |
} else { | |
completion(nil, callResult) | |
} | |
} | |
return self | |
} | |
/// Cancel the call. | |
internal func cancel() { | |
call.cancel() | |
} | |
} | |
/// Expand (Server Streaming) | |
internal final class EchoExpandCall { | |
private var call : Call | |
/// Create a call. | |
fileprivate init(_ channel: Channel) { | |
self.call = channel.makeCall("/Echo/Expand") | |
} | |
/// Call this once with the message to send. Nonblocking. | |
fileprivate func start(request: EchoRequest, | |
metadata: Metadata, | |
completion: @escaping (CallResult) -> ()) | |
throws -> EchoExpandCall { | |
let requestData = try request.serializedData() | |
try call.start(.serverStreaming, | |
metadata:metadata, | |
message:requestData, | |
completion:completion) | |
return self | |
} | |
/// Call this to wait for a result. Blocking. | |
internal func receive() throws -> EchoResponse { | |
var returnError : EchoClientError? | |
var returnResponse : EchoResponse! | |
let sem = DispatchSemaphore(value: 0) | |
do { | |
try receive() {response, error in | |
returnResponse = response | |
returnError = error | |
sem.signal() | |
} | |
_ = sem.wait(timeout: DispatchTime.distantFuture) | |
} | |
if let returnError = returnError { | |
throw returnError | |
} | |
return returnResponse | |
} | |
/// Call this to wait for a result. Nonblocking. | |
internal func receive(completion:@escaping (EchoResponse?, EchoClientError?)->()) throws { | |
do { | |
try call.receiveMessage() {(responseData) in | |
if let responseData = responseData { | |
if let response = try? EchoResponse(serializedData:responseData) { | |
completion(response, nil) | |
} else { | |
completion(nil, EchoClientError.invalidMessageReceived) | |
} | |
} else { | |
completion(nil, EchoClientError.endOfStream) | |
} | |
} | |
} | |
} | |
/// Cancel the call. | |
internal func cancel() { | |
call.cancel() | |
} | |
} | |
/// Collect (Client Streaming) | |
internal final class EchoCollectCall { | |
private var call : Call | |
/// Create a call. | |
fileprivate init(_ channel: Channel) { | |
self.call = channel.makeCall("/Echo/Collect") | |
} | |
/// Call this to start a call. Nonblocking. | |
fileprivate func start(metadata:Metadata, completion:@escaping (CallResult)->()) | |
throws -> EchoCollectCall { | |
try self.call.start(.clientStreaming, metadata:metadata, completion:completion) | |
return self | |
} | |
/// Call this to send each message in the request stream. Nonblocking. | |
internal func send(_ message:EchoRequest, errorHandler:@escaping (Error)->()) throws { | |
let messageData = try message.serializedData() | |
try call.sendMessage(data:messageData, errorHandler:errorHandler) | |
} | |
/// Call this to close the connection and wait for a response. Blocking. | |
internal func closeAndReceive() throws -> EchoResponse { | |
var returnError : EchoClientError? | |
var returnResponse : EchoResponse! | |
let sem = DispatchSemaphore(value: 0) | |
do { | |
try closeAndReceive() {response, error in | |
returnResponse = response | |
returnError = error | |
sem.signal() | |
} | |
_ = sem.wait(timeout: DispatchTime.distantFuture) | |
} catch (let error) { | |
throw error | |
} | |
if let returnError = returnError { | |
throw returnError | |
} | |
return returnResponse | |
} | |
/// Call this to close the connection and wait for a response. Nonblocking. | |
internal func closeAndReceive(completion:@escaping (EchoResponse?, EchoClientError?)->()) | |
throws { | |
do { | |
try call.receiveMessage() {(responseData) in | |
if let responseData = responseData, | |
let response = try? EchoResponse(serializedData:responseData) { | |
completion(response, nil) | |
} else { | |
completion(nil, EchoClientError.invalidMessageReceived) | |
} | |
} | |
try call.close(completion:{}) | |
} catch (let error) { | |
throw error | |
} | |
} | |
/// Cancel the call. | |
internal func cancel() { | |
call.cancel() | |
} | |
} | |
/// Update (Bidirectional Streaming) | |
internal final class EchoUpdateCall { | |
private var call : Call | |
/// Create a call. | |
fileprivate init(_ channel: Channel) { | |
self.call = channel.makeCall("/Echo/Update") | |
} | |
/// Call this to start a call. Nonblocking. | |
fileprivate func start(metadata:Metadata, completion:@escaping (CallResult)->()) | |
throws -> EchoUpdateCall { | |
try self.call.start(.bidiStreaming, metadata:metadata, completion:completion) | |
return self | |
} | |
/// Call this to wait for a result. Blocking. | |
internal func receive() throws -> EchoResponse { | |
var returnError : EchoClientError? | |
var returnMessage : EchoResponse! | |
let sem = DispatchSemaphore(value: 0) | |
do { | |
try receive() {response, error in | |
returnMessage = response | |
returnError = error | |
sem.signal() | |
} | |
_ = sem.wait(timeout: DispatchTime.distantFuture) | |
} | |
if let returnError = returnError { | |
throw returnError | |
} | |
return returnMessage | |
} | |
/// Call this to wait for a result. Nonblocking. | |
internal func receive(completion:@escaping (EchoResponse?, EchoClientError?)->()) throws { | |
do { | |
try call.receiveMessage() {(data) in | |
if let data = data { | |
if let returnMessage = try? EchoResponse(serializedData:data) { | |
completion(returnMessage, nil) | |
} else { | |
completion(nil, EchoClientError.invalidMessageReceived) | |
} | |
} else { | |
completion(nil, EchoClientError.endOfStream) | |
} | |
} | |
} | |
} | |
/// Call this to send each message in the request stream. | |
internal func send(_ message:EchoRequest, errorHandler:@escaping (Error)->()) throws { | |
let messageData = try message.serializedData() | |
try call.sendMessage(data:messageData, errorHandler:errorHandler) | |
} | |
/// Call this to close the sending connection. Blocking. | |
internal func closeSend() throws { | |
let sem = DispatchSemaphore(value: 0) | |
try closeSend() { | |
sem.signal() | |
} | |
_ = sem.wait(timeout: DispatchTime.distantFuture) | |
} | |
/// Call this to close the sending connection. Nonblocking. | |
internal func closeSend(completion:@escaping ()->()) throws { | |
try call.close() { | |
completion() | |
} | |
} | |
/// Cancel the call. | |
internal func cancel() { | |
call.cancel() | |
} | |
} | |
/// Call methods of this class to make API calls. | |
internal final class EchoService { | |
public private(set) var channel: Channel | |
/// This metadata will be sent with all requests. | |
internal var metadata : Metadata | |
/// This property allows the service host name to be overridden. | |
/// For example, it can be used to make calls to "localhost:8080" | |
/// appear to be to "example.com". | |
internal var host : String { | |
get { | |
return self.channel.host | |
} | |
set { | |
self.channel.host = newValue | |
} | |
} | |
/// This property allows the service timeout to be overridden. | |
internal var timeout : TimeInterval { | |
get { | |
return self.channel.timeout | |
} | |
set { | |
self.channel.timeout = newValue | |
} | |
} | |
/// Create a client. | |
internal init(address: String, secure: Bool = true) { | |
gRPC.initialize() | |
channel = Channel(address:address, secure:secure) | |
metadata = Metadata() | |
} | |
/// Create a client that makes secure connections with a custom certificate and (optional) hostname. | |
internal init(address: String, certificates: String, host: String?) { | |
gRPC.initialize() | |
channel = Channel(address:address, certificates:certificates, host:host) | |
metadata = Metadata() | |
} | |
/// Synchronous. Unary. | |
internal func get(_ request: EchoRequest) | |
throws | |
-> EchoResponse { | |
return try EchoGetCall(channel).run(request:request, metadata:metadata) | |
} | |
/// Asynchronous. Unary. | |
internal func get(_ request: EchoRequest, | |
completion: @escaping (EchoResponse?, CallResult)->()) | |
throws | |
-> EchoGetCall { | |
return try EchoGetCall(channel).start(request:request, | |
metadata:metadata, | |
completion:completion) | |
} | |
/// Asynchronous. Server-streaming. | |
/// Send the initial message. | |
/// Use methods on the returned object to get streamed responses. | |
internal func expand(_ request: EchoRequest, completion: @escaping (CallResult)->()) | |
throws | |
-> EchoExpandCall { | |
return try EchoExpandCall(channel).start(request:request, metadata:metadata, completion:completion) | |
} | |
/// Asynchronous. Client-streaming. | |
/// Use methods on the returned object to stream messages and | |
/// to close the connection and wait for a final response. | |
internal func collect(completion: @escaping (CallResult)->()) | |
throws | |
-> EchoCollectCall { | |
return try EchoCollectCall(channel).start(metadata:metadata, completion:completion) | |
} | |
/// Asynchronous. Bidirectional-streaming. | |
/// Use methods on the returned object to stream messages, | |
/// to wait for replies, and to close the connection. | |
internal func update(completion: @escaping (CallResult)->()) | |
throws | |
-> EchoUpdateCall { | |
return try EchoUpdateCall(channel).start(metadata:metadata, completion:completion) | |
} | |
} | |
/// Type for errors thrown from generated server code. | |
internal enum EchoServerError : Error { | |
case endOfStream | |
} | |
/// To build a server, implement a class that conforms to this protocol. | |
internal protocol EchoProvider { | |
func get(request : EchoRequest, session : EchoGetSession) throws -> EchoResponse | |
func expand(request : EchoRequest, session : EchoExpandSession) throws | |
func collect(session : EchoCollectSession) throws | |
func update(session : EchoUpdateSession) throws | |
} | |
/// Common properties available in each service session. | |
internal class EchoSession { | |
fileprivate var handler : gRPC.Handler | |
internal var requestMetadata : Metadata { return handler.requestMetadata } | |
internal var statusCode : StatusCode = .ok | |
internal var statusMessage : String = "OK" | |
internal var initialMetadata : Metadata = Metadata() | |
internal var trailingMetadata : Metadata = Metadata() | |
fileprivate init(handler:gRPC.Handler) { | |
self.handler = handler | |
} | |
} | |
// Get (Unary) | |
internal final class EchoGetSession : EchoSession { | |
private var provider : EchoProvider | |
/// Create a session. | |
fileprivate init(handler:gRPC.Handler, provider: EchoProvider) { | |
self.provider = provider | |
super.init(handler:handler) | |
} | |
/// Run the session. Internal. | |
fileprivate func run(queue:DispatchQueue) throws { | |
try handler.receiveMessage(initialMetadata:initialMetadata) {(requestData) in | |
if let requestData = requestData { | |
let requestMessage = try EchoRequest(serializedData:requestData) | |
let replyMessage = try self.provider.get(request:requestMessage, session: self) | |
try self.handler.sendResponse(message:replyMessage.serializedData(), | |
statusCode:self.statusCode, | |
statusMessage:self.statusMessage, | |
trailingMetadata:self.trailingMetadata) | |
} | |
} | |
} | |
} | |
// Expand (Server Streaming) | |
internal final class EchoExpandSession : EchoSession { | |
private var provider : EchoProvider | |
/// Create a session. | |
fileprivate init(handler:gRPC.Handler, provider: EchoProvider) { | |
self.provider = provider | |
super.init(handler:handler) | |
} | |
/// Send a message. Nonblocking. | |
internal func send(_ response: EchoResponse, completion: @escaping ()->()) throws { | |
try handler.sendResponse(message:response.serializedData()) {completion()} | |
} | |
/// Run the session. Internal. | |
fileprivate func run(queue:DispatchQueue) throws { | |
try self.handler.receiveMessage(initialMetadata:initialMetadata) {(requestData) in | |
if let requestData = requestData { | |
do { | |
let requestMessage = try EchoRequest(serializedData:requestData) | |
// to keep providers from blocking the server thread, | |
// we dispatch them to another queue. | |
queue.async { | |
do { | |
try self.provider.expand(request:requestMessage, session: self) | |
try self.handler.sendStatus(statusCode:self.statusCode, | |
statusMessage:self.statusMessage, | |
trailingMetadata:self.trailingMetadata, | |
completion:{}) | |
} catch (let error) { | |
print("error: \(error)") | |
} | |
} | |
} catch (let error) { | |
print("error: \(error)") | |
} | |
} | |
} | |
} | |
} | |
// Collect (Client Streaming) | |
internal final class EchoCollectSession : EchoSession { | |
private var provider : EchoProvider | |
/// Create a session. | |
fileprivate init(handler:gRPC.Handler, provider: EchoProvider) { | |
self.provider = provider | |
super.init(handler:handler) | |
} | |
/// Receive a message. Blocks until a message is received or the client closes the connection. | |
internal func receive() throws -> EchoRequest { | |
let sem = DispatchSemaphore(value: 0) | |
var requestMessage : EchoRequest? | |
try self.handler.receiveMessage() {(requestData) in | |
if let requestData = requestData { | |
requestMessage = try? EchoRequest(serializedData:requestData) | |
} | |
sem.signal() | |
} | |
_ = sem.wait(timeout: DispatchTime.distantFuture) | |
if requestMessage == nil { | |
throw EchoServerError.endOfStream | |
} | |
return requestMessage! | |
} | |
/// Send a response and close the connection. | |
internal func sendAndClose(_ response: EchoResponse) throws { | |
try self.handler.sendResponse(message:response.serializedData(), | |
statusCode:self.statusCode, | |
statusMessage:self.statusMessage, | |
trailingMetadata:self.trailingMetadata) | |
} | |
/// Run the session. Internal. | |
fileprivate func run(queue:DispatchQueue) throws { | |
try self.handler.sendMetadata(initialMetadata:initialMetadata) { | |
queue.async { | |
do { | |
try self.provider.collect(session:self) | |
} catch (let error) { | |
print("error \(error)") | |
} | |
} | |
} | |
} | |
} | |
// Update (Bidirectional Streaming) | |
internal final class EchoUpdateSession : EchoSession { | |
private var provider : EchoProvider | |
/// Create a session. | |
fileprivate init(handler:gRPC.Handler, provider: EchoProvider) { | |
self.provider = provider | |
super.init(handler:handler) | |
} | |
/// Receive a message. Blocks until a message is received or the client closes the connection. | |
internal func receive() throws -> EchoRequest { | |
let sem = DispatchSemaphore(value: 0) | |
var requestMessage : EchoRequest? | |
try self.handler.receiveMessage() {(requestData) in | |
if let requestData = requestData { | |
do { | |
requestMessage = try EchoRequest(serializedData:requestData) | |
} catch (let error) { | |
print("error \(error)") | |
} | |
} | |
sem.signal() | |
} | |
_ = sem.wait(timeout: DispatchTime.distantFuture) | |
if let requestMessage = requestMessage { | |
return requestMessage | |
} else { | |
throw EchoServerError.endOfStream | |
} | |
} | |
/// Send a message. Nonblocking. | |
internal func send(_ response: EchoResponse, completion: @escaping ()->()) throws { | |
try handler.sendResponse(message:response.serializedData()) {completion()} | |
} | |
/// Close a connection. Blocks until the connection is closed. | |
internal func close() throws { | |
let sem = DispatchSemaphore(value: 0) | |
try self.handler.sendStatus(statusCode:self.statusCode, | |
statusMessage:self.statusMessage, | |
trailingMetadata:self.trailingMetadata) { | |
sem.signal() | |
} | |
_ = sem.wait(timeout: DispatchTime.distantFuture) | |
} | |
/// Run the session. Internal. | |
fileprivate func run(queue:DispatchQueue) throws { | |
try self.handler.sendMetadata(initialMetadata:initialMetadata) { | |
queue.async { | |
do { | |
try self.provider.update(session:self) | |
} catch (let error) { | |
print("error \(error)") | |
} | |
} | |
} | |
} | |
} | |
/// Main server for generated service | |
internal final class EchoServer { | |
private var address: String | |
private var server: gRPC.Server | |
private var provider: EchoProvider? | |
/// Create a server that accepts insecure connections. | |
internal init(address:String, | |
provider:EchoProvider) { | |
gRPC.initialize() | |
self.address = address | |
self.provider = provider | |
self.server = gRPC.Server(address:address) | |
} | |
/// Create a server that accepts secure connections. | |
internal init?(address:String, | |
certificateURL:URL, | |
keyURL:URL, | |
provider:EchoProvider) { | |
gRPC.initialize() | |
self.address = address | |
self.provider = provider | |
guard | |
let certificate = try? String(contentsOf: certificateURL, encoding: .utf8), | |
let key = try? String(contentsOf: keyURL, encoding: .utf8) | |
else { | |
return nil | |
} | |
self.server = gRPC.Server(address:address, key:key, certs:certificate) | |
} | |
/// Start the server. | |
internal func start(queue:DispatchQueue = DispatchQueue.global()) { | |
guard let provider = self.provider else { | |
fatalError() // the server requires a provider | |
} | |
server.run {(handler) in | |
print("Server received request to " + handler.host | |
+ " calling " + handler.method | |
+ " from " + handler.caller | |
+ " with " + String(describing:handler.requestMetadata) ) | |
do { | |
switch handler.method { | |
case "/Echo/Get": | |
try EchoGetSession(handler:handler, provider:provider).run(queue:queue) | |
case "/Echo/Expand": | |
try EchoExpandSession(handler:handler, provider:provider).run(queue:queue) | |
case "/Echo/Collect": | |
try EchoCollectSession(handler:handler, provider:provider).run(queue:queue) | |
case "/Echo/Update": | |
try EchoUpdateSession(handler:handler, provider:provider).run(queue:queue) | |
default: | |
// handle unknown requests | |
try handler.receiveMessage(initialMetadata:Metadata()) {(requestData) in | |
try handler.sendResponse(statusCode:.unimplemented, | |
statusMessage:"unknown method " + handler.method, | |
trailingMetadata:Metadata()) | |
} | |
} | |
} catch (let error) { | |
print("Server error: \(error)") | |
} | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment