Browse Source

Some cleanup of the call surface, all in the Echo Mac app for now.

Tim Burks 9 years ago
parent
commit
2a26afc84a

+ 16 - 12
Examples/Echo/Swift/Echo.xcodeproj/project.pbxproj

@@ -7,13 +7,14 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
-		D30DACF01DB6FC2D00886B20 /* EchoService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D30DACEF1DB6FC2D00886B20 /* EchoService.swift */; };
-		D324A6021D81CF8F00421B59 /* EchoServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D324A6011D81CF8F00421B59 /* EchoServer.swift */; };
+		D30DACF01DB6FC2D00886B20 /* echo.client.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = D30DACEF1DB6FC2D00886B20 /* echo.client.pb.swift */; };
+		D324A6021D81CF8F00421B59 /* echo.server.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = D324A6011D81CF8F00421B59 /* echo.server.pb.swift */; };
 		D359A6271DBAD11C00FE6282 /* echo.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = D359A6261DBAD11C00FE6282 /* echo.pb.swift */; };
 		D35C9FAC1D74B079000443CD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D35C9FAB1D74B079000443CD /* AppDelegate.swift */; };
 		D35C9FAE1D74B079000443CD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D35C9FAD1D74B079000443CD /* Assets.xcassets */; };
 		D35C9FB11D74B079000443CD /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = D35C9FAF1D74B079000443CD /* MainMenu.xib */; };
 		D35C9FC81D74B0C1000443CD /* EchoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D35C9FC71D74B0C1000443CD /* EchoViewController.swift */; };
+		D38F9C401E1F0D2C003DECA4 /* EchoServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D38F9C3F1E1F0D2C003DECA4 /* EchoServer.swift */; };
 		D3971E211D89132E001A0B3F /* ssl.key in Resources */ = {isa = PBXBuildFile; fileRef = D3971E201D89132E001A0B3F /* ssl.key */; };
 		D3BFE28C1D87A45D00A648D8 /* ssl.crt in Resources */ = {isa = PBXBuildFile; fileRef = D3BFE28B1D87A45D00A648D8 /* ssl.crt */; };
 		D3D2EA4C1D75FB7F002EF89C /* gRPC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D3D2EA3E1D75FB56002EF89C /* gRPC.framework */; };
@@ -72,8 +73,8 @@
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
-		D30DACEF1DB6FC2D00886B20 /* EchoService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EchoService.swift; sourceTree = "<group>"; };
-		D324A6011D81CF8F00421B59 /* EchoServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EchoServer.swift; sourceTree = "<group>"; };
+		D30DACEF1DB6FC2D00886B20 /* echo.client.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = echo.client.pb.swift; sourceTree = "<group>"; };
+		D324A6011D81CF8F00421B59 /* echo.server.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = echo.server.pb.swift; sourceTree = "<group>"; };
 		D359A6261DBAD11C00FE6282 /* echo.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = echo.pb.swift; path = Protobuf/echo.pb.swift; sourceTree = "<group>"; };
 		D35C9FA81D74B079000443CD /* Echo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Echo.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		D35C9FAB1D74B079000443CD /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@@ -82,6 +83,7 @@
 		D35C9FB21D74B079000443CD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		D35C9FC71D74B0C1000443CD /* EchoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EchoViewController.swift; sourceTree = "<group>"; };
 		D36C3EF81E145A2200BF4EB3 /* SwiftProtobufRuntime.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SwiftProtobufRuntime.xcodeproj; path = "../../../third_party/swift-protobuf/SwiftProtobufRuntime.xcodeproj"; sourceTree = "<group>"; };
+		D38F9C3F1E1F0D2C003DECA4 /* EchoServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EchoServer.swift; sourceTree = "<group>"; };
 		D3971E201D89132E001A0B3F /* ssl.key */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ssl.key; sourceTree = "<group>"; };
 		D3BFE28B1D87A45D00A648D8 /* ssl.crt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ssl.crt; sourceTree = "<group>"; };
 		D3D2EA391D75FB56002EF89C /* gRPC.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = gRPC.xcodeproj; path = ../../../gRPC.xcodeproj; sourceTree = "<group>"; };
@@ -129,15 +131,16 @@
 		D35C9FAA1D74B079000443CD /* Echo */ = {
 			isa = PBXGroup;
 			children = (
-				D3BFE28B1D87A45D00A648D8 /* ssl.crt */,
-				D3971E201D89132E001A0B3F /* ssl.key */,
 				D35C9FAB1D74B079000443CD /* AppDelegate.swift */,
 				D35C9FAD1D74B079000443CD /* Assets.xcassets */,
-				D35C9FAF1D74B079000443CD /* MainMenu.xib */,
-				D35C9FB21D74B079000443CD /* Info.plist */,
+				D30DACEF1DB6FC2D00886B20 /* echo.client.pb.swift */,
+				D324A6011D81CF8F00421B59 /* echo.server.pb.swift */,
+				D38F9C3F1E1F0D2C003DECA4 /* EchoServer.swift */,
 				D35C9FC71D74B0C1000443CD /* EchoViewController.swift */,
-				D324A6011D81CF8F00421B59 /* EchoServer.swift */,
-				D30DACEF1DB6FC2D00886B20 /* EchoService.swift */,
+				D35C9FB21D74B079000443CD /* Info.plist */,
+				D35C9FAF1D74B079000443CD /* MainMenu.xib */,
+				D3BFE28B1D87A45D00A648D8 /* ssl.crt */,
+				D3971E201D89132E001A0B3F /* ssl.key */,
 			);
 			path = Echo;
 			sourceTree = "<group>";
@@ -285,9 +288,10 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				D30DACF01DB6FC2D00886B20 /* EchoService.swift in Sources */,
-				D324A6021D81CF8F00421B59 /* EchoServer.swift in Sources */,
+				D30DACF01DB6FC2D00886B20 /* echo.client.pb.swift in Sources */,
+				D324A6021D81CF8F00421B59 /* echo.server.pb.swift in Sources */,
 				D35C9FC81D74B0C1000443CD /* EchoViewController.swift in Sources */,
+				D38F9C401E1F0D2C003DECA4 /* EchoServer.swift in Sources */,
 				D359A6271DBAD11C00FE6282 /* echo.pb.swift in Sources */,
 				D35C9FAC1D74B079000443CD /* AppDelegate.swift in Sources */,
 			);

