ConnectionPool+Waiter.swift 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /*
  2. * Copyright 2021, 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 NIOCore
  17. import NIOHTTP2
  18. extension ConnectionPool {
  19. internal final class Waiter {
  20. /// A promise to complete with the initialized channel.
  21. private let promise: EventLoopPromise<Channel>
  22. fileprivate var channelFuture: EventLoopFuture<Channel> {
  23. return self.promise.futureResult
  24. }
  25. /// The channel initializer.
  26. private let channelInitializer: (Channel) -> EventLoopFuture<Void>
  27. /// The deadline at which the timeout is scheduled.
  28. private let deadline: NIODeadline
  29. /// A scheduled task which fails the stream promise should the pool not provide
  30. /// a stream in time.
  31. private var scheduledTimeout: Scheduled<Void>?
  32. /// An identifier for this waiter.
  33. internal var id: ID {
  34. return ID(self)
  35. }
  36. internal init(
  37. deadline: NIODeadline,
  38. promise: EventLoopPromise<Channel>,
  39. channelInitializer: @escaping (Channel) -> EventLoopFuture<Void>
  40. ) {
  41. self.deadline = deadline
  42. self.promise = promise
  43. self.channelInitializer = channelInitializer
  44. self.scheduledTimeout = nil
  45. }
  46. /// Schedule a timeout for this waiter. This task will be cancelled when the waiter is
  47. /// succeeded or failed.
  48. ///
  49. /// - Parameters:
  50. /// - eventLoop: The `EventLoop` to run the timeout task on.
  51. /// - body: The closure to execute when the timeout is fired.
  52. internal func scheduleTimeout(
  53. on eventLoop: EventLoop,
  54. execute body: @escaping () -> Void
  55. ) {
  56. assert(self.scheduledTimeout == nil)
  57. eventLoop.scheduleTask(deadline: self.deadline, body)
  58. }
  59. /// Returns a boolean value indicating whether the deadline for this waiter occurs after the
  60. /// given deadline.
  61. internal func deadlineIsAfter(_ other: NIODeadline) -> Bool {
  62. return self.deadline > other
  63. }
  64. /// Succeed the waiter with the given multiplexer.
  65. internal func succeed(with multiplexer: HTTP2StreamMultiplexer) {
  66. self.scheduledTimeout?.cancel()
  67. self.scheduledTimeout = nil
  68. multiplexer.createStreamChannel(promise: self.promise, self.channelInitializer)
  69. }
  70. /// Fail the waiter with `error`.
  71. internal func fail(_ error: Error) {
  72. self.scheduledTimeout?.cancel()
  73. self.scheduledTimeout = nil
  74. self.promise.fail(error)
  75. }
  76. /// The ID of a waiter.
  77. internal struct ID: Hashable, CustomStringConvertible {
  78. private let id: ObjectIdentifier
  79. fileprivate init(_ waiter: Waiter) {
  80. self.id = ObjectIdentifier(waiter)
  81. }
  82. internal var description: String {
  83. return String(describing: self.id)
  84. }
  85. }
  86. }
  87. }