GRPCAsyncServerCallContext.swift 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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.6)
  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 require a
  30. // promise to glue the NIO and async-await paradigms in the handler.
  31. //
  32. // Note: this is `@unchecked Sendable`; all mutable state is protected by a lock.
  33. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  34. public final class GRPCAsyncServerCallContext: @unchecked Sendable {
  35. private let lock = Lock()
  36. /// Metadata for this request.
  37. public let requestMetadata: HPACKHeaders
  38. /// The logger used for this call.
  39. public var logger: Logger {
  40. get { self.lock.withLock {
  41. self._logger
  42. } }
  43. set { self.lock.withLock {
  44. self._logger = newValue
  45. } }
  46. }
  47. @usableFromInline
  48. internal var _logger: Logger
  49. /// Whether compression should be enabled for responses, defaulting to `true`. Note that for
  50. /// this value to take effect compression must have been enabled on the server and a compression
  51. /// algorithm must have been negotiated with the client.
  52. public var compressionEnabled: Bool {
  53. get { self.lock.withLock {
  54. self._compressionEnabled
  55. } }
  56. set { self.lock.withLock {
  57. self._compressionEnabled = newValue
  58. } }
  59. }
  60. private var _compressionEnabled: Bool = true
  61. /// A `UserInfo` dictionary which is shared with the interceptor contexts for this RPC.
  62. ///
  63. /// - Important: While `UserInfo` has value-semantics, this property retrieves from, and sets a
  64. /// reference wrapped `UserInfo`. The contexts passed to interceptors provide the same
  65. /// reference. As such this may be used as a mechanism to pass information between interceptors
  66. /// and service providers.
  67. public var userInfo: UserInfo {
  68. get { self.lock.withLock {
  69. self.userInfoRef.value
  70. } }
  71. set { self.lock.withLock {
  72. self.userInfoRef.value = newValue
  73. } }
  74. }
  75. /// A reference to an underlying `UserInfo`. We share this with the interceptors.
  76. @usableFromInline
  77. internal let userInfoRef: Ref<UserInfo>
  78. /// Metadata to return at the start of the RPC.
  79. ///
  80. /// - Important: If this is required it should be updated _before_ the first response is sent via
  81. /// the response stream writer. Any updates made after the first response will be ignored.
  82. public var initialResponseMetadata: HPACKHeaders {
  83. get { self.lock.withLock {
  84. return self._initialResponseMetadata
  85. } }
  86. set { self.lock.withLock {
  87. self._initialResponseMetadata = newValue
  88. } }
  89. }
  90. private var _initialResponseMetadata: HPACKHeaders = [:]
  91. /// Metadata to return at the end of the RPC.
  92. ///
  93. /// If this is required it should be updated before returning from the handler.
  94. public var trailingResponseMetadata: HPACKHeaders {
  95. get { self.lock.withLock {
  96. return self._trailingResponseMetadata
  97. } }
  98. set { self.lock.withLock {
  99. self._trailingResponseMetadata = newValue
  100. } }
  101. }
  102. private var _trailingResponseMetadata: HPACKHeaders = [:]
  103. @inlinable
  104. internal init(
  105. headers: HPACKHeaders,
  106. logger: Logger,
  107. userInfoRef: Ref<UserInfo>
  108. ) {
  109. self.requestMetadata = headers
  110. self.userInfoRef = userInfoRef
  111. self._logger = logger
  112. }
  113. }
  114. #endif