GRPCChannelBuilder.swift 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * Copyright 2020, 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 Dispatch
  17. import Logging
  18. import NIO
  19. import NIOSSL
  20. extension ClientConnection {
  21. /// Returns an insecure `ClientConnection` builder which is *not configured with TLS*.
  22. public static func insecure(group: EventLoopGroup) -> ClientConnection.Builder {
  23. return Builder(group: group)
  24. }
  25. /// Returns a `ClientConnection` builder configured with TLS.
  26. public static func secure(group: EventLoopGroup) -> ClientConnection.Builder.Secure {
  27. return Builder.Secure(group: group)
  28. }
  29. }
  30. extension ClientConnection {
  31. public class Builder {
  32. private var configuration: ClientConnection.Configuration
  33. private var maybeTLS: ClientConnection.Configuration.TLS? { return nil }
  34. private var connectionBackoff = ConnectionBackoff()
  35. private var connectionBackoffIsEnabled = true
  36. fileprivate init(group: EventLoopGroup) {
  37. // This is okay: the configuration is only consumed on a call to `connect` which sets the host
  38. // and port.
  39. self.configuration = Configuration(target: .hostAndPort("", .max), eventLoopGroup: group)
  40. }
  41. public func connect(host: String, port: Int) -> ClientConnection {
  42. // Finish setting up the configuration.
  43. self.configuration.target = .hostAndPort(host, port)
  44. self.configuration.connectionBackoff = self.connectionBackoffIsEnabled ? self.connectionBackoff : nil
  45. self.configuration.tls = maybeTLS
  46. return ClientConnection(configuration: self.configuration)
  47. }
  48. }
  49. }
  50. extension ClientConnection.Builder {
  51. public class Secure: ClientConnection.Builder {
  52. internal var tls = ClientConnection.Configuration.TLS()
  53. override internal var maybeTLS: ClientConnection.Configuration.TLS? {
  54. return self.tls
  55. }
  56. }
  57. }
  58. extension ClientConnection.Builder {
  59. /// Sets the initial connection backoff. That is, the initial time to wait before re-attempting to
  60. /// establish a connection. Jitter will *not* be applied to the initial backoff. Defaults to
  61. /// 1 second if not set.
  62. @discardableResult
  63. public func withConnectionBackoff(initial amount: TimeAmount) -> Self {
  64. self.connectionBackoff.initialBackoff = .seconds(from: amount)
  65. return self
  66. }
  67. /// Set the maximum connection backoff. That is, the maximum amount of time to wait before
  68. /// re-attempting to establish a connection. Note that this time amount represents the maximum
  69. /// backoff *before* jitter is applied. Defaults to 120 seconds if not set.
  70. @discardableResult
  71. public func withConnectionBackoff(maximum amount: TimeAmount) -> Self {
  72. self.connectionBackoff.maximumBackoff = .seconds(from: amount)
  73. return self
  74. }
  75. /// Backoff is 'jittered' to randomise the amount of time to wait before re-attempting to
  76. /// establish a connection. The jittered backoff will be no more than `jitter ⨯ unjitteredBackoff`
  77. /// from `unjitteredBackoff`. Defaults to 0.2 if not set.
  78. ///
  79. /// - Precondition: `0 <= jitter <= 1`
  80. @discardableResult
  81. public func withConnectionBackoff(jitter: Double) -> Self {
  82. self.connectionBackoff.jitter = jitter
  83. return self
  84. }
  85. /// The multiplier for scaling the unjittered backoff between attempts to establish a connection.
  86. /// Defaults to 1.6 if not set.
  87. @discardableResult
  88. public func withConnectionBackoff(multiplier: Double) -> Self {
  89. self.connectionBackoff.multiplier = multiplier
  90. return self
  91. }
  92. /// The minimum timeout to use when attempting to establishing a connection. The connection
  93. /// timeout for each attempt is the larger of the jittered backoff and the minimum connection
  94. /// timeout. Defaults to 20 seconds if not set.
  95. @discardableResult
  96. public func withConnectionTimeout(minimum amount: TimeAmount) -> Self {
  97. self.connectionBackoff.minimumConnectionTimeout = .seconds(from: amount)
  98. return self
  99. }
  100. /// Sets the initial and maximum backoff to given amount. Disables jitter and sets the backoff
  101. /// multiplier to 1.0.
  102. @discardableResult
  103. public func withConnectionBackoff(fixed amount: TimeAmount) -> Self {
  104. let seconds = Double.seconds(from: amount)
  105. self.connectionBackoff.initialBackoff = seconds
  106. self.connectionBackoff.maximumBackoff = seconds
  107. self.connectionBackoff.multiplier = 1.0
  108. self.connectionBackoff.jitter = 0.0
  109. return self
  110. }
  111. /// Sets the limit on the number of times to attempt to re-establish a connection. Defaults
  112. /// to `.unlimited` if not set.
  113. @discardableResult
  114. public func withConnectionBackoff(retries: ConnectionBackoff.Retries) -> Self {
  115. self.connectionBackoff.retries = retries
  116. return self
  117. }
  118. /// Sets whether the connection should be re-established automatically if it is dropped. Defaults
  119. /// to `true` if not set.
  120. @discardableResult
  121. public func withConnectionReestablishment(enabled: Bool) -> Self {
  122. self.connectionBackoffIsEnabled = enabled
  123. return self
  124. }
  125. /// Sets a custom configuration for keepalive
  126. /// The defaults for client and server are determined by the gRPC keepalive
  127. /// [documentation] (https://github.com/grpc/grpc/blob/master/doc/keepalive.md).
  128. @discardableResult
  129. public func withKeepalive(_ keepalive: ClientConnectionKeepalive) -> Self {
  130. self.configuration.connectionKeepalive = keepalive
  131. return self
  132. }
  133. /// The amount of time to wait before closing the connection. The idle timeout will start only
  134. /// if there are no RPCs in progress and will be cancelled as soon as any RPCs start. If a
  135. /// connection becomes idle, starting a new RPC will automatically create a new connection.
  136. /// Defaults to 5 minutes if not set.
  137. @discardableResult
  138. public func withConnectionIdleTimeout(_ timeout: TimeAmount) -> Self {
  139. self.configuration.connectionIdleTimeout = timeout
  140. return self
  141. }
  142. /// The behavior used to determine when an RPC should start. That is, whether it should wait for
  143. /// an active connection or fail quickly if no connection is currently available. Calls will
  144. /// use `.waitsForConnectivity` by default.
  145. @discardableResult
  146. public func withCallStartBehavior(_ behavior: CallStartBehavior) -> Self {
  147. self.configuration.callStartBehavior = behavior
  148. return self
  149. }
  150. }
  151. extension ClientConnection.Builder {
  152. /// Sets the client error delegate.
  153. @discardableResult
  154. public func withErrorDelegate(_ delegate: ClientErrorDelegate?) -> Self {
  155. self.configuration.errorDelegate = delegate
  156. return self
  157. }
  158. }
  159. extension ClientConnection.Builder {
  160. /// Sets the client connectivity state delegate and the `DispatchQueue` on which the delegate
  161. /// should be called. If no `queue` is provided then gRPC will create a `DispatchQueue` on which
  162. /// to run the delegate.
  163. @discardableResult
  164. public func withConnectivityStateDelegate(
  165. _ delegate: ConnectivityStateDelegate?,
  166. executingOn queue: DispatchQueue? = nil
  167. ) -> Self {
  168. self.configuration.connectivityStateDelegate = delegate
  169. self.configuration.connectivityStateDelegateQueue = queue
  170. return self
  171. }
  172. }
  173. extension ClientConnection.Builder.Secure {
  174. /// Sets a server hostname override to be used for the TLS Server Name Indication (SNI) extension.
  175. /// The hostname from `connect(host:port)` is for TLS SNI if this value is not set and hostname
  176. /// verification is enabled.
  177. @discardableResult
  178. public func withTLS(serverHostnameOverride: String?) -> Self {
  179. self.tls.hostnameOverride = serverHostnameOverride
  180. return self
  181. }
  182. /// Sets the sources of certificates to offer during negotiation. No certificates are offered
  183. /// during negotiation by default.
  184. @discardableResult
  185. public func withTLS(certificateChain: [NIOSSLCertificate]) -> Self {
  186. // `.certificate` is the only non-deprecated case in `NIOSSLCertificateSource`
  187. self.tls.certificateChain = certificateChain.map { .certificate($0) }
  188. return self
  189. }
  190. /// Sets the private key associated with the leaf certificate.
  191. @discardableResult
  192. public func withTLS(privateKey: NIOSSLPrivateKey) -> Self {
  193. // `.privateKey` is the only non-deprecated case in `NIOSSLPrivateKeySource`
  194. self.tls.privateKey = .privateKey(privateKey)
  195. return self
  196. }
  197. /// Sets the trust roots to use to validate certificates. This only needs to be provided if you
  198. /// intend to validate certificates. Defaults to the system provided trust store (`.default`) if
  199. /// not set.
  200. @discardableResult
  201. public func withTLS(trustRoots: NIOSSLTrustRoots) -> Self {
  202. self.tls.trustRoots = trustRoots
  203. return self
  204. }
  205. }
  206. extension ClientConnection.Builder {
  207. /// Sets the HTTP/2 flow control target window size. Defaults to 65,535 if not explicitly set.
  208. @discardableResult
  209. public func withHTTPTargetWindowSize(_ httpTargetWindowSize: Int) -> Self {
  210. self.configuration.httpTargetWindowSize = httpTargetWindowSize
  211. return self
  212. }
  213. }
  214. extension ClientConnection.Builder {
  215. /// Sets a logger to be used for background activity such as connection state changes. Defaults
  216. /// to a no-op logger if not explicitly set.
  217. ///
  218. /// Note that individual RPCs will use the logger from `CallOptions`, not the logger specified
  219. /// here.
  220. @discardableResult
  221. public func withBackgroundActivityLogger(_ logger: Logger) -> Self {
  222. self.configuration.backgroundActivityLogger = logger
  223. return self
  224. }
  225. }
  226. extension ClientConnection.Builder {
  227. /// A channel initializer which will be run after gRPC has initialized each channel. This may be
  228. /// used to add additional handlers to the pipeline and is intended for debugging.
  229. ///
  230. /// - Warning: The initializer closure may be invoked *multiple times*.
  231. @discardableResult
  232. public func withDebugChannelInitializer(
  233. _ debugChannelInitializer: @escaping (Channel) -> EventLoopFuture<Void>
  234. ) -> Self {
  235. self.configuration.debugChannelInitializer = debugChannelInitializer
  236. return self
  237. }
  238. }
  239. fileprivate extension Double {
  240. static func seconds(from amount: TimeAmount) -> Double {
  241. return Double(amount.nanoseconds) / 1_000_000_000
  242. }
  243. }