main.swift 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*
  2. * Copyright 2019, 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 Commander
  17. import Dispatch
  18. import Foundation
  19. import NIO
  20. import NIOSSL
  21. import GRPC
  22. import GRPCSampleData
  23. import EchoImplementation
  24. import EchoModel
  25. // Common flags and options
  26. let sslFlag = Flag("ssl", description: "if true, use SSL for connections")
  27. func addressOption(_ address: String) -> Option<String> {
  28. return Option("address", default: address, description: "address of server")
  29. }
  30. let portOption = Option("port", default: 8080)
  31. let messageOption = Option("message",
  32. default: "Testing 1 2 3",
  33. description: "message to send")
  34. func makeClientTLSConfiguration() -> ClientConnection.Configuration.TLS {
  35. let caCert = SampleCertificate.ca
  36. let clientCert = SampleCertificate.client
  37. precondition(!caCert.isExpired && !clientCert.isExpired,
  38. "SSL certificates are expired. Please submit an issue at https://github.com/grpc/grpc-swift.")
  39. return .init(certificateChain: [.certificate(clientCert.certificate)],
  40. privateKey: .privateKey(SamplePrivateKey.client),
  41. trustRoots: .certificates([caCert.certificate]),
  42. certificateVerification: .noHostnameVerification)
  43. }
  44. func makeServerTLSConfiguration() -> Server.Configuration.TLS {
  45. let caCert = SampleCertificate.ca
  46. let serverCert = SampleCertificate.server
  47. precondition(!caCert.isExpired && !serverCert.isExpired,
  48. "SSL certificates are expired. Please submit an issue at https://github.com/grpc/grpc-swift.")
  49. return .init(certificateChain: [.certificate(serverCert.certificate)],
  50. privateKey: .privateKey(SamplePrivateKey.server),
  51. trustRoots: .certificates([caCert.certificate]))
  52. }
  53. /// Create en `EchoClient` and wait for it to initialize. Returns nil if initialisation fails.
  54. func makeEchoClient(address: String, port: Int, ssl: Bool) -> Echo_EchoServiceClient? {
  55. let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
  56. let configuration = ClientConnection.Configuration(
  57. target: .hostAndPort(address, port),
  58. eventLoopGroup: eventLoopGroup,
  59. tls: ssl ? makeClientTLSConfiguration() : nil)
  60. return Echo_EchoServiceClient(connection: ClientConnection(configuration: configuration))
  61. }
  62. Group {
  63. $0.command("serve",
  64. sslFlag,
  65. addressOption("localhost"),
  66. portOption,
  67. description: "Run an echo server.") { ssl, address, port in
  68. let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
  69. var configuration = Server.Configuration(
  70. target: .hostAndPort(address, port),
  71. eventLoopGroup: eventLoopGroup,
  72. serviceProviders: [EchoProvider()])
  73. if ssl {
  74. print("starting secure server")
  75. configuration.tls = makeServerTLSConfiguration()
  76. } else {
  77. print("starting insecure server")
  78. }
  79. let server = try! Server.start(configuration: configuration)
  80. .wait()
  81. // This blocks to keep the main thread from finishing while the server runs,
  82. // but the server never exits. Kill the process to stop it.
  83. try server.onClose.wait()
  84. }
  85. $0.command(
  86. "get",
  87. sslFlag,
  88. addressOption("localhost"),
  89. portOption,
  90. messageOption,
  91. description: "Perform a unary get()."
  92. ) { ssl, address, port, message in
  93. print("calling get")
  94. guard let echo = makeEchoClient(address: address, port: port, ssl: ssl) else { return }
  95. var requestMessage = Echo_EchoRequest()
  96. requestMessage.text = message
  97. print("get sending: \(requestMessage.text)")
  98. let get = echo.get(requestMessage)
  99. get.response.whenSuccess { response in
  100. print("get received: \(response.text)")
  101. }
  102. get.response.whenFailure { error in
  103. print("get response failed with error: \(error)")
  104. }
  105. // wait() on the status to stop the program from exiting.
  106. do {
  107. let status = try get.status.wait()
  108. print("get completed with status: \(status)")
  109. } catch {
  110. print("get status failed with error: \(error)")
  111. }
  112. }
  113. $0.command(
  114. "expand",
  115. sslFlag,
  116. addressOption("localhost"),
  117. portOption,
  118. messageOption,
  119. description: "Perform a server-streaming expand()."
  120. ) { ssl, address, port, message in
  121. print("calling expand")
  122. guard let echo = makeEchoClient(address: address, port: port, ssl: ssl) else { return }
  123. let requestMessage = Echo_EchoRequest.with { $0.text = message }
  124. print("expand sending: \(requestMessage.text)")
  125. let expand = echo.expand(requestMessage) { response in
  126. print("expand received: \(response.text)")
  127. }
  128. // wait() on the status to stop the program from exiting.
  129. do {
  130. let status = try expand.status.wait()
  131. print("expand completed with status: \(status)")
  132. } catch {
  133. print("expand status failed with error: \(error)")
  134. }
  135. }
  136. $0.command(
  137. "collect",
  138. sslFlag,
  139. addressOption("localhost"),
  140. portOption,
  141. messageOption,
  142. description: "Perform a client-streaming collect()."
  143. ) { ssl, address, port, message in
  144. print("calling collect")
  145. guard let echo = makeEchoClient(address: address, port: port, ssl: ssl) else { return }
  146. let collect = echo.collect()
  147. var queue = collect.newMessageQueue()
  148. for part in message.components(separatedBy: " ") {
  149. var requestMessage = Echo_EchoRequest()
  150. requestMessage.text = part
  151. print("collect sending: \(requestMessage.text)")
  152. queue = queue.flatMap { collect.sendMessage(requestMessage) }
  153. }
  154. queue.whenSuccess { collect.sendEnd(promise: nil) }
  155. collect.response.whenSuccess { respone in
  156. print("collect received: \(respone.text)")
  157. }
  158. collect.response.whenFailure { error in
  159. print("collect response failed with error: \(error)")
  160. }
  161. // wait() on the status to stop the program from exiting.
  162. do {
  163. let status = try collect.status.wait()
  164. print("collect completed with status: \(status)")
  165. } catch {
  166. print("collect status failed with error: \(error)")
  167. }
  168. }
  169. $0.command(
  170. "update",
  171. sslFlag,
  172. addressOption("localhost"),
  173. portOption,
  174. messageOption,
  175. description: "Perform a bidirectional-streaming update()."
  176. ) { ssl, address, port, message in
  177. print("calling update")
  178. guard let echo = makeEchoClient(address: address, port: port, ssl: ssl) else { return }
  179. let update = echo.update { response in
  180. print("update received: \(response.text)")
  181. }
  182. var queue = update.newMessageQueue()
  183. for part in message.components(separatedBy: " ") {
  184. var requestMessage = Echo_EchoRequest()
  185. requestMessage.text = part
  186. print("update sending: \(requestMessage.text)")
  187. queue = queue.flatMap { update.sendMessage(requestMessage) }
  188. }
  189. queue.whenSuccess { update.sendEnd(promise: nil) }
  190. // wait() on the status to stop the program from exiting.
  191. do {
  192. let status = try update.status.wait()
  193. print("update completed with status: \(status)")
  194. } catch {
  195. print("update status failed with error: \(error)")
  196. }
  197. }
  198. }.run()