Generator-Client.swift 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * Copyright 2018, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import Foundation
  17. import SwiftProtobuf
  18. import SwiftProtobufPluginLibrary
  19. extension Generator {
  20. internal func printClient() {
  21. println()
  22. printServiceClientProtocol()
  23. println()
  24. printServiceClientImplementation()
  25. }
  26. private func printServiceClientProtocol() {
  27. println("/// Usage: instantiate \(clientClassName), then call methods of this protocol to make API calls.")
  28. println("\(options.visibility.sourceSnippet) protocol \(clientProtocolName) {")
  29. indent()
  30. for method in service.methods {
  31. self.method = method
  32. switch streamingType(method) {
  33. case .unary:
  34. println("func \(methodFunctionName)(_ request: \(methodInputName), callOptions: CallOptions?) -> UnaryCall<\(methodInputName), \(methodOutputName)>")
  35. case .serverStreaming:
  36. println("func \(methodFunctionName)(_ request: \(methodInputName), callOptions: CallOptions?, handler: @escaping (\(methodOutputName)) -> Void) -> ServerStreamingCall<\(methodInputName), \(methodOutputName)>")
  37. case .clientStreaming:
  38. println("func \(methodFunctionName)(callOptions: CallOptions?) -> ClientStreamingCall<\(methodInputName), \(methodOutputName)>")
  39. case .bidirectionalStreaming:
  40. println("func \(methodFunctionName)(callOptions: CallOptions?, handler: @escaping (\(methodOutputName)) -> Void) -> BidirectionalStreamingCall<\(methodInputName), \(methodOutputName)>")
  41. }
  42. }
  43. outdent()
  44. println("}")
  45. }
  46. private func printServiceClientImplementation() {
  47. println("\(access) final class \(clientClassName): GRPCClient, \(clientProtocolName) {")
  48. indent()
  49. println("\(access) let channel: GRPCChannel")
  50. println("\(access) var defaultCallOptions: CallOptions")
  51. println()
  52. println("/// Creates a client for the \(servicePath) service.")
  53. println("///")
  54. printParameters()
  55. println("/// - channel: `GRPCChannel` to the service host.")
  56. println("/// - defaultCallOptions: Options to use for each service call if the user doesn't provide them.")
  57. println("\(access) init(channel: GRPCChannel, defaultCallOptions: CallOptions = CallOptions()) {")
  58. indent()
  59. println("self.channel = channel")
  60. println("self.defaultCallOptions = defaultCallOptions")
  61. outdent()
  62. println("}")
  63. println()
  64. for method in service.methods {
  65. self.method = method
  66. let streamType = streamingType(self.method)
  67. switch streamType {
  68. case .unary:
  69. println(self.method.documentation(streamingType: streamType), newline: false)
  70. println("///")
  71. printParameters()
  72. printRequestParameter()
  73. printCallOptionsParameter()
  74. println("/// - Returns: A `UnaryCall` with futures for the metadata, status and response.")
  75. println("\(access) func \(methodFunctionName)(_ request: \(methodInputName), callOptions: CallOptions? = nil) -> UnaryCall<\(methodInputName), \(methodOutputName)> {")
  76. indent()
  77. println("return self.makeUnaryCall(path: \"/\(servicePath)/\(method.name)\",")
  78. println(" request: request,")
  79. println(" callOptions: callOptions ?? self.defaultCallOptions)")
  80. outdent()
  81. println("}")
  82. case .serverStreaming:
  83. println(self.method.documentation(streamingType: streamType), newline: false)
  84. println("///")
  85. printParameters()
  86. printRequestParameter()
  87. printCallOptionsParameter()
  88. printHandlerParameter()
  89. println("/// - Returns: A `ServerStreamingCall` with futures for the metadata and status.")
  90. println("\(access) func \(methodFunctionName)(_ request: \(methodInputName), callOptions: CallOptions? = nil, handler: @escaping (\(methodOutputName)) -> Void) -> ServerStreamingCall<\(methodInputName), \(methodOutputName)> {")
  91. indent()
  92. println("return self.makeServerStreamingCall(path: \"/\(servicePath)/\(method.name)\",")
  93. println(" request: request,")
  94. println(" callOptions: callOptions ?? self.defaultCallOptions,")
  95. println(" handler: handler)")
  96. outdent()
  97. println("}")
  98. case .clientStreaming:
  99. println(self.method.documentation(streamingType: streamType), newline: false)
  100. println("///")
  101. printClientStreamingDetails()
  102. println("///")
  103. printParameters()
  104. printCallOptionsParameter()
  105. println("/// - Returns: A `ClientStreamingCall` with futures for the metadata, status and response.")
  106. println("\(access) func \(methodFunctionName)(callOptions: CallOptions? = nil) -> ClientStreamingCall<\(methodInputName), \(methodOutputName)> {")
  107. indent()
  108. println("return self.makeClientStreamingCall(path: \"/\(servicePath)/\(method.name)\",")
  109. println(" callOptions: callOptions ?? self.defaultCallOptions)")
  110. outdent()
  111. println("}")
  112. case .bidirectionalStreaming:
  113. println(self.method.documentation(streamingType: streamType), newline: false)
  114. println("///")
  115. printClientStreamingDetails()
  116. println("///")
  117. printParameters()
  118. printCallOptionsParameter()
  119. printHandlerParameter()
  120. println("/// - Returns: A `ClientStreamingCall` with futures for the metadata and status.")
  121. println("\(access) func \(methodFunctionName)(callOptions: CallOptions? = nil, handler: @escaping (\(methodOutputName)) -> Void) -> BidirectionalStreamingCall<\(methodInputName), \(methodOutputName)> {")
  122. indent()
  123. println("return self.makeBidirectionalStreamingCall(path: \"/\(servicePath)/\(method.name)\",")
  124. println(" callOptions: callOptions ?? self.defaultCallOptions,")
  125. println(" handler: handler)")
  126. outdent()
  127. println("}")
  128. }
  129. println()
  130. }
  131. outdent()
  132. println("}")
  133. }
  134. private func printClientStreamingDetails() {
  135. println("/// Callers should use the `send` method on the returned object to send messages")
  136. println("/// to the server. The caller should send an `.end` after the final message has been sent.")
  137. }
  138. private func printParameters() {
  139. println("/// - Parameters:")
  140. }
  141. private func printRequestParameter() {
  142. println("/// - request: Request to send to \(method.name).")
  143. }
  144. private func printCallOptionsParameter() {
  145. println("/// - callOptions: Call options; `self.defaultCallOptions` is used if `nil`.")
  146. }
  147. private func printHandlerParameter() {
  148. println("/// - handler: A closure called when each response is received from the server.")
  149. }
  150. }
  151. fileprivate extension StreamingType {
  152. var name: String {
  153. switch self {
  154. case .unary:
  155. return "Unary"
  156. case .clientStreaming:
  157. return "Client streaming"
  158. case .serverStreaming:
  159. return "Server streaming"
  160. case .bidirectionalStreaming:
  161. return "Bidirectional streaming"
  162. }
  163. }
  164. }
  165. extension MethodDescriptor {
  166. var documentation: String? {
  167. let comments = self.protoSourceComments(commentPrefix: "")
  168. return comments.isEmpty ? nil : comments
  169. }
  170. fileprivate func documentation(streamingType: StreamingType) -> String {
  171. let sourceComments = self.protoSourceComments()
  172. if sourceComments.isEmpty {
  173. return "/// \(streamingType.name) call to \(self.name)\n" // comments end with "\n" already.
  174. } else {
  175. return sourceComments // already prefixed with "///"
  176. }
  177. }
  178. }