github.com/profzone/eden-framework@v1.0.10/pkg/courier/status_error/status_error.go (about)

     1  package status_error
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"regexp"
     7  	"sort"
     8  	"strconv"
     9  )
    10  
    11  // code, key, msg, desc, canBeTalkError
    12  var RegexpStatusError = regexp.MustCompile(`@httpError\(([0-9]+),(.+),"(.+)?","(.+)?",(false|true)\);`)
    13  
    14  func NewStatusError(key string, code int64, msg string) *StatusError {
    15  	return &StatusError{
    16  		Key:  key,
    17  		Code: code,
    18  		Msg:  msg,
    19  	}
    20  }
    21  
    22  func ParseString(s string) *StatusError {
    23  	matched := RegexpStatusError.FindStringSubmatch(s)
    24  	if len(matched) != 6 {
    25  		return nil
    26  	}
    27  
    28  	code, _ := strconv.ParseInt(matched[1], 10, 64)
    29  	canBeTalkErr, _ := strconv.ParseBool(matched[5])
    30  
    31  	return &StatusError{
    32  		Code:           code,
    33  		Key:            matched[2],
    34  		Msg:            matched[3],
    35  		Desc:           matched[4],
    36  		CanBeErrorTalk: canBeTalkErr,
    37  	}
    38  }
    39  
    40  func FromError(err error) *StatusError {
    41  	if err == nil {
    42  		return nil
    43  	}
    44  
    45  	if statusErrCode, ok := err.(StatusErrorCode); ok {
    46  		return statusErrCode.StatusError()
    47  	}
    48  
    49  	if statusError, ok := err.(*StatusError); ok {
    50  		return statusError
    51  	}
    52  
    53  	return UnknownError.StatusError().WithDesc(err.Error())
    54  }
    55  
    56  func (statusErr *StatusError) String() string {
    57  	return fmt.Sprintf(`@httpError(%d,%s,"%s","%s",%v);`, statusErr.Code, statusErr.Key, statusErr.Msg, statusErr.Desc, statusErr.CanBeErrorTalk)
    58  }
    59  
    60  type StatusError struct {
    61  	// 错误 Key
    62  	Key string `json:"key" xml:"key"`
    63  	// 错误代码
    64  	Code int64 `json:"code" xml:"code"`
    65  	// 错误信息
    66  	Msg string `json:"msg" xml:"msg"`
    67  	// 详细描述
    68  	Desc string `json:"desc" xml:"desc"`
    69  	// 是否能作为错误话术
    70  	CanBeErrorTalk bool `json:"canBeTalkError" xml:"canBeTalkError"`
    71  	// 错误溯源
    72  	Source []string `json:"source" xml:"source"`
    73  	// 请求 ID
    74  	ID string `json:"id" xml:"id"`
    75  	// 出错字段
    76  	ErrorFields ErrorFields `json:"errorFields" xml:"errorFields"`
    77  }
    78  
    79  func (statusErr *StatusError) Is(err error) bool {
    80  	return FromError(statusErr).Code == statusErr.Code
    81  }
    82  
    83  func (statusErr *StatusError) Error() string {
    84  	return fmt.Sprintf("%v[%s][%d][%s%s] %s", statusErr.Source, statusErr.Key, statusErr.Code, statusErr.Msg, statusErr.ErrorFields, statusErr.Desc)
    85  }
    86  
    87  func (statusErr *StatusError) Status() int {
    88  	strCode := fmt.Sprintf("%d", statusErr.Code)
    89  	if len(strCode) < 3 {
    90  		return 0
    91  	}
    92  	status, _ := strconv.Atoi(strCode[:3])
    93  	return status
    94  }
    95  
    96  // deprecated
    97  func (statusErr *StatusError) HttpCode() int {
    98  	return statusErr.Status()
    99  }
   100  
   101  func (statusErr StatusError) WithErrTalk() *StatusError {
   102  	statusErr.CanBeErrorTalk = true
   103  	return &statusErr
   104  }
   105  
   106  func (statusErr StatusError) WithMsg(msg string) *StatusError {
   107  	statusErr.Msg = msg
   108  	return &statusErr
   109  }
   110  
   111  func (statusErr StatusError) WithoutErrTalk() *StatusError {
   112  	statusErr.CanBeErrorTalk = false
   113  	return &statusErr
   114  }
   115  
   116  func (statusErr StatusError) WithDesc(desc string) *StatusError {
   117  	statusErr.Desc = desc
   118  	return &statusErr
   119  }
   120  
   121  func (statusErr StatusError) WithID(id string) *StatusError {
   122  	statusErr.ID = id
   123  	return &statusErr
   124  }
   125  
   126  func (statusErr StatusError) WithSource(sourceName string) *StatusError {
   127  	length := len(statusErr.Source)
   128  	if length == 0 || statusErr.Source[length-1] != sourceName {
   129  		statusErr.Source = append(statusErr.Source, sourceName)
   130  	}
   131  	return &statusErr
   132  }
   133  
   134  func (statusErr StatusError) WithErrorField(in string, field string, msg string) *StatusError {
   135  	statusErr.ErrorFields = append(statusErr.ErrorFields, NewErrorField(in, field, msg))
   136  	return &statusErr
   137  }
   138  
   139  func (statusErr StatusError) WithErrorFields(errorFields ...*ErrorField) *StatusError {
   140  	statusErr.ErrorFields = append(statusErr.ErrorFields, errorFields...)
   141  	return &statusErr
   142  }
   143  
   144  func NewErrorField(in string, field string, msg string) *ErrorField {
   145  	return &ErrorField{
   146  		In:    in,
   147  		Field: field,
   148  		Msg:   msg,
   149  	}
   150  }
   151  
   152  type ErrorField struct {
   153  	// 出错字段路径
   154  	// 这个信息为一个 json 字符串,方便客户端进行定位错误原因
   155  	// 例如输入中 {"name":{ "alias" : "test"}} 中的alias出错,则返回 "name.alias"
   156  	// 如果alias是数组, 且第2个元素的a字段错误,则返回"name.alias[2].a"
   157  	Field string `json:"field" xml:"field"`
   158  	// 错误信息
   159  	Msg string `json:"msg" xml:"msg"`
   160  	// 错误字段位置
   161  	// body, query, header, path, formData
   162  	In string `json:"in" xml:"in"`
   163  }
   164  
   165  func (s ErrorField) String() string {
   166  	return "[" + s.In + "]" + s.Field + " " + s.Msg
   167  }
   168  
   169  type ErrorFields []*ErrorField
   170  
   171  func (fields ErrorFields) String() string {
   172  	if len(fields) == 0 {
   173  		return ""
   174  	}
   175  	buf := &bytes.Buffer{}
   176  	buf.WriteString("<")
   177  	for _, f := range fields {
   178  		buf.WriteString(f.String())
   179  	}
   180  	buf.WriteString(">")
   181  	return buf.String()
   182  }
   183  
   184  func (fields ErrorFields) Sort() ErrorFields {
   185  	sort.Sort(fields)
   186  	return fields
   187  }
   188  
   189  func (fields ErrorFields) Len() int {
   190  	return len(fields)
   191  }
   192  func (fields ErrorFields) Swap(i, j int) {
   193  	fields[i], fields[j] = fields[j], fields[i]
   194  }
   195  func (fields ErrorFields) Less(i, j int) bool {
   196  	return fields[i].Field < fields[j].Field
   197  }