Browse Source

Simplified call interface for clients.

Tim Burks 9 years ago
parent
commit
3d0d77a9fe

+ 14 - 10
Examples/Echo/Swift/Generated/echo.client.pb.swift

@@ -64,8 +64,9 @@ public class Echo_EchoGetCall {
     var callResult : CallResult!
     var responseMessage : Echo_EchoResponse?
     let requestMessageData = try request.serializeProtobuf()
-    try call.perform(message: requestMessageData,
-                     metadata: metadata)
+    try call.start(.unary,
+                   metadata:metadata,
+                   message:requestMessageData)
     {(_callResult) in
       callResult = _callResult
       if let messageData = callResult.resultData {
@@ -98,8 +99,9 @@ public class Echo_EchoExpandCall {
   // Call this once with the message to send.
   fileprivate func run(request: Echo_EchoRequest, metadata: Metadata) throws -> Echo_EchoExpandCall {
     let requestMessageData = try request.serializeProtobuf()
-    try call.startServerStreaming(message: requestMessageData,
-                                  metadata: metadata)
+    try call.start(.serverStreaming,
+                   metadata:metadata,
+                   message:requestMessageData)
     {_ in}
     return self
   }
@@ -145,7 +147,8 @@ public class Echo_EchoCollectCall {
 
   // Call this to start a call.
   fileprivate func run(metadata:Metadata) throws -> Echo_EchoCollectCall {
-    try self.call.start(metadata: metadata)
+    try self.call.start(.clientStreaming,
+                        metadata:metadata)
     {_ in}
     return self
   }
@@ -220,7 +223,8 @@ public class Echo_EchoUpdateCall {
   }
 
   fileprivate func run(metadata:Metadata) throws -> Echo_EchoUpdateCall {
-    try self.call.start(metadata: metadata)
+    try self.call.start(.bidiStreaming,
+                        metadata:metadata)
     {_ in}
     return self
   }
@@ -307,24 +311,24 @@ public class Echo_EchoService {
 
   // Synchronous. Unary.
   public func get(_ request: Echo_EchoRequest) throws -> Echo_EchoResponse {
-    return try Echo_EchoGetCall(channel).run(request:request, metadata:metadata.copy() as! Metadata)
+    return try Echo_EchoGetCall(channel).run(request:request, metadata:metadata)
   }
   // Asynchronous. Server-streaming.
   // Send the initial message.
   // Use methods on the returned object to get streamed responses.
   public func expand(_ request: Echo_EchoRequest) throws -> Echo_EchoExpandCall {
-    return try Echo_EchoExpandCall(channel).run(request:request, metadata:metadata.copy() as! Metadata)
+    return try Echo_EchoExpandCall(channel).run(request:request, metadata:metadata)
   }
   // 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() throws -> Echo_EchoCollectCall {
-    return try Echo_EchoCollectCall(channel).run(metadata:metadata.copy() as! Metadata)
+    return try Echo_EchoCollectCall(channel).run(metadata:metadata)
   }
   // Asynchronous. Bidirectional-streaming.
   // Use methods on the returned object to stream messages,
   // to wait for replies, and to close the connection.
   public func update() throws -> Echo_EchoUpdateCall {
-    return try Echo_EchoUpdateCall(channel).run(metadata:metadata.copy() as! Metadata)
+    return try Echo_EchoUpdateCall(channel).run(metadata:metadata)
   }
 }

+ 3 - 2
Examples/Sessions/Sessions/Document.swift

@@ -172,8 +172,9 @@ class Document: NSDocument {
                                  ["z": "zither"]])
 
         do {
-          try call.perform(message: messageData!,
-                           metadata: metadata)
+          try call.start(.unary,
+                         metadata:metadata,
+                         message:messageData)
           {(callResult) in
 
             if let initialMetadata = callResult.initialMetadata {

+ 2 - 1
Plugin/swiftgrpc.templates/client-call-bidistreaming.swift

@@ -8,7 +8,8 @@ public class {{ .|call:protoFile,service,method }} {
   }
 
   fileprivate func run(metadata:Metadata) throws -> {{ .|call:protoFile,service,method }} {
-    try self.call.start(metadata: metadata)
+    try self.call.start(.bidiStreaming,
+                        metadata:metadata)
     {_ in}
     return self
   }

+ 2 - 1
Plugin/swiftgrpc.templates/client-call-clientstreaming.swift

@@ -9,7 +9,8 @@ public class {{ .|call:protoFile,service,method }} {
 
   // Call this to start a call.
   fileprivate func run(metadata:Metadata) throws -> {{ .|call:protoFile,service,method }} {
-    try self.call.start(metadata: metadata)
+    try self.call.start(.clientStreaming,
+                        metadata:metadata)
     {_ in}
     return self
   }

+ 3 - 2
Plugin/swiftgrpc.templates/client-call-serverstreaming.swift

@@ -10,8 +10,9 @@ public class {{ .|call:protoFile,service,method }} {
   // Call this once with the message to send.
   fileprivate func run(request: {{ method|input }}, metadata: Metadata) throws -> {{ .|call:protoFile,service,method }} {
     let requestMessageData = try request.serializeProtobuf()
-    try call.startServerStreaming(message: requestMessageData,
-                                  metadata: metadata)
+    try call.start(.serverStreaming,
+                   metadata:metadata,
+                   message:requestMessageData)
     {_ in}
     return self
   }

+ 3 - 2
Plugin/swiftgrpc.templates/client-call-unary.swift

@@ -14,8 +14,9 @@ public class {{ .|call:protoFile,service,method }} {
     var callResult : CallResult!
     var responseMessage : {{ method|output }}?
     let requestMessageData = try request.serializeProtobuf()
-    try call.perform(message: requestMessageData,
-                     metadata: metadata)
+    try call.start(.unary,
+                   metadata:metadata,
+                   message:requestMessageData)
     {(_callResult) in
       callResult = _callResult
       if let messageData = callResult.resultData {

+ 4 - 4
Plugin/swiftgrpc.templates/client.pb.swift

@@ -101,7 +101,7 @@ public class {{ protoFile.package|capitalize }}_{{ service.name }}Service {
   //-{% if not method.clientStreaming and not method.serverStreaming %}
   // Synchronous. Unary.
   public func {{ method.name|lowercase }}(_ request: {{ method|input }}) throws -> {{ method|output }} {
-    return try {{ .|call:protoFile,service,method }}(channel).run(request:request, metadata:metadata.copy() as! Metadata)
+    return try {{ .|call:protoFile,service,method }}(channel).run(request:request, metadata:metadata)
   }
   //-{% endif %}
   //-{% if not method.clientStreaming and method.serverStreaming %}
@@ -109,7 +109,7 @@ public class {{ protoFile.package|capitalize }}_{{ service.name }}Service {
   // Send the initial message.
   // Use methods on the returned object to get streamed responses.
   public func {{ method.name|lowercase }}(_ request: {{ method|input }}) throws -> {{ .|call:protoFile,service,method }} {
-    return try {{ .|call:protoFile,service,method }}(channel).run(request:request, metadata:metadata.copy() as! Metadata)
+    return try {{ .|call:protoFile,service,method }}(channel).run(request:request, metadata:metadata)
   }
   //-{% endif %}
   //-{% if method.clientStreaming and not method.serverStreaming %}
@@ -117,7 +117,7 @@ public class {{ protoFile.package|capitalize }}_{{ service.name }}Service {
   // Use methods on the returned object to stream messages and
   // to close the connection and wait for a final response.
   public func {{ method.name|lowercase }}() throws -> {{ .|call:protoFile,service,method }} {
-    return try {{ .|call:protoFile,service,method }}(channel).run(metadata:metadata.copy() as! Metadata)
+    return try {{ .|call:protoFile,service,method }}(channel).run(metadata:metadata)
   }
   //-{% endif %}
   //-{% if method.clientStreaming and method.serverStreaming %}
@@ -125,7 +125,7 @@ public class {{ protoFile.package|capitalize }}_{{ service.name }}Service {
   // Use methods on the returned object to stream messages,
   // to wait for replies, and to close the connection.
   public func {{ method.name|lowercase }}() throws -> {{ .|call:protoFile,service,method }} {
-    return try {{ .|call:protoFile,service,method }}(channel).run(metadata:metadata.copy() as! Metadata)
+    return try {{ .|call:protoFile,service,method }}(channel).run(metadata:metadata)
   }
   //-{% endif %}
   //-{% endfor %}

+ 69 - 107
Sources/gRPC/Call.swift

@@ -36,6 +36,13 @@
 #endif
 import Foundation
 
+public enum CallStyle {
+  case unary
+  case serverStreaming
+  case clientStreaming
+  case bidiStreaming
+}
+
 public enum CallError : Error {
   case ok
   case unknown
@@ -97,6 +104,22 @@ public struct CallResult {
   public var resultData : Data?
   public var initialMetadata : Metadata?
   public var trailingMetadata : Metadata?
+
+  fileprivate init(_ op : OperationGroup) {
+    if (op.success) {
+      self.statusCode = op.receivedStatusCode()!
+      self.statusMessage = op.receivedStatusMessage()
+      self.resultData = op.receivedMessage()?.data()
+      self.initialMetadata = op.receivedInitialMetadata()
+      self.trailingMetadata = op.receivedTrailingMetadata()
+    } else {
+      self.statusCode = 0
+      self.statusMessage = nil
+      self.resultData = nil
+      self.initialMetadata = nil
+      self.trailingMetadata = nil
+    }
+  }
 }
 
 /// A gRPC API call
@@ -148,7 +171,7 @@ public class Call {
     }
   }
 
-  /// Initiate performance of a group of operations without waiting for completion
+  /// Initiates performance of a group of operations without waiting for completion.
   ///
   /// - Parameter operations: group of operations to be performed
   /// - Returns: the result of initiating the call
@@ -162,104 +185,49 @@ public class Call {
     }
   }
 
-  /// Performs a nonstreaming gRPC API call
+  /// Starts a gRPC API call.
   ///
-  /// - Parameter message: data containing the message to send
+  /// - Parameter style: the style of call to start
   /// - Parameter metadata: metadata to send with the call
-  /// - Parameter callback: a block to call with a CallResponse object containing call results
-  public func perform(message: Data,
-                      metadata: Metadata,
-                      completion: @escaping (CallResult) -> Void)
+  /// - Parameter message: data containing the message to send (.unary and .serverStreaming only)
+  /// - Parameter callback: a block to call with call results
+  public func start(_ style: CallStyle,
+                    metadata: Metadata,
+                    message: Data? = nil,
+                    completion: @escaping (CallResult) -> Void)
     throws -> Void {
-      let messageBuffer = ByteBuffer(data:message)
-      let operations = OperationGroup(call:self,
-                                      operations:[.sendInitialMetadata(metadata),
-                                                  .receiveInitialMetadata,
-                                                  .receiveStatusOnClient,
-                                                  .sendMessage(messageBuffer),
-                                                  .sendCloseFromClient,
-                                                  .receiveMessage],
-                                      completion:
-        {(operationGroup) in
-          if operationGroup.success {
-            completion(CallResult(statusCode:operationGroup.receivedStatusCode()!,
-                                  statusMessage:operationGroup.receivedStatusMessage(),
-                                  resultData:operationGroup.receivedMessage()?.data(),
-                                  initialMetadata:operationGroup.receivedInitialMetadata(),
-                                  trailingMetadata:operationGroup.receivedTrailingMetadata()))
-          } else {
-            completion(CallResult(statusCode:0,
-                                  statusMessage:nil,
-                                  resultData:nil,
-                                  initialMetadata:nil,
-                                  trailingMetadata:nil))
-          }
-      })
-
-      try self.perform(operations)
-  }
-
-  public func startServerStreaming(message: Data,
-                                   metadata: Metadata,
-                                   completion: @escaping (CallResult) -> Void)
-    throws -> Void {
-      let messageBuffer = ByteBuffer(data:message)
-      let operations = OperationGroup(call:self,
-                                      operations:[.sendInitialMetadata(metadata),
-                                                  .receiveInitialMetadata,
-                                                  .receiveStatusOnClient,
-                                                  .sendMessage(messageBuffer),
-                                                  .sendCloseFromClient,
-                                                  ],
-                                      completion:
-        {(operationGroup) in
-          if operationGroup.success {
-            completion(CallResult(statusCode:operationGroup.receivedStatusCode()!,
-                                  statusMessage:operationGroup.receivedStatusMessage(),
-                                  resultData:nil,
-                                  initialMetadata:operationGroup.receivedInitialMetadata(),
-                                  trailingMetadata:nil))
-          } else {
-            completion(CallResult(statusCode:0,
-                                  statusMessage:nil,
-                                  resultData:nil,
-                                  initialMetadata:nil,
-                                  trailingMetadata:nil))
-          }
-      })
-
-      try self.perform(operations)
-  }
-
-  /// start a streaming connection
-  ///
-  /// Parameter metadata: initial metadata to send
-  public func start(metadata: Metadata,
-                    completion:@escaping (CallResult) -> Void)
-    throws -> Void {
-      let operations = OperationGroup(call:self,
-                                      operations:[.sendInitialMetadata(metadata),
-                                                  .receiveInitialMetadata,
-                                                  .receiveStatusOnClient])
-      {(operationGroup) in
-        if operationGroup.success {
-          completion(CallResult(statusCode:operationGroup.receivedStatusCode()!,
-                                statusMessage:operationGroup.receivedStatusMessage(),
-                                resultData:nil,
-                                initialMetadata:operationGroup.receivedInitialMetadata(),
-                                trailingMetadata:nil))
-        } else {
-          completion(CallResult(statusCode:0,
-                                statusMessage:nil,
-                                resultData:nil,
-                                initialMetadata:nil,
-                                trailingMetadata:nil))
+      var operations : [Operation] = []
+      switch style {
+      case .unary:
+        guard let message = message else {
+          throw CallError.invalidMessage
         }
+        operations = [.sendInitialMetadata(metadata.copy() as! Metadata),
+                      .receiveInitialMetadata,
+                      .receiveStatusOnClient,
+                      .sendMessage(ByteBuffer(data:message)),
+                      .sendCloseFromClient,
+                      .receiveMessage]
+      case .serverStreaming:
+        guard let message = message else {
+          throw CallError.invalidMessage
+        }
+        operations = [.sendInitialMetadata(metadata.copy() as! Metadata),
+                      .receiveInitialMetadata,
+                      .receiveStatusOnClient,
+                      .sendMessage(ByteBuffer(data:message)),
+                      .sendCloseFromClient]
+      case .clientStreaming, .bidiStreaming:
+        operations = [.sendInitialMetadata(metadata.copy() as! Metadata),
+                      .receiveInitialMetadata,
+                      .receiveStatusOnClient]
       }
-      try self.perform(operations)
+      try self.perform(OperationGroup(call:self,
+                                      operations:operations,
+                                      completion:{(op) in completion(CallResult(op))}))
   }
 
-  /// send a message over a streaming connection
+  /// Sends a message over a streaming connection.
   ///
   /// Parameter data: the message data to send
   /// Returns: true if the message could be queued or sent, false if the queue is full
@@ -284,7 +252,7 @@ public class Call {
 
   /// helper for sending queued messages
   private func sendWithoutBlocking(data: Data) throws -> Void {
-    let operations = OperationGroup(call:self,
+    try self.perform(OperationGroup(call:self,
                                     operations:[.sendMessage(ByteBuffer(data:data))])
     {(operationGroup) in
       if operationGroup.success {
@@ -308,14 +276,12 @@ public class Call {
       } else {
         // TODO: if the event failed, shut down
       }
-    }
-    try self.perform(operations)
+    })
   }
 
-  // receive a message over a streaming connection
+  // Receive a message over a streaming connection.
   public func receiveMessage(callback:@escaping ((Data!) throws -> Void)) throws -> Void {
-    let operations = OperationGroup(call:self,
-                                    operations:[.receiveMessage])
+    try self.perform(OperationGroup(call:self, operations:[.receiveMessage])
     {(operationGroup) in
       if operationGroup.success {
         if let messageBuffer = operationGroup.receivedMessage() {
@@ -324,17 +290,13 @@ public class Call {
           try callback(nil) // an empty response signals the end of a connection
         }
       }
-    }
-    try self.perform(operations)
+    })
   }
 
-  // close a streaming connection
+  // Closes a streaming connection.
   public func close(completion:@escaping (() -> Void)) throws -> Void {
-    let operations = OperationGroup(call:self,
-                                    operations:[.sendCloseFromClient])
-    {(operationGroup) in
-      completion()
-    }
-    try self.perform(operations)
+    try self.perform(OperationGroup(call:self, operations:[.sendCloseFromClient])
+    {(operationGroup) in completion()
+    })
   }
 }

+ 1 - 1
Tests/gRPCTests/GRPCTests.swift

@@ -72,7 +72,7 @@ func client() {
       let method = (i < steps-1) ? hello : goodbye
       let call = c.makeCall(method)
       let metadata = Metadata(initialClientMetadata)
-      try call.perform(message: message!, metadata:metadata) {
+      try call.start(.unary, metadata:metadata, message:message) {
         (response) in
         // verify the basic response from the server
         XCTAssertEqual(response.statusCode, statusCode)