134 lines
2.9 KiB
Go
134 lines
2.9 KiB
Go
|
package exerr
|
||
|
|
||
|
import (
|
||
|
"bringman.de/common/shared/langext"
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"github.com/rs/zerolog/log"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
//
|
||
|
// These are wrapper objects, because for some metadata-types we need to serialize a bit more complex data
|
||
|
// (eg thy actual type for ID objects, or the json representation for any types)
|
||
|
//
|
||
|
|
||
|
type IDWrap struct {
|
||
|
Type string
|
||
|
Value string
|
||
|
IsNil bool
|
||
|
}
|
||
|
|
||
|
func newIDWrap(val fmt.Stringer) IDWrap {
|
||
|
t := fmt.Sprintf("%T", val)
|
||
|
arr := strings.Split(t, ".")
|
||
|
if len(arr) > 0 {
|
||
|
t = arr[len(arr)-1]
|
||
|
}
|
||
|
|
||
|
if langext.IsNil(val) {
|
||
|
return IDWrap{Type: t, Value: "", IsNil: true}
|
||
|
}
|
||
|
|
||
|
v := val.String()
|
||
|
return IDWrap{Type: t, Value: v, IsNil: false}
|
||
|
}
|
||
|
|
||
|
func (w IDWrap) Serialize() string {
|
||
|
if w.IsNil {
|
||
|
return "!nil" + ":" + w.Type
|
||
|
}
|
||
|
return w.Type + ":" + w.Value
|
||
|
}
|
||
|
|
||
|
func (w IDWrap) String() string {
|
||
|
if w.IsNil {
|
||
|
return w.Type + "<<nil>>"
|
||
|
}
|
||
|
return w.Type + "(" + w.Value + ")"
|
||
|
}
|
||
|
|
||
|
func deserializeIDWrap(v string) IDWrap {
|
||
|
r := strings.SplitN(v, ":", 2)
|
||
|
|
||
|
if len(r) == 2 && r[0] == "!nil" {
|
||
|
return IDWrap{Type: r[1], Value: v, IsNil: true}
|
||
|
}
|
||
|
|
||
|
if len(r) == 0 {
|
||
|
return IDWrap{}
|
||
|
} else if len(r) == 1 {
|
||
|
return IDWrap{Type: "", Value: v, IsNil: false}
|
||
|
} else {
|
||
|
return IDWrap{Type: r[0], Value: r[1], IsNil: false}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type AnyWrap struct {
|
||
|
Type string
|
||
|
Json string
|
||
|
IsError bool
|
||
|
IsNil bool
|
||
|
}
|
||
|
|
||
|
func newAnyWrap(val any) (result AnyWrap) {
|
||
|
result = AnyWrap{Type: "", Json: "", IsError: true, IsNil: false} // ensure a return in case of recover()
|
||
|
|
||
|
defer func() {
|
||
|
if err := recover(); err != nil {
|
||
|
// send error should never crash our program
|
||
|
log.Error().Interface("err", err).Msg("Panic while trying to marshal anywrap ( bmerror.Interface )")
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
t := fmt.Sprintf("%T", val)
|
||
|
|
||
|
if langext.IsNil(val) {
|
||
|
return AnyWrap{Type: t, Json: "", IsError: false, IsNil: true}
|
||
|
}
|
||
|
|
||
|
j, err := json.Marshal(val)
|
||
|
if err == nil {
|
||
|
return AnyWrap{Type: t, Json: string(j), IsError: false, IsNil: false}
|
||
|
} else {
|
||
|
return AnyWrap{Type: t, Json: "", IsError: true, IsNil: false}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (w AnyWrap) Serialize() string {
|
||
|
if w.IsError {
|
||
|
return "ERR" + ":" + w.Type + ":" + w.Json
|
||
|
} else if w.IsNil {
|
||
|
return "NIL" + ":" + w.Type + ":" + w.Json
|
||
|
} else {
|
||
|
return "OK" + ":" + w.Type + ":" + w.Json
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (w AnyWrap) String() string {
|
||
|
if w.IsError {
|
||
|
return "(error)"
|
||
|
} else if w.IsNil {
|
||
|
return "(nil)"
|
||
|
} else {
|
||
|
return w.Json
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func deserializeAnyWrap(v string) AnyWrap {
|
||
|
r := strings.SplitN(v, ":", 3)
|
||
|
if len(r) != 3 {
|
||
|
return AnyWrap{IsError: true, Type: "", Json: "", IsNil: false}
|
||
|
} else {
|
||
|
if r[0] == "OK" {
|
||
|
return AnyWrap{IsError: false, Type: r[1], Json: r[2], IsNil: false}
|
||
|
} else if r[0] == "ERR" {
|
||
|
return AnyWrap{IsError: true, Type: r[1], Json: r[2], IsNil: false}
|
||
|
} else if r[0] == "NIL" {
|
||
|
return AnyWrap{IsError: false, Type: r[1], Json: "", IsNil: true}
|
||
|
} else {
|
||
|
return AnyWrap{IsError: true, Type: "", Json: "", IsNil: false}
|
||
|
}
|
||
|
}
|
||
|
}
|