GRPCChannelBuilder.swift 7.8 KB

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