github.com/cloudwego/kitex@v0.9.0/pkg/remote/trans_errors.go (about)

     1  /*
     2   * Copyright 2021 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package remote
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  
    23  	"github.com/cloudwego/kitex/pkg/kerrors"
    24  )
    25  
    26  // corresponding with thrift TApplicationException, cannot change it
    27  const (
    28  	UnknownApplicationException = 0
    29  	UnknownMethod               = 1
    30  	InvalidMessageTypeException = 2
    31  	WrongMethodName             = 3
    32  	BadSequenceID               = 4
    33  	MissingResult               = 5
    34  	InternalError               = 6
    35  	ProtocolError               = 7
    36  	InvalidTransform            = 8
    37  	InvalidProtocol             = 9
    38  	UnsupportedClientType       = 10
    39  	// kitex's own type id from number 20
    40  	UnknownService = 20
    41  	NoServiceName  = 21
    42  )
    43  
    44  var defaultTransErrorMessage = map[int32]string{
    45  	UnknownApplicationException: "unknown application exception",
    46  	UnknownMethod:               "unknown method",
    47  	InvalidMessageTypeException: "invalid message type",
    48  	WrongMethodName:             "wrong method name",
    49  	BadSequenceID:               "bad sequence ID",
    50  	MissingResult:               "missing result",
    51  	InternalError:               "unknown internal error",
    52  	ProtocolError:               "unknown protocol error",
    53  	InvalidTransform:            "Invalid transform",
    54  	InvalidProtocol:             "Invalid protocol",
    55  	UnsupportedClientType:       "Unsupported client type",
    56  	UnknownService:              "unknown service",
    57  }
    58  
    59  // TransError is the error that can be transmitted, it corresponds to TApplicationException in Thrift
    60  type TransError struct {
    61  	message string
    62  	typeID  int32
    63  	rawErr  error
    64  }
    65  
    66  // Error implements the error interface.
    67  func (e TransError) Error() string {
    68  	if e.message != "" {
    69  		return e.message
    70  	}
    71  	return defaultTransErrorMessage[e.typeID]
    72  }
    73  
    74  // TypeID return err type id
    75  func (e TransError) TypeID() int32 {
    76  	return e.typeID
    77  }
    78  
    79  // Unwrap the transError to expose raw error
    80  func (e TransError) Unwrap() error {
    81  	return e.rawErr
    82  }
    83  
    84  // Is to check if inner error that transError wrap is target error
    85  func (e TransError) Is(target error) bool {
    86  	return e == target || errors.Is(e.rawErr, target)
    87  }
    88  
    89  // AppendMessage append extra msg for TransError
    90  func (e TransError) AppendMessage(extraMsg string) *TransError {
    91  	if extraMsg == "" {
    92  		return &e
    93  	}
    94  	msg := fmt.Sprintf("%s %s", e.message, extraMsg)
    95  	// should not modify origin error
    96  	return &TransError{message: msg, typeID: e.typeID, rawErr: e.rawErr}
    97  }
    98  
    99  // NewTransErrorWithMsg to build TransError with typeID and errMsg
   100  func NewTransErrorWithMsg(typeID int32, message string) *TransError {
   101  	return &TransError{message: message, typeID: typeID}
   102  }
   103  
   104  // NewTransError to build TransError with typeID and rawErr.
   105  // rawErr can be used by errors.Is(target) to check err type, like read timeout.
   106  func NewTransError(typeID int32, err error) *TransError {
   107  	if e, ok := err.(*TransError); ok {
   108  		return e
   109  	}
   110  	// biz error should add biz info which is convenient to be recognized by client side
   111  	var dErr *kerrors.DetailedError
   112  	if errors.As(err, &dErr) && dErr.Is(kerrors.ErrBiz) {
   113  		if e, ok := dErr.Unwrap().(*TransError); ok {
   114  			e = e.AppendMessage(fmt.Sprintf("[%s]", kerrors.ErrBiz.Error()))
   115  			return e
   116  		}
   117  	}
   118  	if typeID == InternalError {
   119  		// try to get more specific err type if typeID is InternalError
   120  		if tID, ok := err.(TypeId); ok {
   121  			typeID = tID.TypeId()
   122  		} else if tID, ok := err.(TypeID); ok {
   123  			typeID = tID.TypeID()
   124  		}
   125  	}
   126  	return &TransError{message: err.Error(), typeID: typeID, rawErr: err}
   127  }
   128  
   129  // TypeId is used to assert Error with has 'TypeID() int32'
   130  type TypeID interface {
   131  	TypeID() int32
   132  }
   133  
   134  // TypeId is used to assert Error with has 'TypeId() int32' like TApplicationException
   135  type TypeId interface {
   136  	TypeId() int32
   137  }