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