mirror of
https://github.com/yusing/godoxy.git
synced 2026-03-26 11:01:07 +01:00
fixes, meaningful error messages and new features
This commit is contained in:
194
src/go-proxy/error.go
Normal file
194
src/go-proxy/error.go
Normal file
@@ -0,0 +1,194 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type NestedError struct {
|
||||
subject string
|
||||
message string
|
||||
extras []string
|
||||
inner *NestedError
|
||||
level int
|
||||
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
type NestedErrorLike interface {
|
||||
Error() string
|
||||
Inner() NestedErrorLike
|
||||
Level() int
|
||||
HasInner() bool
|
||||
HasExtras() bool
|
||||
|
||||
Extra(string) NestedErrorLike
|
||||
Extraf(string, ...any) NestedErrorLike
|
||||
ExtraError(error) NestedErrorLike
|
||||
Subject(string) NestedErrorLike
|
||||
Subjectf(string, ...any) NestedErrorLike
|
||||
With(error) NestedErrorLike
|
||||
|
||||
addLevel(int) NestedErrorLike
|
||||
copy() *NestedError
|
||||
}
|
||||
|
||||
func NewNestedError(message string) NestedErrorLike {
|
||||
return &NestedError{message: message, extras: make([]string, 0)}
|
||||
}
|
||||
|
||||
func NewNestedErrorf(format string, args ...any) NestedErrorLike {
|
||||
return NewNestedError(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func NewNestedErrorFrom(err error) NestedErrorLike {
|
||||
if err == nil {
|
||||
panic("cannot convert nil error to NestedError")
|
||||
}
|
||||
return NewNestedError(err.Error())
|
||||
}
|
||||
|
||||
func (ne *NestedError) Extra(s string) NestedErrorLike {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return ne
|
||||
}
|
||||
ne.Lock()
|
||||
defer ne.Unlock()
|
||||
ne.extras = append(ne.extras, s)
|
||||
return ne
|
||||
}
|
||||
|
||||
func (ne *NestedError) Extraf(format string, args ...any) NestedErrorLike {
|
||||
return ne.Extra(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (ne *NestedError) ExtraError(e error) NestedErrorLike {
|
||||
switch t := e.(type) {
|
||||
case NestedErrorLike:
|
||||
extra := t.copy()
|
||||
extra.addLevel(ne.Level() + 1)
|
||||
e = extra
|
||||
}
|
||||
return ne.Extra(e.Error())
|
||||
}
|
||||
|
||||
func (ne *NestedError) Subject(s string) NestedErrorLike {
|
||||
ne.subject = s
|
||||
return ne
|
||||
}
|
||||
|
||||
func (ne *NestedError) Subjectf(format string, args ...any) NestedErrorLike {
|
||||
ne.subject = fmt.Sprintf(format, args...)
|
||||
return ne
|
||||
}
|
||||
|
||||
func (ne *NestedError) Inner() NestedErrorLike {
|
||||
return ne.inner
|
||||
}
|
||||
|
||||
func (ne *NestedError) Level() int {
|
||||
return ne.level
|
||||
}
|
||||
|
||||
func (ef *NestedError) Error() string {
|
||||
var buf strings.Builder
|
||||
ef.writeToSB(&buf, "")
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (ef *NestedError) HasInner() bool {
|
||||
return ef.inner != nil
|
||||
}
|
||||
|
||||
func (ef *NestedError) HasExtras() bool {
|
||||
return len(ef.extras) > 0
|
||||
}
|
||||
|
||||
func (ef *NestedError) With(inner error) NestedErrorLike {
|
||||
ef.Lock()
|
||||
defer ef.Unlock()
|
||||
|
||||
var in *NestedError
|
||||
|
||||
switch t := inner.(type) {
|
||||
case NestedErrorLike:
|
||||
in = t.copy()
|
||||
default:
|
||||
in = &NestedError{extras: []string{t.Error()}}
|
||||
}
|
||||
if ef.inner == nil {
|
||||
ef.inner = in
|
||||
} else {
|
||||
ef.inner.ExtraError(in)
|
||||
}
|
||||
root := ef
|
||||
for root.inner != nil {
|
||||
root.inner.level = root.level + 1
|
||||
root = root.inner
|
||||
}
|
||||
return ef
|
||||
}
|
||||
|
||||
func (ef *NestedError) addLevel(level int) NestedErrorLike {
|
||||
ef.level += level
|
||||
if ef.inner != nil {
|
||||
ef.inner.addLevel(level)
|
||||
}
|
||||
return ef
|
||||
}
|
||||
|
||||
func (ef *NestedError) copy() *NestedError {
|
||||
var inner *NestedError
|
||||
if ef.inner != nil {
|
||||
inner = ef.inner.copy()
|
||||
}
|
||||
return &NestedError{
|
||||
subject: ef.subject,
|
||||
message: ef.message,
|
||||
extras: ef.extras,
|
||||
inner: inner,
|
||||
level: ef.level,
|
||||
}
|
||||
}
|
||||
|
||||
func (ef *NestedError) writeIndents(sb *strings.Builder, level int) {
|
||||
for i := 0; i < level; i++ {
|
||||
sb.WriteString(" ")
|
||||
}
|
||||
}
|
||||
|
||||
func (ef *NestedError) writeToSB(sb *strings.Builder, prefix string) {
|
||||
ef.writeIndents(sb, ef.level)
|
||||
sb.WriteString(prefix)
|
||||
|
||||
if ef.subject != "" {
|
||||
sb.WriteRune('"')
|
||||
sb.WriteString(ef.subject)
|
||||
sb.WriteRune('"')
|
||||
if ef.message != "" {
|
||||
sb.WriteString(":\n")
|
||||
} else {
|
||||
sb.WriteRune('\n')
|
||||
}
|
||||
}
|
||||
if ef.message != "" {
|
||||
ef.writeIndents(sb, ef.level)
|
||||
sb.WriteString(ef.message)
|
||||
sb.WriteRune('\n')
|
||||
}
|
||||
for _, l := range ef.extras {
|
||||
l = strings.TrimSpace(l)
|
||||
if l == "" {
|
||||
continue
|
||||
}
|
||||
ef.writeIndents(sb, ef.level)
|
||||
sb.WriteString("- ")
|
||||
sb.WriteString(l)
|
||||
sb.WriteRune('\n')
|
||||
}
|
||||
if ef.inner != nil {
|
||||
ef.inner.writeToSB(sb, "- ")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user