Browse Source

Add a runtime support class for unary client calls.

Daniel Alm 8 years ago
parent
commit
6a553c3636

+ 3 - 59
Examples/Echo/Generated/echo.grpc.swift

@@ -33,66 +33,10 @@ internal enum Echo_EchoClientError : Error {
   case error(c: CallResult)
 }
 
-/// Get (Unary)
-internal protocol Echo_EchoGetCall {
-  /// Cancel the call.
-  func cancel()
-}
-
-/// Get (Unary)
-fileprivate final class Echo_EchoGetCallImpl: Echo_EchoGetCall {
-  private var call : Call
-
-  /// Create a call.
-  init(_ channel: Channel) {
-    self.call = channel.makeCall("/echo.Echo/Get")
-  }
-
-  /// Run the call. Blocks until the reply is received.
-  /// - Throws: `BinaryEncodingError` if encoding fails. `CallError` if fails to call. `Echo_EchoClientError` if receives no response.
-  func run(request: Echo_EchoRequest,
-                       metadata: Metadata) throws -> Echo_EchoResponse {
-    let sem = DispatchSemaphore(value: 0)
-    var returnCallResult : CallResult!
-    var returnResponse : Echo_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 Echo_EchoClientError.error(c: returnCallResult)
-    }
-  }
-
-  /// Start the call. Nonblocking.
-  /// - Throws: `BinaryEncodingError` if encoding fails. `CallError` if fails to call.
-  func start(request: Echo_EchoRequest,
-                         metadata: Metadata,
-                         completion: @escaping ((Echo_EchoResponse?, CallResult)->()))
-    throws -> Echo_EchoGetCall {
-
-      let requestData = try request.serializedData()
-      try call.start(.unary,
-                     metadata:metadata,
-                     message:requestData)
-      {(callResult) in
-        if let responseData = callResult.resultData,
-          let response = try? Echo_EchoResponse(serializedData:responseData) {
-          completion(response, callResult)
-        } else {
-          completion(nil, callResult)
-        }
-      }
-      return self
-  }
+internal protocol Echo_EchoGetCall: ClientCallUnary { }
 
-  func cancel() {
-    call.cancel()
-  }
+fileprivate final class Echo_EchoGetCallImpl: ClientCallUnaryImpl<Echo_EchoRequest, Echo_EchoResponse>, Echo_EchoGetCall {
+  override class var method: String { return "/echo.Echo/Get" }
 }
 
 /// Expand (Server Streaming)

+ 1 - 1
Examples/Echo/PackageManager/Makefile

@@ -1,6 +1,6 @@
 
 all:
-	swift build -c release
+	swift build -c release --product Echo
 	cp .build/release/Echo .
 
 project:

+ 2 - 1
Package.swift

@@ -25,5 +25,6 @@ let package = Package(
     Target(name: "RootsEncoder")
   ],
   dependencies: [
-    .Package(url: "https://github.com/Zewo/zlib.git", majorVersion: 0, minor: 4)
+    .Package(url: "https://github.com/Zewo/zlib.git", majorVersion: 0, minor: 4),
+    .Package(url: "https://github.com/apple/swift-protobuf.git", majorVersion: 1, minor: 0)
   ])

+ 3 - 59
Plugin/Templates/client-call-unary.swift

