go.sdls.io/sin@v0.0.9/pkg/sin/errors.go (about) 1 // Copyright 2014 Manu Martinez-Almeida. All rights reserved. 2 // Use of this source code is governed by a MIT style 3 // license that can be found in the LICENSE file. 4 5 package sin 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "reflect" 11 "strconv" 12 "strings" 13 ) 14 15 // ErrorType is an unsigned 64-bit error code as defined in the gin spec. 16 type ErrorType uint64 17 18 const ( 19 // ErrorTypeBind is used when Context.Bind() fails. 20 ErrorTypeBind ErrorType = 1 << 63 21 // ErrorTypeRender is used when Context.Render() fails. 22 ErrorTypeRender ErrorType = 1 << 62 23 // ErrorTypePrivate indicates a private error. 24 ErrorTypePrivate ErrorType = 1 << 0 25 // ErrorTypePublic indicates a public error. 26 ErrorTypePublic ErrorType = 1 << 1 27 // ErrorTypeAny indicates any other error. 28 ErrorTypeAny ErrorType = 1<<64 - 1 29 // ErrorTypeNu indicates any other error. 30 ErrorTypeNu = 2 31 ) 32 33 // Error represents a error's specification. 34 type Error struct { 35 Err error 36 Meta interface{} 37 Type ErrorType 38 } 39 40 type errorMsgs []*Error 41 42 var _ error = &Error{} 43 44 // SetType sets the error's type. 45 func (msg *Error) SetType(flags ErrorType) *Error { 46 msg.Type = flags 47 return msg 48 } 49 50 // SetMeta sets the error's meta data. 51 func (msg *Error) SetMeta(data interface{}) *Error { 52 msg.Meta = data 53 return msg 54 } 55 56 // JSON creates a properly formatted JSON 57 func (msg *Error) JSON() interface{} { 58 jsonData := H{} 59 if msg.Meta != nil { 60 value := reflect.ValueOf(msg.Meta) 61 switch value.Kind() { 62 case reflect.Struct: 63 return msg.Meta 64 case reflect.Map: 65 for _, key := range value.MapKeys() { 66 jsonData[key.String()] = value.MapIndex(key).Interface() 67 } 68 default: 69 jsonData["meta"] = msg.Meta 70 } 71 } 72 if _, ok := jsonData["error"]; !ok { 73 jsonData["error"] = msg.Error() 74 } 75 return jsonData 76 } 77 78 // MarshalJSON implements the json.Marshaller interface. 79 func (msg *Error) MarshalJSON() ([]byte, error) { 80 return json.Marshal(msg.JSON()) 81 } 82 83 // Error implements the error interface. 84 func (msg Error) Error() string { 85 return msg.Err.Error() 86 } 87 88 // IsType judges one error. 89 func (msg *Error) IsType(flags ErrorType) bool { 90 return (msg.Type & flags) > 0 91 } 92 93 // Unwrap returns the wrapped error, to allow interoperability with errors.Is(), errors.As() and errors.Unwrap() 94 func (msg *Error) Unwrap() error { 95 return msg.Err 96 } 97 98 // ByType returns a readonly copy filtered the byte. 99 // ie ByType(gin.ErrorTypePublic) returns a slice of errors with type=ErrorTypePublic. 100 func (a errorMsgs) ByType(typ ErrorType) errorMsgs { 101 if len(a) == 0 { 102 return nil 103 } 104 if typ == ErrorTypeAny { 105 return a 106 } 107 var result errorMsgs 108 for _, msg := range a { 109 if msg.IsType(typ) { 110 result = append(result, msg) 111 } 112 } 113 return result 114 } 115 116 // Last returns the last error in the slice. It returns nil if the array is empty. 117 // Shortcut for errors[len(errors)-1]. 118 func (a errorMsgs) Last() *Error { 119 if length := len(a); length > 0 { 120 return a[length-1] 121 } 122 return nil 123 } 124 125 // Errors returns an array will all the error messages. 126 // Example: 127 // c.Error(errors.New("first")) 128 // c.Error(errors.New("second")) 129 // c.Error(errors.New("third")) 130 // c.Errors.Errors() // == []string{"first", "second", "third"} 131 func (a errorMsgs) Errors() []string { 132 if len(a) == 0 { 133 return nil 134 } 135 errorStrings := make([]string, len(a)) 136 for i, err := range a { 137 errorStrings[i] = err.Error() 138 } 139 return errorStrings 140 } 141 142 func (a errorMsgs) JSON() interface{} { 143 switch length := len(a); length { 144 case 0: 145 return nil 146 case 1: 147 return a.Last().JSON() 148 default: 149 jsonData := make([]interface{}, length) 150 for i, err := range a { 151 jsonData[i] = err.JSON() 152 } 153 return jsonData 154 } 155 } 156 157 // MarshalJSON implements the json.Marshaller interface. 158 func (a errorMsgs) MarshalJSON() ([]byte, error) { 159 return json.Marshal(a.JSON()) 160 } 161 162 func (a errorMsgs) String() string { 163 if len(a) == 0 { 164 return "" 165 } 166 167 var buffer strings.Builder 168 for i, msg := range a { 169 buffer.WriteString("Error #") 170 if i < 9 { 171 buffer.WriteRune('0') 172 } 173 buffer.WriteString(strconv.FormatInt(int64(i+1), 10)) 174 buffer.WriteString(": ") 175 buffer.WriteString(msg.Err.Error()) 176 buffer.WriteRune('\n') 177 178 if msg.Meta != nil { 179 _, _ = fmt.Fprintf(&buffer, " Meta: %v\n", msg.Meta) 180 } 181 } 182 183 return buffer.String() 184 }