diff --git a/Sources/GRPC/ServerCallContexts/ServerCallContext.swift b/Sources/GRPC/ServerCallContexts/ServerCallContext.swift index f74453ede..90d2f6b10 100644 --- a/Sources/GRPC/ServerCallContexts/ServerCallContext.swift +++ b/Sources/GRPC/ServerCallContexts/ServerCallContext.swift @@ -54,17 +54,37 @@ open class ServerCallContextBase: ServerCallContext { /// Whether compression should be enabled for responses, defaulting to `true`. Note that for /// this value to take effect compression must have been enabled on the server and a compression /// algorithm must have been negotiated with the client. - public var compressionEnabled: Bool = true + /// + /// - Important: This *must* be accessed from the context's `eventLoop` in order to ensure + /// thread-safety. + public var compressionEnabled: Bool { + get { + self.eventLoop.assertInEventLoop() + return self._compressionEnabled + } + set { + self.eventLoop.assertInEventLoop() + self._compressionEnabled = newValue + } + } + + private var _compressionEnabled: Bool = true + /// A `UserInfo` dictionary which is shared with the interceptor contexts for this RPC. + /// /// - Important: While `UserInfo` has value-semantics, this property retrieves from, and sets a /// reference wrapped `UserInfo`. The contexts passed to interceptors provide the same /// reference. As such this may be used as a mechanism to pass information between interceptors /// and service providers. + /// - Important: This *must* be accessed from the context's `eventLoop` in order to ensure + /// thread-safety. public var userInfo: UserInfo { get { + self.eventLoop.assertInEventLoop() return self.userInfoRef.value } set { + self.eventLoop.assertInEventLoop() self.userInfoRef.value = newValue } } @@ -75,7 +95,21 @@ open class ServerCallContextBase: ServerCallContext { /// Metadata to return at the end of the RPC. If this is required it should be updated before /// the `responsePromise` or `statusPromise` is fulfilled. - public var trailers = HPACKHeaders() + /// + /// - Important: This *must* be accessed from the context's `eventLoop` in order to ensure + /// thread-safety. + public var trailers: HPACKHeaders { + get { + self.eventLoop.assertInEventLoop() + return self._trailers + } + set { + self.eventLoop.assertInEventLoop() + self._trailers = newValue + } + } + + private var _trailers: HPACKHeaders = [:] public convenience init( eventLoop: EventLoop, diff --git a/Sources/GRPC/ServerCallContexts/UnaryResponseCallContext.swift b/Sources/GRPC/ServerCallContexts/UnaryResponseCallContext.swift index 70966af95..1b9d37815 100644 --- a/Sources/GRPC/ServerCallContexts/UnaryResponseCallContext.swift +++ b/Sources/GRPC/ServerCallContexts/UnaryResponseCallContext.swift @@ -35,7 +35,21 @@ open class UnaryResponseCallContext: ServerCallContextBase, StatusOnly /// The status sent back to the client at the end of the RPC, providing the `responsePromise` was /// completed successfully. - public var responseStatus: GRPCStatus = .ok + /// + /// - Important: This *must* be accessed from the context's `eventLoop` in order to ensure + /// thread-safety. + public var responseStatus: GRPCStatus { + get { + self.eventLoop.assertInEventLoop() + return self._responseStatus + } + set { + self.eventLoop.assertInEventLoop() + self._responseStatus = newValue + } + } + + private var _responseStatus: GRPCStatus = .ok public convenience init( eventLoop: EventLoop,