Generator-Client.swift 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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. self.printMethods()
  64. outdent()
  65. println("}")
  66. }
  67. private func printMethods(callFactory: String = "self") {
  68. for method in self.service.methods {
  69. self.println()
  70. self.method = method
  71. switch self.streamType {
  72. case .unary:
  73. self.printUnaryCall(callFactory: callFactory)
  74. case .serverStreaming:
  75. self.printServerStreamingCall(callFactory: callFactory)
  76. case .clientStreaming:
  77. self.printClientStreamingCall(callFactory: callFactory)
  78. case .bidirectionalStreaming:
  79. self.printBidirectionalStreamingCall(callFactory: callFactory)
  80. }
  81. }
  82. }
  83. private func printUnaryCall(callFactory: String) {
  84. self.println(self.method.documentation(streamingType: self.streamType), newline: false)
  85. self.println("///")
  86. self.printParameters()
  87. self.printRequestParameter()
  88. self.printCallOptionsParameter()
  89. self.println("/// - Returns: A `UnaryCall` with futures for the metadata, status and response.")
  90. self.println("\(self.access) func \(self.methodFunctionName)(")
  91. self.withIndentation {
  92. self.println("_ request: \(self.methodInputName),")
  93. self.println("callOptions: CallOptions? = nil")
  94. }
  95. self.println(") -> UnaryCall<\(self.methodInputName), \(self.methodOutputName)> {")
  96. self.withIndentation {
  97. self.println("return \(callFactory).makeUnaryCall(")
  98. self.withIndentation {
  99. self.println("path: \(self.methodPath),")
  100. self.println("request: request,")
  101. self.println("callOptions: callOptions ?? self.defaultCallOptions")
  102. }
  103. self.println(")")
  104. }
  105. self.println("}")
  106. }
  107. private func printServerStreamingCall(callFactory: String) {
  108. self.println(self.method.documentation(streamingType: self.streamType), newline: false)
  109. self.println("///")
  110. self.printParameters()
  111. self.printRequestParameter()
  112. self.printCallOptionsParameter()
  113. self.printHandlerParameter()
  114. self.println("/// - Returns: A `ServerStreamingCall` with futures for the metadata and status.")
  115. self.println("\(self.access) func \(self.methodFunctionName)(")
  116. self.withIndentation {
  117. self.println("_ request: \(self.methodInputName),")
  118. self.println("callOptions: CallOptions? = nil,")
  119. self.println("handler: @escaping (\(methodOutputName)) -> Void")
  120. }
  121. self.println(") -> ServerStreamingCall<\(methodInputName), \(methodOutputName)> {")
  122. self.withIndentation {
  123. self.println("return \(callFactory).makeServerStreamingCall(") // path: \"/\(servicePath)/\(method.name)\",")
  124. self.withIndentation {
  125. self.println("path: \(self.methodPath),")
  126. self.println("request: request,")
  127. self.println("callOptions: callOptions ?? self.defaultCallOptions,")
  128. self.println("handler: handler")
  129. }
  130. self.println(")")
  131. }
  132. self.println("}")
  133. }
  134. private func printClientStreamingCall(callFactory: String) {
  135. self.println(self.method.documentation(streamingType: self.streamType), newline: false)
  136. self.println("///")
  137. self.printClientStreamingDetails()
  138. self.println("///")
  139. self.printParameters()
  140. self.printCallOptionsParameter()
  141. self.println("/// - Returns: A `ClientStreamingCall` with futures for the metadata, status and response.")
  142. self.println("\(self.access) func \(self.methodFunctionName)(")
  143. self.withIndentation {
  144. self.println("callOptions: CallOptions? = nil")
  145. }
  146. self.println(") -> ClientStreamingCall<\(self.methodInputName), \(self.methodOutputName)> {")
  147. self.withIndentation {
  148. self.println("return \(callFactory).makeClientStreamingCall(")
  149. self.withIndentation {
  150. self.println("path: \(self.methodPath),")
  151. self.println("callOptions: callOptions ?? self.defaultCallOptions")
  152. }
  153. self.println(")")
  154. }
  155. self.println("}")
  156. }
  157. private func printBidirectionalStreamingCall(callFactory: String) {
  158. self.println(self.method.documentation(streamingType: self.streamType), newline: false)
  159. self.println("///")
  160. self.printClientStreamingDetails()
  161. self.println("///")
  162. self.printParameters()
  163. self.printCallOptionsParameter()
  164. self.printHandlerParameter()
  165. self.println("/// - Returns: A `ClientStreamingCall` with futures for the metadata and status.")
  166. self.println("\(self.access) func \(self.methodFunctionName)(")
  167. self.withIndentation {
  168. self.println("callOptions: CallOptions? = nil,")
  169. self.println("handler: @escaping (\(self.methodOutputName)) -> Void")
  170. }
  171. self.println(") -> BidirectionalStreamingCall<\(self.methodInputName), \(self.methodOutputName)> {")
  172. self.withIndentation {
  173. self.println("return \(callFactory).makeBidirectionalStreamingCall(")
  174. self.withIndentation {
  175. self.println("path: \(self.methodPath),")
  176. self.println("callOptions: callOptions ?? self.defaultCallOptions,")
  177. self.println("handler: handler")
  178. }
  179. self.println(")")
  180. }
  181. self.println("}")
  182. }
  183. private func printClientStreamingDetails() {
  184. println("/// Callers should use the `send` method on the returned object to send messages")
  185. println("/// to the server. The caller should send an `.end` after the final message has been sent.")
  186. }
  187. private func printParameters() {
  188. println("/// - Parameters:")
  189. }
  190. private func printRequestParameter() {
  191. println("/// - request: Request to send to \(method.name).")
  192. }
  193. private func printCallOptionsParameter() {
  194. println("/// - callOptions: Call options; `self.defaultCallOptions` is used if `nil`.")
  195. }
  196. private func printHandlerParameter() {
  197. println("/// - handler: A closure called when each response is received from the server.")
  198. }
  199. }
  200. fileprivate extension Generator {
  201. var streamType: StreamingType {
  202. return streamingType(self.method)
  203. }
  204. }
  205. fileprivate extension StreamingType {
  206. var name: String {
  207. switch self {
  208. case .unary:
  209. return "Unary"
  210. case .clientStreaming:
  211. return "Client streaming"
  212. case .serverStreaming:
  213. return "Server streaming"
  214. case .bidirectionalStreaming:
  215. return "Bidirectional streaming"
  216. }
  217. }
  218. }
  219. extension MethodDescriptor {
  220. var documentation: String? {
  221. let comments = self.protoSourceComments(commentPrefix: "")
  222. return comments.isEmpty ? nil : comments
  223. }
  224. fileprivate func documentation(streamingType: StreamingType) -> String {
  225. let sourceComments = self.protoSourceComments()
  226. if sourceComments.isEmpty {
  227. return "/// \(streamingType.name) call to \(self.name)\n" // comments end with "\n" already.
  228. } else {
  229. return sourceComments // already prefixed with "///"
  230. }
  231. }
  232. }