1# Copyright 2015 gRPC authors. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15require_relative './structs' 16require_relative './core/status_codes' 17require_relative './google_rpc_status_utils' 18 19# GRPC contains the General RPC module. 20module GRPC 21 # BadStatus is an exception class that indicates that an error occurred at 22 # either end of a GRPC connection. When raised, it indicates that a status 23 # error should be returned to the other end of a GRPC connection; when 24 # caught it means that this end received a status error. 25 # 26 # There is also subclass of BadStatus in this module for each GRPC status. 27 # E.g., the GRPC::Cancelled class corresponds to status CANCELLED. 28 # 29 # See 30 # https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/status.h 31 # for detailed descriptions of each status code. 32 class BadStatus < StandardError 33 attr_reader :code, :details, :metadata, :debug_error_string 34 35 include GRPC::Core::StatusCodes 36 37 # @param code [Numeric] the status code 38 # @param details [String] the details of the exception 39 # @param metadata [Hash] the error's metadata 40 def initialize(code, 41 details = 'unknown cause', 42 metadata = {}, 43 debug_error_string = nil) 44 exception_message = "#{code}:#{details}" 45 if debug_error_string 46 exception_message += ". debug_error_string:#{debug_error_string}" 47 end 48 super(exception_message) 49 @code = code 50 @details = details 51 @metadata = metadata 52 @debug_error_string = debug_error_string 53 end 54 55 # Converts the exception to a {Struct::Status} for use in the networking 56 # wrapper layer. 57 # 58 # @return [Struct::Status] with the same code and details 59 def to_status 60 Struct::Status.new(code, details, metadata, debug_error_string) 61 end 62 63 # Converts the exception to a deserialized {Google::Rpc::Status} object. 64 # Returns `nil` if the `grpc-status-details-bin` trailer could not be 65 # converted to a {Google::Rpc::Status} due to the server not providing 66 # the necessary trailers. 67 # 68 # @return [Google::Rpc::Status, nil] 69 def to_rpc_status 70 GoogleRpcStatusUtils.extract_google_rpc_status(to_status) 71 rescue Google::Protobuf::ParseError => parse_error 72 GRPC.logger.warn('parse error: to_rpc_status failed') 73 GRPC.logger.warn(parse_error) 74 nil 75 end 76 77 def self.new_status_exception(code, 78 details = 'unknown cause', 79 metadata = {}, 80 debug_error_string = nil) 81 codes = {} 82 codes[OK] = Ok 83 codes[CANCELLED] = Cancelled 84 codes[UNKNOWN] = Unknown 85 codes[INVALID_ARGUMENT] = InvalidArgument 86 codes[DEADLINE_EXCEEDED] = DeadlineExceeded 87 codes[NOT_FOUND] = NotFound 88 codes[ALREADY_EXISTS] = AlreadyExists 89 codes[PERMISSION_DENIED] = PermissionDenied 90 codes[UNAUTHENTICATED] = Unauthenticated 91 codes[RESOURCE_EXHAUSTED] = ResourceExhausted 92 codes[FAILED_PRECONDITION] = FailedPrecondition 93 codes[ABORTED] = Aborted 94 codes[OUT_OF_RANGE] = OutOfRange 95 codes[UNIMPLEMENTED] = Unimplemented 96 codes[INTERNAL] = Internal 97 codes[UNAVAILABLE] = Unavailable 98 codes[DATA_LOSS] = DataLoss 99 100 if codes[code].nil? 101 BadStatus.new(code, details, metadata, debug_error_string) 102 else 103 codes[code].new(details, metadata, debug_error_string) 104 end 105 end 106 end 107 108 # GRPC status code corresponding to status OK 109 class Ok < BadStatus 110 def initialize(details = 'unknown cause', 111 metadata = {}, 112 debug_error_string = nil) 113 super(Core::StatusCodes::OK, 114 details, metadata, debug_error_string) 115 end 116 end 117 118 # GRPC status code corresponding to status CANCELLED 119 class Cancelled < BadStatus 120 def initialize(details = 'unknown cause', 121 metadata = {}, 122 debug_error_string = nil) 123 super(Core::StatusCodes::CANCELLED, 124 details, metadata, debug_error_string) 125 end 126 end 127 128 # GRPC status code corresponding to status UNKNOWN 129 class Unknown < BadStatus 130 def initialize(details = 'unknown cause', 131 metadata = {}, 132 debug_error_string = nil) 133 super(Core::StatusCodes::UNKNOWN, 134 details, metadata, debug_error_string) 135 end 136 end 137 138 # GRPC status code corresponding to status INVALID_ARGUMENT 139 class InvalidArgument < BadStatus 140 def initialize(details = 'unknown cause', 141 metadata = {}, 142 debug_error_string = nil) 143 super(Core::StatusCodes::INVALID_ARGUMENT, 144 details, metadata, debug_error_string) 145 end 146 end 147 148 # GRPC status code corresponding to status DEADLINE_EXCEEDED 149 class DeadlineExceeded < BadStatus 150 def initialize(details = 'unknown cause', 151 metadata = {}, 152 debug_error_string = nil) 153 super(Core::StatusCodes::DEADLINE_EXCEEDED, 154 details, metadata, debug_error_string) 155 end 156 end 157 158 # GRPC status code corresponding to status NOT_FOUND 159 class NotFound < BadStatus 160 def initialize(details = 'unknown cause', 161 metadata = {}, 162 debug_error_string = nil) 163 super(Core::StatusCodes::NOT_FOUND, 164 details, metadata, debug_error_string) 165 end 166 end 167 168 # GRPC status code corresponding to status ALREADY_EXISTS 169 class AlreadyExists < BadStatus 170 def initialize(details = 'unknown cause', 171 metadata = {}, 172 debug_error_string = nil) 173 super(Core::StatusCodes::ALREADY_EXISTS, 174 details, metadata, debug_error_string) 175 end 176 end 177 178 # GRPC status code corresponding to status PERMISSION_DENIED 179 class PermissionDenied < BadStatus 180 def initialize(details = 'unknown cause', 181 metadata = {}, 182 debug_error_string = nil) 183 super(Core::StatusCodes::PERMISSION_DENIED, 184 details, metadata, debug_error_string) 185 end 186 end 187 188 # GRPC status code corresponding to status UNAUTHENTICATED 189 class Unauthenticated < BadStatus 190 def initialize(details = 'unknown cause', 191 metadata = {}, 192 debug_error_string = nil) 193 super(Core::StatusCodes::UNAUTHENTICATED, 194 details, metadata, debug_error_string) 195 end 196 end 197 198 # GRPC status code corresponding to status RESOURCE_EXHAUSTED 199 class ResourceExhausted < BadStatus 200 def initialize(details = 'unknown cause', 201 metadata = {}, 202 debug_error_string = nil) 203 super(Core::StatusCodes::RESOURCE_EXHAUSTED, 204 details, metadata, debug_error_string) 205 end 206 end 207 208 # GRPC status code corresponding to status FAILED_PRECONDITION 209 class FailedPrecondition < BadStatus 210 def initialize(details = 'unknown cause', 211 metadata = {}, 212 debug_error_string = nil) 213 super(Core::StatusCodes::FAILED_PRECONDITION, 214 details, metadata, debug_error_string) 215 end 216 end 217 218 # GRPC status code corresponding to status ABORTED 219 class Aborted < BadStatus 220 def initialize(details = 'unknown cause', 221 metadata = {}, 222 debug_error_string = nil) 223 super(Core::StatusCodes::ABORTED, 224 details, metadata, debug_error_string) 225 end 226 end 227 228 # GRPC status code corresponding to status OUT_OF_RANGE 229 class OutOfRange < BadStatus 230 def initialize(details = 'unknown cause', 231 metadata = {}, 232 debug_error_string = nil) 233 super(Core::StatusCodes::OUT_OF_RANGE, 234 details, metadata, debug_error_string) 235 end 236 end 237 238 # GRPC status code corresponding to status UNIMPLEMENTED 239 class Unimplemented < BadStatus 240 def initialize(details = 'unknown cause', 241 metadata = {}, 242 debug_error_string = nil) 243 super(Core::StatusCodes::UNIMPLEMENTED, 244 details, metadata, debug_error_string) 245 end 246 end 247 248 # GRPC status code corresponding to status INTERNAL 249 class Internal < BadStatus 250 def initialize(details = 'unknown cause', 251 metadata = {}, 252 debug_error_string = nil) 253 super(Core::StatusCodes::INTERNAL, 254 details, metadata, debug_error_string) 255 end 256 end 257 258 # GRPC status code corresponding to status UNAVAILABLE 259 class Unavailable < BadStatus 260 def initialize(details = 'unknown cause', 261 metadata = {}, 262 debug_error_string = nil) 263 super(Core::StatusCodes::UNAVAILABLE, 264 details, metadata, debug_error_string) 265 end 266 end 267 268 # GRPC status code corresponding to status DATA_LOSS 269 class DataLoss < BadStatus 270 def initialize(details = 'unknown cause', 271 metadata = {}, 272 debug_error_string = nil) 273 super(Core::StatusCodes::DATA_LOSS, 274 details, metadata, debug_error_string) 275 end 276 end 277end 278