+ 3 - 3
Examples/Echo/Swift/Echo/Base.lproj/MainMenu.xib

@@ -1,8 +1,9 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11201" systemVersion="15G1004" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="15G1212" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
     <dependencies>
         <deployment identifier="macosx"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11201"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <objects>
         <customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
@@ -219,7 +220,6 @@
                 <outlet property="callSelectButton" destination="Xjz-PB-FD9" id="hac-kZ-WIN"/>
                 <outlet property="closeButton" destination="lTw-do-2ef" id="gLi-Sn-tTw"/>
                 <outlet property="messageField" destination="DcE-8I-pH3" id="G2X-oh-frG"/>
-                <outlet property="outputField" destination="EyU-Iq-sai" id="9O7-AA-RS0"/>
                 <outlet property="receivedOutputField" destination="EyU-Iq-sai" id="39V-wQ-Rfw"/>
                 <outlet property="sentOutputField" destination="pDG-mY-8Lh" id="JCm-KC-T92"/>
                 <outlet property="view" destination="EiT-Mj-1SZ" id="HXg-ep-0aP"/>

+ 11 - 295
Examples/Echo/Swift/Echo/EchoServer.swift

@@ -30,286 +30,8 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-import Foundation
-import gRPC
-import Darwin // for sleep()
-
-enum ServerError : Error {
-  case endOfStream
-  case error
-}
-
-protocol CustomEchoServer {
-  func Get(request : Echo_EchoRequest) throws -> Echo_EchoResponse
-  func Collect(stream : EchoCollectSession) throws -> Void
-  func Expand(request : Echo_EchoRequest, stream : EchoExpandSession) throws -> Void
-  func Update(stream : EchoUpdateSession) throws -> Void
-}
-
-// This seemed like a nice idea but doesn't work because
-// specific message types are in the protocol signatures.
-// There are also functions in the Session classes that depend
-// on specific message types.
-
-protocol ServerStreamingServer {
-  func handle(session:EchoExpandSession, message:Echo_EchoRequest) -> Void
-}
-
-protocol ClientStreamingServer {
-  func handle(session:EchoCollectSession, message:Echo_EchoRequest) -> Void
-  func close(session:EchoCollectSession)
-}
-
-protocol BidiStreamingServer {
-  func handle(session:EchoUpdateSession, message:Echo_EchoRequest) -> Void
-}
-
-// unary
-class EchoGetSession : Session {
-  var handler : Handler
-  var server : CustomEchoServer
-
-  init(handler:Handler, server: CustomEchoServer) {
-    self.handler = handler
-    self.server = server
-  }
-
-  func run() {
-    do {
-      try handler.receiveMessage(initialMetadata:Metadata()) {(requestData) in
-        if let requestData = requestData {
-          let requestMessage = try! Echo_EchoRequest(protobuf:requestData)
-          let replyMessage = try! self.server.Get(request:requestMessage)
-          // calling stub
-          try self.handler.sendResponse(message:replyMessage.serializeProtobuf(),
-                                        statusCode: 0,
-                                        statusMessage: "OK",
-                                        trailingMetadata:Metadata())
-
-        }
-      }
-    } catch (let callError) {
-      print("grpc error: \(callError)")
-    }
-  }
-}
-
-// server streaming
-class EchoExpandSession : Session {
-  var handler : Handler
-  var server : CustomEchoServer
-
-  init(handler:Handler, server: CustomEchoServer) {
-    self.handler = handler
-    self.server = server
-  }
-
-  func Send(_ response: Echo_EchoResponse) throws {
-    try! handler.sendResponse(message:response.serializeProtobuf()) {}
-  }
-
-  func run() {
-    do {
-      try handler.receiveMessage(initialMetadata:Metadata()) {(requestData) in
-        if let requestData = requestData {
-          let requestMessage = try! Echo_EchoRequest(protobuf:requestData)
-          try self.server.Expand(request:requestMessage, stream: self)
-          try! self.handler.sendStatus(statusCode:0,
-                                       statusMessage:"OK",
-                                       trailingMetadata:Metadata(),
-                                       completion:{})
-        }
-      }
-    } catch (let callError) {
-      print("grpc error: \(callError)")
-    }
-  }
-}
-
-// client streaming
-class EchoCollectSession : Session {
-  var handler : Handler
-  var server : CustomEchoServer
-
-  init(handler:Handler, server: CustomEchoServer) {
-    self.handler = handler
-    self.server = server
-  }
-
-  func Recv() throws -> Echo_EchoRequest {
-    print("collect awaiting message")
-    let done = NSCondition()
-    var requestMessage : Echo_EchoRequest?
-    try self.handler.receiveMessage() {(requestData) in
-      print("collect received message")
-      if let requestData = requestData {
-        requestMessage = try! Echo_EchoRequest(protobuf:requestData)
-      }
-      done.lock()
-      done.signal()
-      done.unlock()
-    }
-    done.lock()
-    done.wait()
-    done.unlock()
-    if requestMessage == nil {
-      throw ServerError.endOfStream
-    }
-    return requestMessage!
-  }
-
-  func SendAndClose(_ response: Echo_EchoResponse) throws {
-    try! self.handler.sendResponse(message:response.serializeProtobuf(),
-                                   statusCode: 0,
-                                   statusMessage: "OK",
-                                   trailingMetadata: Metadata())
-  }
-
-  func sendMessage(message:Echo_EchoResponse) -> Void {
-    try! self.handler.sendResponse(message:message.serializeProtobuf(),
-                                   statusCode: 0,
-                                   statusMessage: "OK",
-                                   trailingMetadata: Metadata())
-  }
-
-  func run() {
-    do {
-      print("EchoCollectSession run")
-      try self.handler.sendMetadata(initialMetadata:Metadata()) {
-        try self.server.Collect(stream:self)
-      }
-    } catch (let callError) {
-      print("grpc error: \(callError)")
-    }
-  }
-}
-
-// fully streaming
-class EchoUpdateSession : Session {
-  var handler : Handler
-  var server : CustomEchoServer
-
-  init(handler:Handler, server: CustomEchoServer) {
-    self.handler = handler
-    self.server = server
-  }
-
-  func Recv() throws -> Echo_EchoRequest {
-    print("update awaiting message")
-    let done = NSCondition()
-    var requestMessage : Echo_EchoRequest?
-    try self.handler.receiveMessage() {(requestData) in
-      print("update received message")
-      if let requestData = requestData {
-        requestMessage = try! Echo_EchoRequest(protobuf:requestData)
-      }
-      done.lock()
-      done.signal()
-      done.unlock()
-    }
-    done.lock()
-    done.wait()
-    done.unlock()
-    if requestMessage == nil {
-      throw ServerError.endOfStream
-    }
-    return requestMessage!
-  }
-
-  func Send(_ response: Echo_EchoResponse) throws {
-    try handler.sendResponse(message:response.serializeProtobuf()) {}
-  }
-
-  func sendMessage(message:Echo_EchoResponse) -> Void {
-    try! handler.sendResponse(message:message.serializeProtobuf()) {}
-  }
-
-  func Close() {
-    let done = NSCondition()
-
-    try! self.handler.sendStatus(statusCode: 0,
-                                 statusMessage: "OK",
-                                 trailingMetadata: Metadata()) {
-                                  done.lock()
-                                  done.signal()
-                                  done.unlock()
-    }
 
-    done.lock()
-    done.wait()
-    done.unlock()
-  }
-
-  func run() {
-    do {
-      try self.handler.sendMetadata(initialMetadata:Metadata()) {
-        try self.server.Update(stream:self)
-      }
-    } catch (let callError) {
-      print("grpc error: \(callError)")
-    }
-  }
-}
-
-class EchoServer {
-  private var address: String
-  private var server: Server
-
-  public var myServer: MyEchoServer!
-
-  init(address:String, secure:Bool) {
-    gRPC.initialize()
-    self.address = address
-    if secure {
-      let certificateURL = Bundle.main.url(forResource: "ssl", withExtension: "crt")!
-
-      let certificate = try! String(contentsOf: certificateURL)
-      let keyURL = Bundle.main.url(forResource: "ssl", withExtension: "key")!
-      let key = try! String(contentsOf: keyURL)
-      self.server = gRPC.Server(address:address, key:key, certs:certificate)
-    } else {
-      self.server = gRPC.Server(address:address)
-    }
-    self.myServer = MyEchoServer()
-  }
-
-  func start() {
-    print("Server Starting")
-    print("GRPC version " + gRPC.version())
-
-    server.run {(handler) in
-
-      print("Server received request to " + handler.host
-        + " calling " + handler.method
-        + " from " + handler.caller)
-
-      if (handler.method == "/echo.Echo/Get") {
-        handler.session = EchoGetSession(handler:handler,
-                                         server:self.myServer)
-        handler.session.run()
-      }
-
-      else if (handler.method == "/echo.Echo/Expand") {
-        handler.session = EchoExpandSession(handler:handler,
-                                            server:self.myServer)
-        handler.session.run()
-      }
-
-      else if (handler.method == "/echo.Echo/Collect") {
-        handler.session = EchoCollectSession(handler:handler,
-                                             server:self.myServer)
-
-        handler.session.run()
-      }
-
-      else if (handler.method == "/echo.Echo/Update") {
-        handler.session = EchoUpdateSession(handler:handler,
-                                            server:self.myServer)
-        handler.session.run()
-      }
-    }
-  }
-}
+import Foundation
 
 // The following code is for developer/users to edit.
 // Everything above these lines is intended to be preexisting or generated.
