package exerr import ( "encoding/json" "fmt" "github.com/rs/zerolog/log" "gogs.mikescher.com/BlackForestBytes/goext/enums" "gogs.mikescher.com/BlackForestBytes/goext/langext" "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 + "<>" } 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} } } } type EnumWrap struct { Type string ValueString string ValueRaw enums.Enum // `ValueRaw` is lost during serialization roundtrip IsNil bool } func newEnumWrap(val enums.Enum) EnumWrap { t := fmt.Sprintf("%T", val) arr := strings.Split(t, ".") if len(arr) > 0 { t = arr[len(arr)-1] } if langext.IsNil(val) { return EnumWrap{Type: t, ValueString: "", ValueRaw: val, IsNil: true} } if enumstr, ok := val.(enums.StringEnum); ok { return EnumWrap{Type: t, ValueString: enumstr.String(), ValueRaw: val, IsNil: false} } return EnumWrap{Type: t, ValueString: fmt.Sprintf("%v", val), ValueRaw: val, IsNil: false} } func (w EnumWrap) Serialize() string { if w.IsNil { return "!nil" + ":" + w.Type } return w.Type + ":" + w.ValueString } func (w EnumWrap) String() string { if w.IsNil { return w.Type + "<>" } return "[" + w.Type + "] " + w.ValueString } func deserializeEnumWrap(v string) EnumWrap { r := strings.SplitN(v, ":", 2) if len(r) == 2 && r[0] == "!nil" { return EnumWrap{Type: r[1], ValueString: v, ValueRaw: nil, IsNil: true} } if len(r) == 0 { return EnumWrap{} } else if len(r) == 1 { return EnumWrap{Type: "", ValueString: v, ValueRaw: nil, IsNil: false} } else { return EnumWrap{Type: r[0], ValueString: r[1], ValueRaw: nil, IsNil: false} } }