GRPCChannelBuilder.swift 9.8 KB

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