parent
7e21c39e86
commit
109f8f79e4
@ -0,0 +1,118 @@
|
|||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
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:
|
||||||
|
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
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package errors
|
||||||
|
|
||||||
|
type Username string
|
||||||
|
type Method string
|
||||||
|
type Message string
|
||||||
|
type Kind uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
Other Kind = iota // Unknown error or something that doesn't fit other categories
|
||||||
|
Internal // Internal error that should not be shown to user
|
||||||
|
Invalid // Operation is not permitted for this type of item
|
||||||
|
Permission // Permission denied
|
||||||
|
IO // External IO error
|
||||||
|
Conflict // The item already exists
|
||||||
|
NotFound // The item does not exist
|
||||||
|
Malformed // The request format is not valid
|
||||||
|
)
|
||||||
|
|
||||||
|
func (k Kind) String() string {
|
||||||
|
switch k {
|
||||||
|
case Other:
|
||||||
|
return "other error"
|
||||||
|
case Internal:
|
||||||
|
return "internal error"
|
||||||
|
case Invalid:
|
||||||
|
return "invalid operation"
|
||||||
|
case Permission:
|
||||||
|
return "permission denied"
|
||||||
|
case IO:
|
||||||
|
return "I/O error"
|
||||||
|
case Conflict:
|
||||||
|
return "item already exists"
|
||||||
|
case NotFound:
|
||||||
|
return "item does not exist"
|
||||||
|
case Malformed:
|
||||||
|
return "malformed request"
|
||||||
|
}
|
||||||
|
return "unknown type"
|
||||||
|
}
|
||||||
Loading…
Reference in new issue