@@ -317,29 +39,25 @@ class EchoServer {
 class MyEchoServer : CustomEchoServer {
 
   func Get(request : Echo_EchoRequest) throws -> Echo_EchoResponse {
-    print("Get received: \(request.text)")
     return Echo_EchoResponse(text:"Swift echo get: " + request.text)
   }
 
-  func Expand(request : Echo_EchoRequest, stream : EchoExpandSession) throws -> Void {
-    print("Expand received: \(request.text)")
+  func Expand(request : Echo_EchoRequest, session : EchoExpandSession) throws -> Void {
     let parts = request.text.components(separatedBy: " ")
     var i = 0
     for part in parts {
-      try stream.Send(Echo_EchoResponse(text:"Swift echo expand (\(i)): \(part)"))
+      try! session.Send(Echo_EchoResponse(text:"Swift echo expand (\(i)): \(part)"))
       i += 1
       sleep(1)
     }
   }
 
-  func Collect(stream : EchoCollectSession) throws -> Void {
+  func Collect(session : EchoCollectSession) throws -> Void {
     DispatchQueue.global().async {
-      print("Called collect")
       var parts : [String] = []
       while true {
         do {
-          let request = try stream.Recv()
-          print("Collect received: \(request.text)")
+          let request = try session.Recv()
           parts.append(request.text)
         } catch ServerError.endOfStream {
           break
@@ -347,28 +65,26 @@ class MyEchoServer : CustomEchoServer {
           print("\(error)")
         }
       }
-      print("sending collect response")
       let response = Echo_EchoResponse(text:"Swift echo collect: " + parts.joined(separator: " "))
-      try! stream.SendAndClose(response)
+      try! session.SendAndClose(response)
     }
   }
 
-  func Update(stream : EchoUpdateSession) throws -> Void {
+  func Update(session : EchoUpdateSession) throws -> Void {
     DispatchQueue.global().async {
       var count = 0
       while true {
         do {
-          let request = try stream.Recv()
-          print("Update received: \(request.text)")
+          let request = try session.Recv()
           count += 1
-          try stream.Send(Echo_EchoResponse(text:"Swift echo update (\(count)): \(request.text)"))
+          try session.Send(Echo_EchoResponse(text:"Swift echo update (\(count)): \(request.text)"))
         } catch ServerError.endOfStream {
           break
         } catch (let error) {
-          
+          print("\(error)")
         }
       }
-      stream.Close()
+      session.Close()
     }
   }
 }

+ 1 - 15
Examples/Echo/Swift/Echo/EchoViewController.swift

@@ -143,6 +143,7 @@ class EchoViewController : NSViewController, NSTextFieldDelegate {
         var requestMessage = Echo_EchoRequest()
         requestMessage.text = self.messageField.stringValue
 
+        // service.get() is a blocking call
         DispatchQueue.global().async {
           let result = service.get(requestMessage)
           switch result {
@@ -227,21 +228,6 @@ class EchoViewController : NSViewController, NSTextFieldDelegate {
     }
   }
 
-  func receiveCollectMessage() throws -> Void {
-    guard let collectCall = collectCall else {
-      return
-    }
-    try collectCall.receiveMessage() {(responseMessage) in
-      if let responseMessage = responseMessage {
-        self.displayMessageReceived(responseMessage.text)
-      } else {
-        print("collect closed")
-        self.nowStreaming = false
-        self.closeButton.isEnabled = false
-      }
-    }
-  }
-
   func sendUpdateMessage() {
     if let updateCall = updateCall {
       var requestMessage = Echo_EchoRequest()

+ 54 - 26
Examples/Echo/Swift/Echo/EchoService.swift → Examples/Echo/Swift/Echo/echo.client.pb.swift

@@ -30,29 +30,33 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-import Foundation
-import gRPC
 
 // all code that follows is to-be-generated
 
-enum EchoResult {
+import Foundation
+import gRPC
+
+public enum EchoResult {
   case Response(r: Echo_EchoResponse)
   // these last two should be merged
   case CallResult(c: CallResult)
   case Error(s: String)
 }
 
+//
+// Unary GET
+//
 public class EchoGetCall {
   var call : Call
 
-  init(_ channel: Channel) {
+  fileprivate init(_ channel: Channel) {
     self.call = channel.makeCall("/echo.Echo/Get")
   }
 
   // Call this with the message to send,
   // the callback will be called after the request is received.
-  func perform(request: Echo_EchoRequest,
-               callback:@escaping (EchoResult) -> Void)
+  fileprivate func perform(request: Echo_EchoRequest,
+                           callback:@escaping (EchoResult) -> Void)
     -> Void {
       let requestMessageData = try! request.serializeProtobuf()
       let requestMetadata = Metadata()
@@ -70,17 +74,20 @@ public class EchoGetCall {
   }
 }
 
+//
+// Server-streaming EXPAND
+//
 public class EchoExpandCall {
   var call : Call
 
-  init(_ channel: Channel) {
+  fileprivate init(_ channel: Channel) {
     self.call = channel.makeCall("/echo.Echo/Expand")
   }
 
   // Call this once with the message to send,
   // the callback will be called after the request is initiated.
-  func perform(request: Echo_EchoRequest,
-               callback:@escaping (CallResult) -> Void)
+  fileprivate func perform(request: Echo_EchoRequest,
+                           callback:@escaping (CallResult) -> Void)
     -> Void {
       let requestMessageData = try! request.serializeProtobuf()
       let requestMetadata = Metadata()
@@ -91,7 +98,9 @@ public class EchoExpandCall {
       }
   }
 
-  func Recv() -> EchoResult {
+  // Call this to wait for a result.
+  // BLOCKING
+  public func Recv() -> EchoResult {
     let done = NSCondition()
     var result : EchoResult!
     try! call.receiveMessage() {(data) in
@@ -115,25 +124,30 @@ public class EchoExpandCall {
   }
 }
 
+//
+// Client-streaming COLLECT
+//
 public class EchoCollectCall {
   var call : Call
 
-  init(_ channel: Channel) {
+  fileprivate init(_ channel: Channel) {
     self.call = channel.makeCall("/echo.Echo/Collect")
   }
 
   // Call this to start a call.
-  func start(metadata:Metadata, completion:@escaping (() -> Void)) throws {
+  fileprivate func start(metadata:Metadata, completion:@escaping (() -> Void)) throws {
     try self.call.start(metadata: metadata, completion:completion)
   }
 
   // Call this to send each message in the request stream.
-  func Send(_ message: Echo_EchoRequest) {
+  public func Send(_ message: Echo_EchoRequest) {
     let messageData = try! message.serializeProtobuf()
     _ = call.sendMessage(data:messageData)
   }
 
-  func CloseAndRecv() -> EchoResult {
+  // Call this to close the connection and wait for a response.
+  // BLOCKING
+  public func CloseAndRecv() -> EchoResult {
     let done = NSCondition()
     var result : EchoResult!
 
@@ -169,7 +183,7 @@ public class EchoCollectCall {
   // Call this to receive a message.
   // The callback will be called when a message is received.
   // call this again from the callback to wait for another message.
-  func receiveMessage(callback:@escaping (Echo_EchoResponse?) throws -> Void)
+  fileprivate func receiveMessage(callback:@escaping (Echo_EchoResponse?) throws -> Void)
     throws {
       try call.receiveMessage() {(data) in
         guard let data = data else {
@@ -187,18 +201,21 @@ public class EchoCollectCall {
 
 }
 
+//
+// Bidirectional-streaming UPDATE
+//
 public class EchoUpdateCall {
   var call : Call
 
-  init(_ channel: Channel) {
+  fileprivate init(_ channel: Channel) {
     self.call = channel.makeCall("/echo.Echo/Update")
   }
 
-  func start(metadata:Metadata, completion:@escaping (() -> Void)) throws {
+  fileprivate func start(metadata:Metadata, completion:@escaping (() -> Void)) throws {
     try self.call.start(metadata: metadata, completion:completion)
   }
 
-  func receiveMessage(callback:@escaping (Echo_EchoResponse?) throws -> Void) throws {
+  fileprivate func receiveMessage(callback:@escaping (Echo_EchoResponse?) throws -> Void) throws {
     try call.receiveMessage() {(data) in
       if let data = data {
         if let responseMessage = try? Echo_EchoResponse(protobuf:data) {
@@ -212,7 +229,7 @@ public class EchoUpdateCall {
     }
   }
 
-  func Recv() -> EchoResult {
+  public func Recv() -> EchoResult {
     let done = NSCondition()
     var result : EchoResult!
     try! self.receiveMessage() {responseMessage in
@@ -231,12 +248,12 @@ public class EchoUpdateCall {
     return result
   }
 
-  func Send(message:Echo_EchoRequest) {
+  public func Send(message:Echo_EchoRequest) {
     let messageData = try! message.serializeProtobuf()
     _ = call.sendMessage(data:messageData)
   }
 
-  func CloseSend() {
+  public func CloseSend() {
     let done = NSCondition()
     try! call.close() {
       done.lock()
@@ -249,6 +266,8 @@ public class EchoUpdateCall {
   }
 }
 
+// The generated service adaptor
+// Call these methods to make API calls
 public class EchoService {
   public var channel: Channel
 
@@ -260,9 +279,9 @@ public class EchoService {
     channel = Channel(address:address, certificates:certificates, host:host)
   }
 
-  func get(_ requestMessage: Echo_EchoRequest) -> EchoResult {
+  // Synchronous. Unary.
+  public func get(_ requestMessage: Echo_EchoRequest) -> EchoResult {
     let call = EchoGetCall(channel)
-
     let done = NSCondition()
     var finalResult : EchoResult!
     call.perform(request:requestMessage) {(result) in
@@ -277,19 +296,28 @@ public class EchoService {
     return finalResult
   }
 
-  func expand(_ requestMessage: Echo_EchoRequest) -> EchoExpandCall {
+  // Asynchronous. Server-streaming.
+  // Send the initial message.
+  // Use methods on the returned object to get streamed responses.
+  public func expand(_ requestMessage: Echo_EchoRequest) -> EchoExpandCall {
     let call = EchoExpandCall(channel)
     call.perform(request:requestMessage) {response in }
     return call
   }
 
-  func collect() -> EchoCollectCall {
+  // Asynchronous. Client-streaming.
+  // Use methods on the returned object to stream messages and
+  // to close the connection and wait for a final response.
+  public func collect() -> EchoCollectCall {
     let call = EchoCollectCall(channel)
     try! call.start(metadata:Metadata(), completion:{})
     return call
   }
 
-  func update() -> EchoUpdateCall {
+  // Asynchronous. Bidirectional-streaming.
+  // Use methods on the returned object to stream messages,
+  // to wait for replies, and to close the connection.
+  public func update() -> EchoUpdateCall {
     let call = EchoUpdateCall(channel)
     try! call.start(metadata:Metadata(), completion:{})
     return call

+ 300 - 0
Examples/Echo/Swift/Echo/echo.server.pb.swift

@@ -0,0 +1,300 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+// all code that follows is to-be-generated
+
+import Foundation
+import gRPC
+import Darwin // for sleep()
+
+enum ServerError : Error {
+  case endOfStream
+}
+
+protocol CustomEchoServer {
+  func Get(request : Echo_EchoRequest) throws -> Echo_EchoResponse
+  func Collect(session : EchoCollectSession) throws -> Void
+  func Expand(request : Echo_EchoRequest, session : EchoExpandSession) throws -> Void
+  func Update(session : EchoUpdateSession) throws -> Void
+}
+
+// unary
+class EchoGetSession : Session {
+  var handler : Handler
+  var server : CustomEchoServer
+
+  init(handler:Handler, server: CustomEchoServer) {
+    self.handler = handler
+    self.server = server
+  }
+
+  func run() {
+    do {
+      try handler.receiveMessage(initialMetadata:Metadata()) {(requestData) in
+        if let requestData = requestData {
+          let requestMessage = try! Echo_EchoRequest(protobuf:requestData)
+          let replyMessage = try! self.server.Get(request:requestMessage)
+          // calling stub
+          try self.handler.sendResponse(message:replyMessage.serializeProtobuf(),
+                                        statusCode: 0,
+                                        statusMessage: "OK",
+                                        trailingMetadata:Metadata())
+
+        }
+      }
+    } catch (let callError) {
+      print("grpc error: \(callError)")
+    }
+  }
+}
+
+// server streaming
+class EchoExpandSession : Session {
+  var handler : Handler
+  var server : CustomEchoServer
+
+  init(handler:Handler, server: CustomEchoServer) {
+    self.handler = handler
+    self.server = server
+  }
+
+  func Send(_ response: Echo_EchoResponse) throws {
+    try! handler.sendResponse(message:response.serializeProtobuf()) {}
+  }
+
+  func run() {
+    do {
+      try self.handler.receiveMessage(initialMetadata:Metadata()) {(requestData) in
+        if let requestData = requestData {
+          let requestMessage = try! Echo_EchoRequest(protobuf:requestData)
+          try self.server.Expand(request:requestMessage, session: self)
+          try! self.handler.sendStatus(statusCode:0,
+                                       statusMessage:"OK",
+                                       trailingMetadata:Metadata(),
+                                       completion:{})
+        }
+      }
+    } catch (let callError) {
+      print("grpc error: \(callError)")
+    }
+  }
+}
+
+// client streaming
+class EchoCollectSession : Session {
+  var handler : Handler
+  var server : CustomEchoServer
+
+  init(handler:Handler, server: CustomEchoServer) {
+    self.handler = handler
+    self.server = server
+  }
+
+  func Recv() throws -> Echo_EchoRequest {
+    print("collect awaiting message")
+    let done = NSCondition()
+    var requestMessage : Echo_EchoRequest?
+    try self.handler.receiveMessage() {(requestData) in
+      print("collect received message")
+      if let requestData = requestData {
+        requestMessage = try! Echo_EchoRequest(protobuf:requestData)
+      }
+      done.lock()
+      done.signal()
+      done.unlock()
+    }
+    done.lock()
+    done.wait()
+    done.unlock()
+    if requestMessage == nil {
+      throw ServerError.endOfStream
+    }
+    return requestMessage!
+  }
+
+  func SendAndClose(_ response: Echo_EchoResponse) throws {
+    try! self.handler.sendResponse(message:response.serializeProtobuf(),
+                                   statusCode: 0,
+                                   statusMessage: "OK",
+                                   trailingMetadata: Metadata())
+  }
+
+  func sendMessage(message:Echo_EchoResponse) -> Void {
+    try! self.handler.sendResponse(message:message.serializeProtobuf(),
+                                   statusCode: 0,
+                                   statusMessage: "OK",
+                                   trailingMetadata: Metadata())
+  }
+
+  func run() {
+    do {
+      print("EchoCollectSession run")
+      try self.handler.sendMetadata(initialMetadata:Metadata()) {
+        try self.server.Collect(session:self)
+      }
+    } catch (let callError) {
+      print("grpc error: \(callError)")
+    }
+  }
+}
+
+// fully streaming
+class EchoUpdateSession : Session {
+  var handler : Handler
+  var server : CustomEchoServer
+
+  init(handler:Handler, server: CustomEchoServer) {
+    self.handler = handler
+    self.server = server
+  }
+
+  func Recv() throws -> Echo_EchoRequest {
+    print("update awaiting message")
+    let done = NSCondition()
+    var requestMessage : Echo_EchoRequest?
+    try self.handler.receiveMessage() {(requestData) in
+      print("update received message")
+      if let requestData = requestData {
+        requestMessage = try! Echo_EchoRequest(protobuf:requestData)
+      }
+      done.lock()
+      done.signal()
+      done.unlock()
+    }
+    done.lock()
+    done.wait()
+    done.unlock()
+    if requestMessage == nil {
+      throw ServerError.endOfStream
+    }
+    return requestMessage!
+  }
+
+  func Send(_ response: Echo_EchoResponse) throws {
+    try handler.sendResponse(message:response.serializeProtobuf()) {}
+  }
+
+  func sendMessage(message:Echo_EchoResponse) -> Void {
+    try! handler.sendResponse(message:message.serializeProtobuf()) {}
+  }
+
+  func Close() {
+    let done = NSCondition()
+
+    try! self.handler.sendStatus(statusCode: 0,
+                                 statusMessage: "OK",
+                                 trailingMetadata: Metadata()) {
+                                  done.lock()
+                                  done.signal()
+                                  done.unlock()
+    }
+
+    done.lock()
+    done.wait()
+    done.unlock()
+  }
+
+  func run() {
+    do {
+      try self.handler.sendMetadata(initialMetadata:Metadata()) {
+        try self.server.Update(session:self)
+      }
+    } catch (let callError) {
+      print("grpc error: \(callError)")
+    }
+  }
+}
+
+class EchoServer {
+  private var address: String
+  private var server: Server
+
+  public var myServer: MyEchoServer!
+
+  init(address:String, secure:Bool) {
+    gRPC.initialize()
+    self.address = address
+    if secure {
+      let certificateURL = Bundle.main.url(forResource: "ssl", withExtension: "crt")!
+
+      let certificate = try! String(contentsOf: certificateURL)
+      let keyURL = Bundle.main.url(forResource: "ssl", withExtension: "key")!
+      let key = try! String(contentsOf: keyURL)
+      self.server = gRPC.Server(address:address, key:key, certs:certificate)
+    } else {
+      self.server = gRPC.Server(address:address)
+    }
+    self.myServer = MyEchoServer()
+  }
+
+  func start() {
+    print("Server Starting")
+    print("GRPC version " + gRPC.version())
+
+    server.run {(handler) in
+
+      print("Server received request to " + handler.host
+        + " calling " + handler.method
+        + " from " + handler.caller)
+
+      // to keep handlers from blocking the server thread,
+      // we dispatch them to another queue.
+      DispatchQueue.global().async {
+        if (handler.method == "/echo.Echo/Get") {
+          handler.session = EchoGetSession(handler:handler,
+                                           server:self.myServer)
+          handler.session.run()
+        }
+
+        else if (handler.method == "/echo.Echo/Expand") {
+          handler.session = EchoExpandSession(handler:handler,
+                                              server:self.myServer)
+          handler.session.run()
+        }
+
+        else if (handler.method == "/echo.Echo/Collect") {
+          handler.session = EchoCollectSession(handler:handler,
+                                               server:self.myServer)
+          handler.session.run()
+        }
+
+        else if (handler.method == "/echo.Echo/Update") {
+          handler.session = EchoUpdateSession(handler:handler,
+                                              server:self.myServer)
+          handler.session.run()
+        }
+      }
+    }
+  }
+}
+