| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | /* | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright 2017 gRPC authors. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Package status implements errors returned by gRPC.  These errors are | 
					
						
							|  |  |  | // serialized and transmitted on the wire between server and client, and allow | 
					
						
							|  |  |  | // for additional data to be transmitted via the Details field in the status | 
					
						
							|  |  |  | // proto.  gRPC service handlers should return an error created by this | 
					
						
							|  |  |  | // package, and gRPC clients should expect a corresponding error to be | 
					
						
							|  |  |  | // returned from the RPC call. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // This package upholds the invariants that a non-nil error may not | 
					
						
							|  |  |  | // contain an OK code, and an OK code must result in a nil error. | 
					
						
							|  |  |  | package status | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spb "google.golang.org/genproto/googleapis/rpc/status" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"google.golang.org/grpc/codes" | 
					
						
							|  |  |  | 	"google.golang.org/grpc/internal/status" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Status references google.golang.org/grpc/internal/status. It represents an | 
					
						
							|  |  |  | // RPC status code, message, and details.  It is immutable and should be | 
					
						
							|  |  |  | // created with New, Newf, or FromProto. | 
					
						
							|  |  |  | // https://godoc.org/google.golang.org/grpc/internal/status | 
					
						
							|  |  |  | type Status = status.Status | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // New returns a Status representing c and msg. | 
					
						
							|  |  |  | func New(c codes.Code, msg string) *Status { | 
					
						
							|  |  |  | 	return status.New(c, msg) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Newf returns New(c, fmt.Sprintf(format, a...)). | 
					
						
							|  |  |  | func Newf(c codes.Code, format string, a ...interface{}) *Status { | 
					
						
							|  |  |  | 	return New(c, fmt.Sprintf(format, a...)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Error returns an error representing c and msg.  If c is OK, returns nil. | 
					
						
							|  |  |  | func Error(c codes.Code, msg string) error { | 
					
						
							|  |  |  | 	return New(c, msg).Err() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Errorf returns Error(c, fmt.Sprintf(format, a...)). | 
					
						
							|  |  |  | func Errorf(c codes.Code, format string, a ...interface{}) error { | 
					
						
							|  |  |  | 	return Error(c, fmt.Sprintf(format, a...)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ErrorProto returns an error representing s.  If s.Code is OK, returns nil. | 
					
						
							|  |  |  | func ErrorProto(s *spb.Status) error { | 
					
						
							|  |  |  | 	return FromProto(s).Err() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // FromProto returns a Status representing s. | 
					
						
							|  |  |  | func FromProto(s *spb.Status) *Status { | 
					
						
							|  |  |  | 	return status.FromProto(s) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // FromError returns a Status representation of err. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //   - If err was produced by this package or implements the method `GRPCStatus() | 
					
						
							| 
									
										
										
										
											2023-09-07 13:20:37 +02:00
										 |  |  | //     *Status` and `GRPCStatus()` does not return nil, or if err wraps a type | 
					
						
							|  |  |  | //     satisfying this, the Status from `GRPCStatus()` is returned.  For wrapped | 
					
						
							|  |  |  | //     errors, the message returned contains the entire err.Error() text and not | 
					
						
							|  |  |  | //     just the wrapped status. In that case, ok is true. | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2023-09-07 13:20:37 +02:00
										 |  |  | //   - If err is nil, a Status is returned with codes.OK and no message, and ok | 
					
						
							|  |  |  | //     is true. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //   - If err implements the method `GRPCStatus() *Status` and `GRPCStatus()` | 
					
						
							|  |  |  | //     returns nil (which maps to Codes.OK), or if err wraps a type | 
					
						
							|  |  |  | //     satisfying this, a Status is returned with codes.Unknown and err's | 
					
						
							|  |  |  | //     Error() message, and ok is false. | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | // | 
					
						
							|  |  |  | //   - Otherwise, err is an error not compatible with this package.  In this | 
					
						
							|  |  |  | //     case, a Status is returned with codes.Unknown and err's Error() message, | 
					
						
							|  |  |  | //     and ok is false. | 
					
						
							|  |  |  | func FromError(err error) (s *Status, ok bool) { | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		return nil, true | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | 	type grpcstatus interface{ GRPCStatus() *Status } | 
					
						
							|  |  |  | 	if gs, ok := err.(grpcstatus); ok { | 
					
						
							| 
									
										
										
										
											2023-09-07 13:20:37 +02:00
										 |  |  | 		if gs.GRPCStatus() == nil { | 
					
						
							|  |  |  | 			// Error has status nil, which maps to codes.OK. There | 
					
						
							|  |  |  | 			// is no sensible behavior for this, so we turn it into | 
					
						
							|  |  |  | 			// an error with codes.Unknown and discard the existing | 
					
						
							|  |  |  | 			// status. | 
					
						
							|  |  |  | 			return New(codes.Unknown, err.Error()), false | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | 		return gs.GRPCStatus(), true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var gs grpcstatus | 
					
						
							|  |  |  | 	if errors.As(err, &gs) { | 
					
						
							| 
									
										
										
										
											2023-09-07 13:20:37 +02:00
										 |  |  | 		if gs.GRPCStatus() == nil { | 
					
						
							|  |  |  | 			// Error wraps an error that has status nil, which maps | 
					
						
							|  |  |  | 			// to codes.OK.  There is no sensible behavior for this, | 
					
						
							|  |  |  | 			// so we turn it into an error with codes.Unknown and | 
					
						
							|  |  |  | 			// discard the existing status. | 
					
						
							|  |  |  | 			return New(codes.Unknown, err.Error()), false | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | 		p := gs.GRPCStatus().Proto() | 
					
						
							|  |  |  | 		p.Message = err.Error() | 
					
						
							|  |  |  | 		return status.FromProto(p), true | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return New(codes.Unknown, err.Error()), false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Convert is a convenience function which removes the need to handle the | 
					
						
							|  |  |  | // boolean return value from FromError. | 
					
						
							|  |  |  | func Convert(err error) *Status { | 
					
						
							|  |  |  | 	s, _ := FromError(err) | 
					
						
							|  |  |  | 	return s | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | // Code returns the Code of the error if it is a Status error or if it wraps a | 
					
						
							|  |  |  | // Status error. If that is not the case, it returns codes.OK if err is nil, or | 
					
						
							|  |  |  | // codes.Unknown otherwise. | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | func Code(err error) codes.Code { | 
					
						
							|  |  |  | 	// Don't use FromError to avoid allocation of OK status. | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		return codes.OK | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-06-05 10:15:05 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return Convert(err).Code() | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // FromContextError converts a context error or wrapped context error into a | 
					
						
							|  |  |  | // Status.  It returns a Status with codes.OK if err is nil, or a Status with | 
					
						
							|  |  |  | // codes.Unknown if err is non-nil and not a context error. | 
					
						
							|  |  |  | func FromContextError(err error) *Status { | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if errors.Is(err, context.DeadlineExceeded) { | 
					
						
							|  |  |  | 		return New(codes.DeadlineExceeded, err.Error()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if errors.Is(err, context.Canceled) { | 
					
						
							|  |  |  | 		return New(codes.Canceled, err.Error()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return New(codes.Unknown, err.Error()) | 
					
						
							|  |  |  | } |