Compare commits
	
		
			5 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 655d4daad9 | |||
| 87a004e577 | |||
| 376c6cab50 | |||
| 4a3f25baa0 | |||
| aa33bc8df3 | 
| @@ -7,6 +7,9 @@ type SyncSet[TData comparable] struct { | |||||||
| 	lock sync.Mutex | 	lock sync.Mutex | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Add adds `value` to the set | ||||||
|  | // returns true  if the value was actually inserted | ||||||
|  | // returns false if the value already existed | ||||||
| func (s *SyncSet[TData]) Add(value TData) bool { | func (s *SyncSet[TData]) Add(value TData) bool { | ||||||
| 	s.lock.Lock() | 	s.lock.Lock() | ||||||
| 	defer s.lock.Unlock() | 	defer s.lock.Unlock() | ||||||
| @@ -15,10 +18,10 @@ func (s *SyncSet[TData]) Add(value TData) bool { | |||||||
| 		s.data = make(map[TData]bool) | 		s.data = make(map[TData]bool) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	_, ok := s.data[value] | 	_, existsInPreState := s.data[value] | ||||||
| 	s.data[value] = true | 	s.data[value] = true | ||||||
|  |  | ||||||
| 	return !ok | 	return !existsInPreState | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *SyncSet[TData]) AddAll(values []TData) { | func (s *SyncSet[TData]) AddAll(values []TData) { | ||||||
|   | |||||||
| @@ -270,8 +270,12 @@ func (b *Builder) Any(key string, val any) *Builder { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (b *Builder) Stringer(key string, val fmt.Stringer) *Builder { | func (b *Builder) Stringer(key string, val fmt.Stringer) *Builder { | ||||||
|  | 	if val == nil { | ||||||
|  | 		return b.addMeta(key, MDTString, "(!nil)") | ||||||
|  | 	} else { | ||||||
| 		return b.addMeta(key, MDTString, val.String()) | 		return b.addMeta(key, MDTString, val.String()) | ||||||
| 	} | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| func (b *Builder) Stack() *Builder { | func (b *Builder) Stack() *Builder { | ||||||
| 	return b.addMeta("@Stack", MDTString, string(debug.Stack())) | 	return b.addMeta("@Stack", MDTString, string(debug.Stack())) | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ func FromError(err error) *ExErr { | |||||||
| 		StatusCode:     nil, | 		StatusCode:     nil, | ||||||
| 		Message:        err.Error(), | 		Message:        err.Error(), | ||||||
| 		WrappedErrType: fmt.Sprintf("%T", err), | 		WrappedErrType: fmt.Sprintf("%T", err), | ||||||
|  | 		WrappedErr:     err, | ||||||
| 		Caller:         "", | 		Caller:         "", | ||||||
| 		OriginalError:  nil, | 		OriginalError:  nil, | ||||||
| 		Meta:           getForeignMeta(err), | 		Meta:           getForeignMeta(err), | ||||||
| @@ -43,6 +44,7 @@ func newExErr(cat ErrorCategory, errtype ErrorType, msg string) *ExErr { | |||||||
| 		StatusCode:     nil, | 		StatusCode:     nil, | ||||||
| 		Message:        msg, | 		Message:        msg, | ||||||
| 		WrappedErrType: "", | 		WrappedErrType: "", | ||||||
|  | 		WrappedErr:     nil, | ||||||
| 		Caller:         callername(2), | 		Caller:         callername(2), | ||||||
| 		OriginalError:  nil, | 		OriginalError:  nil, | ||||||
| 		Meta:           make(map[string]MetaValue), | 		Meta:           make(map[string]MetaValue), | ||||||
| @@ -59,6 +61,7 @@ func wrapExErr(e *ExErr, msg string, cat ErrorCategory, stacktraceskip int) *ExE | |||||||
| 		StatusCode:     e.StatusCode, | 		StatusCode:     e.StatusCode, | ||||||
| 		Message:        msg, | 		Message:        msg, | ||||||
| 		WrappedErrType: "", | 		WrappedErrType: "", | ||||||
|  | 		WrappedErr:     nil, | ||||||
| 		Caller:         callername(1 + stacktraceskip), | 		Caller:         callername(1 + stacktraceskip), | ||||||
| 		OriginalError:  e, | 		OriginalError:  e, | ||||||
| 		Meta:           make(map[string]MetaValue), | 		Meta:           make(map[string]MetaValue), | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package exerr | package exerr | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"gogs.mikescher.com/BlackForestBytes/goext/dataext" | ||||||
| 	"gogs.mikescher.com/BlackForestBytes/goext/langext" | 	"gogs.mikescher.com/BlackForestBytes/goext/langext" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -37,25 +38,32 @@ type ErrorType struct { | |||||||
|  |  | ||||||
| //goland:noinspection GoUnusedGlobalVariable | //goland:noinspection GoUnusedGlobalVariable | ||||||
| var ( | var ( | ||||||
| 	TypeInternal       = ErrorType{"INTERNAL_ERROR", langext.Ptr(500)} | 	TypeInternal       = NewType("INTERNAL_ERROR", langext.Ptr(500)) | ||||||
| 	TypePanic          = ErrorType{"PANIC", langext.Ptr(500)} | 	TypePanic          = NewType("PANIC", langext.Ptr(500)) | ||||||
| 	TypeNotImplemented = ErrorType{"NOT_IMPLEMENTED", langext.Ptr(500)} | 	TypeNotImplemented = NewType("NOT_IMPLEMENTED", langext.Ptr(500)) | ||||||
|  |  | ||||||
| 	TypeWrap = ErrorType{"Wrap", nil} | 	TypeWrap = NewType("Wrap", nil) | ||||||
|  |  | ||||||
| 	TypeBindFailURI      = ErrorType{"BINDFAIL_URI", langext.Ptr(400)} | 	TypeBindFailURI      = NewType("BINDFAIL_URI", langext.Ptr(400)) | ||||||
| 	TypeBindFailQuery    = ErrorType{"BINDFAIL_QUERY", langext.Ptr(400)} | 	TypeBindFailQuery    = NewType("BINDFAIL_QUERY", langext.Ptr(400)) | ||||||
| 	TypeBindFailJSON     = ErrorType{"BINDFAIL_JSON", langext.Ptr(400)} | 	TypeBindFailJSON     = NewType("BINDFAIL_JSON", langext.Ptr(400)) | ||||||
| 	TypeBindFailFormData = ErrorType{"BINDFAIL_FORMDATA", langext.Ptr(400)} | 	TypeBindFailFormData = NewType("BINDFAIL_FORMDATA", langext.Ptr(400)) | ||||||
| 	TypeBindFailHeader   = ErrorType{"BINDFAIL_HEADER", langext.Ptr(400)} | 	TypeBindFailHeader   = NewType("BINDFAIL_HEADER", langext.Ptr(400)) | ||||||
|  |  | ||||||
| 	TypeUnauthorized = ErrorType{"UNAUTHORIZED", langext.Ptr(401)} | 	TypeUnauthorized = NewType("UNAUTHORIZED", langext.Ptr(401)) | ||||||
| 	TypeAuthFailed   = ErrorType{"AUTH_FAILED", langext.Ptr(401)} | 	TypeAuthFailed   = NewType("AUTH_FAILED", langext.Ptr(401)) | ||||||
|  |  | ||||||
| 	// other values come from pkgconfig | 	// other values come from pkgconfig | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | var registeredTypes = dataext.SyncSet[string]{} | ||||||
|  |  | ||||||
| func NewType(key string, defStatusCode *int) ErrorType { | func NewType(key string, defStatusCode *int) ErrorType { | ||||||
|  | 	insertOkay := registeredTypes.Add(key) | ||||||
|  | 	if !insertOkay { | ||||||
|  | 		panic("Cannot register same ErrType ('" + key + "') more than once") | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return ErrorType{key, defStatusCode} | 	return ErrorType{key, defStatusCode} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import ( | |||||||
| 	"github.com/rs/xid" | 	"github.com/rs/xid" | ||||||
| 	"github.com/rs/zerolog" | 	"github.com/rs/zerolog" | ||||||
| 	"gogs.mikescher.com/BlackForestBytes/goext/langext" | 	"gogs.mikescher.com/BlackForestBytes/goext/langext" | ||||||
|  | 	"reflect" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
| @@ -20,6 +21,7 @@ type ExErr struct { | |||||||
|  |  | ||||||
| 	Message        string `json:"message"` | 	Message        string `json:"message"` | ||||||
| 	WrappedErrType string `json:"wrappedErrType"` | 	WrappedErrType string `json:"wrappedErrType"` | ||||||
|  | 	WrappedErr     any    `json:"-"` | ||||||
| 	Caller         string `json:"caller"` | 	Caller         string `json:"caller"` | ||||||
|  |  | ||||||
| 	OriginalError *ExErr `json:"originalError"` | 	OriginalError *ExErr `json:"originalError"` | ||||||
| @@ -33,6 +35,9 @@ func (ee *ExErr) Error() string { | |||||||
|  |  | ||||||
| // Unwrap must be implemented so that some error.XXX methods work | // Unwrap must be implemented so that some error.XXX methods work | ||||||
| func (ee *ExErr) Unwrap() error { | func (ee *ExErr) Unwrap() error { | ||||||
|  | 	if ee.OriginalError == nil { | ||||||
|  | 		return nil // this is neccessary - otherwise we return a wrapped nil and the `x == nil` comparison fails (= panic in errors.Is and other failures) | ||||||
|  | 	} | ||||||
| 	return ee.OriginalError | 	return ee.OriginalError | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -44,17 +49,29 @@ func (ee *ExErr) Is(e error) bool { | |||||||
| // As must be implemented so that error.As(x) works | // As must be implemented so that error.As(x) works | ||||||
| // | // | ||||||
| //goland:noinspection GoTypeAssertionOnErrors | //goland:noinspection GoTypeAssertionOnErrors | ||||||
| func (ee *ExErr) As(e any) bool { | func (ee *ExErr) As(target any) bool { | ||||||
| 	if dstErr, ok := e.(*ExErr); ok { | 	if dstErr, ok := target.(*ExErr); ok { | ||||||
|  |  | ||||||
| 		if dst0, ok := ee.contains(dstErr); ok { | 		if dst0, ok := ee.contains(dstErr); ok { | ||||||
| 			dstErr = dst0 | 			dstErr = dst0 | ||||||
| 			return true | 			return true | ||||||
| 		} else { | 		} else { | ||||||
| 			return false | 			return false | ||||||
| 		} | 		} | ||||||
| 	} else if dstErr, ok := e.(error); ok { |  | ||||||
| 		return IsFrom(ee, dstErr) |  | ||||||
| 	} else { | 	} else { | ||||||
|  |  | ||||||
|  | 		val := reflect.ValueOf(target) | ||||||
|  |  | ||||||
|  | 		typStr := val.Type().Elem().String() | ||||||
|  |  | ||||||
|  | 		for curr := ee; curr != nil; curr = curr.OriginalError { | ||||||
|  | 			if curr.Category == CatForeign && curr.WrappedErrType == typStr && curr.WrappedErr != nil { | ||||||
|  | 				val.Elem().Set(reflect.ValueOf(curr.WrappedErr)) | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										93
									
								
								exerr/exerr_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								exerr/exerr_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | |||||||
|  | package exerr | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"gogs.mikescher.com/BlackForestBytes/goext/tst" | ||||||
|  | 	"testing" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type golangErr struct { | ||||||
|  | 	Message string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (g golangErr) Error() string { | ||||||
|  | 	return g.Message | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type golangErr2 struct { | ||||||
|  | 	Message string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (g golangErr2) Error() string { | ||||||
|  | 	return g.Message | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type simpleError struct { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (g simpleError) Error() string { | ||||||
|  | 	return "Something simple went wroong" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type simpleError2 struct { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (g simpleError2) Error() string { | ||||||
|  | 	return "Something simple went wroong" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestExErrIs1(t *testing.T) { | ||||||
|  | 	e0 := simpleError{} | ||||||
|  |  | ||||||
|  | 	wrap := Wrap(e0, "something went wrong").Str("test", "123").Build() | ||||||
|  |  | ||||||
|  | 	tst.AssertTrue(t, errors.Is(wrap, simpleError{})) | ||||||
|  | 	tst.AssertFalse(t, errors.Is(wrap, golangErr{})) | ||||||
|  | 	tst.AssertFalse(t, errors.Is(wrap, golangErr{"error1"})) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestExErrIs2(t *testing.T) { | ||||||
|  | 	e0 := golangErr{"error1"} | ||||||
|  |  | ||||||
|  | 	wrap := Wrap(e0, "something went wrong").Str("test", "123").Build() | ||||||
|  |  | ||||||
|  | 	tst.AssertTrue(t, errors.Is(wrap, e0)) | ||||||
|  | 	tst.AssertTrue(t, errors.Is(wrap, golangErr{"error1"})) | ||||||
|  | 	tst.AssertFalse(t, errors.Is(wrap, golangErr{"error2"})) | ||||||
|  | 	tst.AssertFalse(t, errors.Is(wrap, simpleError{})) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestExErrAs(t *testing.T) { | ||||||
|  |  | ||||||
|  | 	e0 := golangErr{"error1"} | ||||||
|  |  | ||||||
|  | 	w0 := Wrap(e0, "something went wrong").Str("test", "123").Build() | ||||||
|  |  | ||||||
|  | 	{ | ||||||
|  | 		out := golangErr{} | ||||||
|  | 		ok := errors.As(w0, &out) | ||||||
|  | 		tst.AssertTrue(t, ok) | ||||||
|  | 		tst.AssertEqual(t, out.Message, "error1") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	w1 := Wrap(w0, "outher error").Build() | ||||||
|  |  | ||||||
|  | 	{ | ||||||
|  | 		out := golangErr{} | ||||||
|  | 		ok := errors.As(w1, &out) | ||||||
|  | 		tst.AssertTrue(t, ok) | ||||||
|  | 		tst.AssertEqual(t, out.Message, "error1") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	{ | ||||||
|  | 		out := golangErr2{} | ||||||
|  | 		ok := errors.As(w1, &out) | ||||||
|  | 		tst.AssertFalse(t, ok) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	{ | ||||||
|  | 		out := simpleError2{} | ||||||
|  | 		ok := errors.As(w1, &out) | ||||||
|  | 		tst.AssertFalse(t, ok) | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -5,10 +5,8 @@ import ( | |||||||
| 	"gogs.mikescher.com/BlackForestBytes/goext/dataext" | 	"gogs.mikescher.com/BlackForestBytes/goext/dataext" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func BodyBuffer() gin.HandlerFunc { | func BodyBuffer(g *gin.Context) { | ||||||
| 	return func(g *gin.Context) { |  | ||||||
| 	if g.Request.Body != nil { | 	if g.Request.Body != nil { | ||||||
| 		g.Request.Body = dataext.NewBufferedReadCloser(g.Request.Body) | 		g.Request.Body = dataext.NewBufferedReadCloser(g.Request.Body) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| } |  | ||||||
|   | |||||||
| @@ -112,8 +112,8 @@ func (w *GinRouteBuilder) Use(middleware ...gin.HandlerFunc) *GinRouteBuilder { | |||||||
| func (w *GinRouteBuilder) Handle(handler WHandlerFunc) { | func (w *GinRouteBuilder) Handle(handler WHandlerFunc) { | ||||||
|  |  | ||||||
| 	if w.routes.wrapper.bufferBody { | 	if w.routes.wrapper.bufferBody { | ||||||
| 		arr := make([]gin.HandlerFunc, len(w.handlers)+1) | 		arr := make([]gin.HandlerFunc, 0, len(w.handlers)+1) | ||||||
| 		arr = append(arr, BodyBuffer()) | 		arr = append(arr, BodyBuffer) | ||||||
| 		arr = append(arr, w.handlers...) | 		arr = append(arr, w.handlers...) | ||||||
| 		w.handlers = arr | 		w.handlers = arr | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| package goext | package goext | ||||||
|  |  | ||||||
| const GoextVersion = "0.0.224" | const GoextVersion = "0.0.229" | ||||||
|  |  | ||||||
| const GoextVersionTimestamp = "2023-08-08T12:38:22+0200" | const GoextVersionTimestamp = "2023-08-08T16:05:44+0200" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user