@@ -1,61 +1,5 @@
-/// {{ method|methodDescriptorName }} (Unary)
-{{ access }} protocol {{ .|call:file,service,method }} {
-  /// Cancel the call.
-  func cancel()
-}
-
-/// {{ method|methodDescriptorName }} (Unary)
-fileprivate final class {{ .|call:file,service,method }}Impl: {{ .|call:file,service,method }} {
-  private var call : Call
-
-  /// Create a call.
-  init(_ channel: Channel) {
-    self.call = channel.makeCall("{{ .|path:file,service,method }}")
-  }
-
-  /// Run the call. Blocks until the reply is received.
-  /// - Throws: `BinaryEncodingError` if encoding fails. `CallError` if fails to call. `{{ .|clienterror:file,service }}` if receives no response.
-  func run(request: {{ method|input }},
-                       metadata: Metadata) throws -> {{ method|output }} {
-    let sem = DispatchSemaphore(value: 0)
-    var returnCallResult : CallResult!
-    var returnResponse : {{ method|output }}?
-    _ = 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 {{ .|clienterror:file,service }}.error(c: returnCallResult)
-    }
-  }
-
-  /// Start the call. Nonblocking.
-  /// - Throws: `BinaryEncodingError` if encoding fails. `CallError` if fails to call.
-  func start(request: {{ method|input }},
-                         metadata: Metadata,
-                         completion: @escaping (({{ method|output }}?, CallResult)->()))
-    throws -> {{ .|call:file,service,method }} {
-
-      let requestData = try request.serializedData()
-      try call.start(.unary,
-                     metadata:metadata,
-                     message:requestData)
-      {(callResult) in
-        if let responseData = callResult.resultData,
-          let response = try? {{ method|output }}(serializedData:responseData) {
-          completion(response, callResult)
-        } else {
-          completion(nil, callResult)
-        }
-      }
-      return self
-  }
+{{ access }} protocol {{ .|call:file,service,method }}: ClientCallUnary { }
 
-  func cancel() {
-    call.cancel()
-  }
+fileprivate final class {{ .|call:file,service,method }}Impl: ClientCallUnaryImpl<{{ method|input }}, {{ method|output }}>, {{ .|call:file,service,method }} {
+  override class var method: String { return "{{ .|path:file,service,method }}" }
 }

+ 77 - 0
Sources/gRPC/GenCodeSupport/ClientCallUnary.swift

@@ -0,0 +1,77 @@
+/*
+ * 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 SwiftProtobuf
+
+public protocol ClientCallUnary: class {
+  static var method: String { get }
+  
+  /// Cancel the call.
+  func cancel()
+}
+
+open class ClientCallUnaryImpl<InputType: Message, OutputType: Message>: ClientCallUnary {
+  open class var method: String { fatalError("needs to be overridden") }
+  
+  private var call: Call
+  
+  /// Create a call.
+  public init(_ channel: Channel) {
+    self.call = channel.makeCall(type(of: self).method)
+  }
+  
+  /// Run the call. Blocks until the reply is received.
+  /// - Throws: `BinaryEncodingError` if encoding fails. `CallError` if fails to call. `ClientError` if receives no response.
+  public func run(request: InputType, metadata: Metadata) throws -> OutputType {
+    let sem = DispatchSemaphore(value: 0)
+    var returnCallResult : CallResult!
+    var returnResponse : OutputType?
+    _ = 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 ClientError.error(c: returnCallResult)
+    }
+  }
+  
+  /// Start the call. Nonblocking.
+  /// - Throws: `BinaryEncodingError` if encoding fails. `CallError` if fails to call.
+  public func start(request: InputType,
+                    metadata: Metadata,
+                    completion: @escaping ((OutputType?, CallResult)->())) throws -> Self {
+    let requestData = try request.serializedData()
+    try call.start(.unary, metadata:metadata, message:requestData) { (callResult) in
+      if let responseData = callResult.resultData,
+        let response = try? OutputType(serializedData:responseData) {
+        completion(response, callResult)
+      } else {
+        completion(nil, callResult)
+      }
+    }
+    return self
+  }
+  
+  public func cancel() {
+    call.cancel()
+  }
+}

+ 25 - 0
Sources/gRPC/GenCodeSupport/ClientError.swift

@@ -0,0 +1,25 @@
+/*
+ * 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 SwiftProtobuf
+
+public enum ClientError: Error {
+	case endOfStream
+	case invalidMessageReceived
+	case error(c: CallResult)
+}