You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
125 lines
2.4 KiB
125 lines
2.4 KiB
package errors
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"log"
|
|
)
|
|
|
|
var (
|
|
_ error = (*Error)(nil)
|
|
)
|
|
|
|
type Error struct {
|
|
// The kind of error
|
|
Kind Kind `json:"kind"`
|
|
// The method or function being invoked
|
|
Method Method `json:"method"`
|
|
// The username of the user attempting the operation
|
|
Username Username `json:"username"`
|
|
// The error message
|
|
Message Message `json:"message"`
|
|
// Nested Error
|
|
Err error `json:"err"`
|
|
}
|
|
|
|
func E(args ...interface{}) error {
|
|
if len(args) == 0 {
|
|
return nil
|
|
}
|
|
e := &Error{}
|
|
for _, arg := range args {
|
|
switch arg := arg.(type) {
|
|
case Kind:
|
|
e.Kind = arg
|
|
case Method:
|
|
e.Method = arg
|
|
case Username:
|
|
e.Username = arg
|
|
case Message:
|
|
e.Message = arg
|
|
case string:
|
|
if e.Message == "" {
|
|
e.Message = Message(arg)
|
|
}
|
|
case *Error:
|
|
copy := *arg
|
|
e.Err = ©
|
|
case error:
|
|
e.Err = arg
|
|
default:
|
|
log.Println(args)
|
|
return Errorf("unknown type %T with value %v in error call", arg, arg)
|
|
}
|
|
}
|
|
return e
|
|
}
|
|
|
|
func (e *Error) isZero() bool {
|
|
return e.Method == "" && e.Username == "" && e.Message == "" && e.Kind == 0 && e.Err == nil
|
|
}
|
|
|
|
// pad appends str to the buffer if the buffer already has some data.
|
|
func pad(b *bytes.Buffer, str string) {
|
|
if b.Len() == 0 {
|
|
return
|
|
}
|
|
b.WriteString(str)
|
|
}
|
|
|
|
func (e *Error) Error() string {
|
|
b := new(bytes.Buffer)
|
|
if e.Method != "" {
|
|
b.WriteString(string(e.Method))
|
|
}
|
|
if e.Username != "" {
|
|
pad(b, ": ")
|
|
b.WriteString(string(e.Username))
|
|
}
|
|
if e.Kind != 0 {
|
|
pad(b, ": ")
|
|
b.WriteString(e.Kind.String())
|
|
}
|
|
if e.Message != "" {
|
|
pad(b, ": ")
|
|
b.WriteString(string(e.Message))
|
|
}
|
|
if e.Err != nil {
|
|
// Indent to new line if it is another Error
|
|
if prevErr, ok := e.Err.(*Error); ok {
|
|
if !prevErr.isZero() {
|
|
pad(b, ":\n\t")
|
|
b.WriteString(string(e.Err.Error()))
|
|
}
|
|
} else { // Just print it out if a standard error
|
|
pad(b, ": ")
|
|
b.WriteString(string(e.Err.Error()))
|
|
}
|
|
}
|
|
if b.Len() == 0 {
|
|
return "no error message"
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
// Errorf is a wrapper that calls E with just a message formatted with the args
|
|
// this allows for only importing this library for all error handling
|
|
func Errorf(f string, args ...interface{}) error {
|
|
return E(fmt.Sprintf(f, args...))
|
|
}
|
|
|
|
// Returns True if err is of type Error and of the given Kind
|
|
func Is(k Kind, err error) bool {
|
|
e, ok := err.(*Error)
|
|
if !ok {
|
|
return false
|
|
}
|
|
if e.Kind != Other {
|
|
return e.Kind == k
|
|
}
|
|
if e.Err != nil {
|
|
return Is(k, e.Err)
|
|
}
|
|
return false
|
|
}
|