GRPCStatus.swift 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import Foundation
  2. import NIO
  3. import NIOHTTP1
  4. import NIOHTTP2
  5. /// Encapsulates the result of a gRPC call.
  6. ///
  7. /// We use a `class` here for a couple of reasons:
  8. /// - The size of the equivalent `struct` is larger than the value buffer in an existential
  9. /// container so would incur a heap allocation each time a `GRPCStatus` is passed to a function
  10. /// taking an `Error`.
  11. /// - We aren't using value semantics (since all properties are constant).
  12. public final class GRPCStatus: Error {
  13. /// The code to return in the `grpc-status` header.
  14. public let code: StatusCode
  15. /// The message to return in the `grpc-message` header.
  16. public let message: String?
  17. /// Additional HTTP headers to return in the trailers.
  18. public let trailingMetadata: HTTPHeaders
  19. public init(code: StatusCode, message: String?, trailingMetadata: HTTPHeaders = HTTPHeaders()) {
  20. self.code = code
  21. self.message = message
  22. self.trailingMetadata = trailingMetadata
  23. }
  24. // Frequently used "default" statuses.
  25. /// The default status to return for succeeded calls.
  26. public static let ok = GRPCStatus(code: .ok, message: "OK")
  27. /// "Internal server error" status.
  28. public static let processingError = GRPCStatus(code: .internalError, message: "unknown error processing request")
  29. }
  30. public protocol GRPCStatusTransformable: Error {
  31. func asGRPCStatus() -> GRPCStatus
  32. }
  33. extension GRPCStatus: GRPCStatusTransformable {
  34. public func asGRPCStatus() -> GRPCStatus {
  35. return self
  36. }
  37. }
  38. extension NIOHTTP2Errors.StreamClosed: GRPCStatusTransformable {
  39. public func asGRPCStatus() -> GRPCStatus {
  40. return .init(code: .unavailable, message: self.localizedDescription)
  41. }
  42. }
  43. extension NIOHTTP2Errors.IOOnClosedConnection: GRPCStatusTransformable {
  44. public func asGRPCStatus() -> GRPCStatus {
  45. return .init(code: .unavailable, message: "The connection is closed")
  46. }
  47. }
  48. extension ChannelError: GRPCStatusTransformable {
  49. public func asGRPCStatus() -> GRPCStatus {
  50. switch self {
  51. case .inputClosed, .outputClosed, .ioOnClosedChannel:
  52. return .init(code: .unavailable, message: "The connection is closed")
  53. default:
  54. return .processingError
  55. }
  56. }
  57. }