Files
aleesa-webapp-go/vendor/github.com/cockroachdb/errors/errbase/decode.go
2024-09-17 23:59:38 +03:00

207 lines
6.9 KiB
Go

// Copyright 2019 The Cockroach 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 errbase
import (
"context"
"github.com/cockroachdb/errors/errorspb"
"github.com/gogo/protobuf/proto"
"github.com/gogo/protobuf/types"
)
// DecodeError decodes an error.
//
// Can only be called if the EncodedError is set (see IsSet()).
func DecodeError(ctx context.Context, enc EncodedError) error {
if w := enc.GetWrapper(); w != nil {
return decodeWrapper(ctx, w)
}
return decodeLeaf(ctx, enc.GetLeaf())
}
func decodeLeaf(ctx context.Context, enc *errorspb.EncodedErrorLeaf) error {
// In case there is a detailed payload, decode it.
var payload proto.Message
if enc.Details.FullDetails != nil {
var d types.DynamicAny
err := types.UnmarshalAny(enc.Details.FullDetails, &d)
if err != nil {
// It's OK if we can't decode. We'll use
// the opaque type below.
warningFn(ctx, "error while unmarshalling error: %+v", err)
} else {
payload = d.Message
}
}
// Do we have a leaf decoder for this type?
typeKey := TypeKey(enc.Details.ErrorTypeMark.FamilyName)
if decoder, ok := leafDecoders[typeKey]; ok {
// Yes, use it.
genErr := decoder(ctx, enc.Message, enc.Details.ReportablePayload, payload)
if genErr != nil {
// Decoding succeeded. Use this.
return genErr
}
// Decoding failed, we'll drop through to opaqueLeaf{} below.
} else if decoder, ok := multiCauseDecoders[typeKey]; ok {
causes := make([]error, len(enc.MultierrorCauses))
for i, e := range enc.MultierrorCauses {
causes[i] = DecodeError(ctx, *e)
}
genErr := decoder(ctx, causes, enc.Message, enc.Details.ReportablePayload, payload)
if genErr != nil {
return genErr
}
} else {
// Shortcut for non-registered proto-encodable error types:
// if it already implements `error`, it's good to go.
if e, ok := payload.(error); ok {
// yes: we're done!
return e
}
}
if len(enc.MultierrorCauses) > 0 {
causes := make([]error, len(enc.MultierrorCauses))
for i, e := range enc.MultierrorCauses {
causes[i] = DecodeError(ctx, *e)
}
leaf := &opaqueLeafCauses{
causes: causes,
}
leaf.msg = enc.Message
leaf.details = enc.Details
return leaf
}
// No decoder and no error type: we'll keep what we received and
// make it ready to re-encode exactly (if the error leaves over the
// network again).
return &opaqueLeaf{
msg: enc.Message,
details: enc.Details,
}
}
func decodeWrapper(ctx context.Context, enc *errorspb.EncodedWrapper) error {
// First decode the cause.
cause := DecodeError(ctx, enc.Cause)
// In case there is a detailed payload, decode it.
var payload proto.Message
if enc.Details.FullDetails != nil {
var d types.DynamicAny
err := types.UnmarshalAny(enc.Details.FullDetails, &d)
if err != nil {
// It's OK if we can't decode. We'll use
// the opaque type below.
warningFn(ctx, "error while unmarshalling wrapper error: %+v", err)
} else {
payload = d.Message
}
}
// Do we have a wrapper decoder for this?
typeKey := TypeKey(enc.Details.ErrorTypeMark.FamilyName)
if decoder, ok := decoders[typeKey]; ok {
// Yes, use it.
genErr := decoder(ctx, cause, enc.Message, enc.Details.ReportablePayload, payload)
if genErr != nil {
// Decoding succeeded. Use this.
return genErr
}
// Decoding failed, we'll drop through to opaqueWrapper{} below.
}
// Otherwise, preserve all details about the original object.
return &opaqueWrapper{
cause: cause,
prefix: enc.Message,
details: enc.Details,
messageType: MessageType(enc.MessageType),
}
}
// RegisterLeafDecoder can be used to register new leaf error types to
// the library. Registered types will be decoded using their own
// Go type when an error is decoded. Wrappers that have not been
// registered will be decoded using the opaqueLeaf type.
//
// Note: if the error type has been migrated from a previous location
// or a different type, ensure that RegisterTypeMigration() was called
// prior to RegisterLeafDecoder().
func RegisterLeafDecoder(theType TypeKey, decoder LeafDecoder) {
if decoder == nil {
delete(leafDecoders, theType)
} else {
leafDecoders[theType] = decoder
}
}
// LeafDecoder is to be provided (via RegisterLeafDecoder above)
// by additional wrapper types not yet known to this library.
// A nil return indicates that decoding was not successful.
type LeafDecoder = func(ctx context.Context, msg string, safeDetails []string, payload proto.Message) error
// registry for RegisterLeafDecoder.
var leafDecoders = map[TypeKey]LeafDecoder{}
// RegisterWrapperDecoder can be used to register new wrapper types to
// the library. Registered wrappers will be decoded using their own
// Go type when an error is decoded. Wrappers that have not been
// registered will be decoded using the opaqueWrapper type.
//
// Note: if the error type has been migrated from a previous location
// or a different type, ensure that RegisterTypeMigration() was called
// prior to RegisterWrapperDecoder().
func RegisterWrapperDecoder(theType TypeKey, decoder WrapperDecoder) {
if decoder == nil {
delete(decoders, theType)
} else {
decoders[theType] = decoder
}
}
// WrapperDecoder is to be provided (via RegisterWrapperDecoder above)
// by additional wrapper types not yet known to this library.
// A nil return indicates that decoding was not successful.
type WrapperDecoder = func(ctx context.Context, cause error, msgPrefix string, safeDetails []string, payload proto.Message) error
// registry for RegisterWrapperType.
var decoders = map[TypeKey]WrapperDecoder{}
// MultiCauseDecoder is to be provided (via RegisterMultiCauseDecoder
// above) by additional multi-cause wrapper types not yet known by the
// library. A nil return indicates that decoding was not successful.
type MultiCauseDecoder = func(ctx context.Context, causes []error, msgPrefix string, safeDetails []string, payload proto.Message) error
// registry for RegisterMultiCauseDecoder.
var multiCauseDecoders = map[TypeKey]MultiCauseDecoder{}
// RegisterMultiCauseDecoder can be used to register new multi-cause
// wrapper types to the library. Registered wrappers will be decoded
// using their own Go type when an error is decoded. Multi-cause
// wrappers that have not been registered will be decoded using the
// opaqueWrapper type.
func RegisterMultiCauseDecoder(theType TypeKey, decoder MultiCauseDecoder) {
if decoder == nil {
delete(multiCauseDecoders, theType)
} else {
multiCauseDecoders[theType] = decoder
}
}