GRPCAsyncServerCallContext.swift 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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. #if compiler(>=5.5.2) && canImport(_Concurrency)
  17. import Logging
  18. import NIOConcurrencyHelpers
  19. import NIOHPACK
  20. // We use a `class` here because we do not want copy-on-write semantics. The instance that the async
  21. // handler holds must not diverge from the instance the implementor of the RPC holds. They hold these
  22. // instances on different threads (EventLoop vs Task).
  23. //
  24. // We considered wrapping this in a `struct` and pass it `inout` to the RPC. This would communicate
  25. // explicitly that it stores mutable state. However, without copy-on-write semantics, this could
  26. // make for a surprising API.
  27. //
  28. // We also considered an `actor` but that felt clunky at the point of use since adopters would need
  29. // to `await` the retrieval of a logger or the updating of the trailers and each would requrie a
  30. // promise to glue the NIO and async-await paradigms in the handler.
  31. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  32. public final class GRPCAsyncServerCallContext {
  33. private let lock = Lock()
  34. /// Metadata for this request.
  35. public let requestMetadata: HPACKHeaders
  36. /// The logger used for this call.
  37. public var logger: Logger {
  38. get { self.lock.withLock {
  39. self._logger
  40. } }
  41. set { self.lock.withLock {
  42. self._logger = newValue
  43. } }
  44. }
  45. @usableFromInline
  46. internal var _logger: Logger
  47. /// Whether compression should be enabled for responses, defaulting to `true`. Note that for
  48. /// this value to take effect compression must have been enabled on the server and a compression
  49. /// algorithm must have been negotiated with the client.
  50. public var compressionEnabled: Bool {
  51. get { self.lock.withLock {
  52. self._compressionEnabled
  53. } }
  54. set { self.lock.withLock {
  55. self._compressionEnabled = newValue
  56. } }
  57. }
  58. private var _compressionEnabled: Bool = true
  59. /// A `UserInfo` dictionary which is shared with the interceptor contexts for this RPC.
  60. ///
  61. /// - Important: While `UserInfo` has value-semantics, this property retrieves from, and sets a
  62. /// reference wrapped `UserInfo`. The contexts passed to interceptors provide the same
  63. /// reference. As such this may be used as a mechanism to pass information between interceptors
  64. /// and service providers.
  65. public var userInfo: UserInfo {
  66. get { self.lock.withLock {
  67. self.userInfoRef.value
  68. } }
  69. set { self.lock.withLock {
  70. self.userInfoRef.value = newValue
  71. } }
  72. }
  73. /// A reference to an underlying `UserInfo`. We share this with the interceptors.
  74. @usableFromInline
  75. internal let userInfoRef: Ref<UserInfo>
  76. /// Metadata to return at the start of the RPC.
  77. ///
  78. /// - Important: If this is required it should be updated _before_ the first response is sent via
  79. /// the response stream writer. Any updates made after the first response will be ignored.
  80. public var initialResponseMetadata: HPACKHeaders {
  81. get { self.lock.withLock {
  82. return self._initialResponseMetadata
  83. } }
  84. set { self.lock.withLock {
  85. self._initialResponseMetadata = newValue
  86. } }
  87. }
  88. private var _initialResponseMetadata: HPACKHeaders = [:]
  89. /// Metadata to return at the end of the RPC.
  90. ///
  91. /// If this is required it should be updated before returning from the handler.
  92. public var trailingResponseMetadata: HPACKHeaders {
  93. get { self.lock.withLock {
  94. return self._trailingResponseMetadata
  95. } }
  96. set { self.lock.withLock {
  97. self._trailingResponseMetadata = newValue
  98. } }
  99. }
  100. private var _trailingResponseMetadata: HPACKHeaders = [:]
  101. @inlinable
  102. internal init(
  103. headers: HPACKHeaders,
  104. logger: Logger,
  105. userInfoRef: Ref<UserInfo>
  106. ) {
  107. self.requestMetadata = headers
  108. self.userInfoRef = userInfoRef
  109. self._logger = logger
  110. }
  111. }
  112. #endif