finalize session management

This commit is contained in:
Sky Johnson 2025-04-10 14:27:50 -05:00
parent 8c134774ee
commit 50f4cb91f6

View File

@ -139,33 +139,26 @@ func (s *Session) SizePlain() (size int) {
// ID // ID
size += bstd.SizeString(s.ID) size += bstd.SizeString(s.ID)
// Data (map of string to any) // Data map
// For simplicity, we store data as binary-encoded strings size += bstd.SizeMap(s.Data, bstd.SizeString, func(v any) int {
// This is a simplification, in a real-world scenario you would handle return sizeAny(v)
// different types differently })
dataAsStrings := make(map[string]string)
for k, v := range s.Data {
dataAsStrings[k] = toString(v)
}
size += bstd.SizeMap(dataAsStrings, bstd.SizeString, bstd.SizeString)
// Time fields // Time fields stored as int64 Unix timestamps
size += bstd.SizeInt64() * 4 // Store Unix timestamps for all time fields size += bstd.SizeInt64() * 4
return size return size
} }
// MarshalPlain serializes the session to binary // MarshalPlain serializes the session to binary
func (s *Session) MarshalPlain(n int, b []byte) (int, error) { func (s *Session) MarshalPlain(n int, b []byte) int {
// ID // ID
n = bstd.MarshalString(n, b, s.ID) n = bstd.MarshalString(n, b, s.ID)
// Data // Data map
dataAsStrings := make(map[string]string) n = bstd.MarshalMap(n, b, s.Data, bstd.MarshalString, func(n int, b []byte, v any) int {
for k, v := range s.Data { return marshalAny(n, b, v)
dataAsStrings[k] = toString(v) })
}
n = bstd.MarshalMap(n, b, dataAsStrings, bstd.MarshalString, bstd.MarshalString)
// Time fields as Unix timestamps // Time fields as Unix timestamps
n = bstd.MarshalInt64(n, b, s.CreatedAt.Unix()) n = bstd.MarshalInt64(n, b, s.CreatedAt.Unix())
@ -173,7 +166,7 @@ func (s *Session) MarshalPlain(n int, b []byte) (int, error) {
n = bstd.MarshalInt64(n, b, s.LastUsed.Unix()) n = bstd.MarshalInt64(n, b, s.LastUsed.Unix())
n = bstd.MarshalInt64(n, b, s.Expiry.Unix()) n = bstd.MarshalInt64(n, b, s.Expiry.Unix())
return n, nil return n
} }
// UnmarshalPlain deserializes the session from binary // UnmarshalPlain deserializes the session from binary
@ -186,44 +179,35 @@ func (s *Session) UnmarshalPlain(n int, b []byte) (int, error) {
return n, err return n, err
} }
// Data // Data map
var dataAsStrings map[string]string n, s.Data, err = bstd.UnmarshalMap[string, any](n, b, bstd.UnmarshalString, func(n int, b []byte) (int, any, error) {
n, dataAsStrings, err = bstd.UnmarshalMap[string, string](n, b, bstd.UnmarshalString, bstd.UnmarshalString) return unmarshalAny(n, b)
})
if err != nil { if err != nil {
return n, err return n, err
} }
// Convert string data back to original types // Time fields as Unix timestamps
s.Data = make(map[string]any, len(dataAsStrings))
for k, v := range dataAsStrings {
s.Data[k] = fromString(v)
}
// Time fields
var timestamp int64 var timestamp int64
// CreatedAt
n, timestamp, err = bstd.UnmarshalInt64(n, b) n, timestamp, err = bstd.UnmarshalInt64(n, b)
if err != nil { if err != nil {
return n, err return n, err
} }
s.CreatedAt = time.Unix(timestamp, 0) s.CreatedAt = time.Unix(timestamp, 0)
// UpdatedAt
n, timestamp, err = bstd.UnmarshalInt64(n, b) n, timestamp, err = bstd.UnmarshalInt64(n, b)
if err != nil { if err != nil {
return n, err return n, err
} }
s.UpdatedAt = time.Unix(timestamp, 0) s.UpdatedAt = time.Unix(timestamp, 0)
// LastUsed
n, timestamp, err = bstd.UnmarshalInt64(n, b) n, timestamp, err = bstd.UnmarshalInt64(n, b)
if err != nil { if err != nil {
return n, err return n, err
} }
s.LastUsed = time.Unix(timestamp, 0) s.LastUsed = time.Unix(timestamp, 0)
// Expiry
n, timestamp, err = bstd.UnmarshalInt64(n, b) n, timestamp, err = bstd.UnmarshalInt64(n, b)
if err != nil { if err != nil {
return n, err return n, err
@ -238,8 +222,7 @@ func (s *Session) Marshal() ([]byte, error) {
size := s.SizePlain() size := s.SizePlain()
data, err := bufPool.Marshal(size, func(b []byte) (n int) { data, err := bufPool.Marshal(size, func(b []byte) (n int) {
n, _ = s.MarshalPlain(0, b) return s.MarshalPlain(0, b)
return n
}) })
if err != nil { if err != nil {
@ -260,52 +243,108 @@ func Unmarshal(data []byte) (*Session, error) {
return session, nil return session, nil
} }
// Helper functions to convert between any and string // Type identifiers for any values
// In a production environment, you would use a more robust serialization method for the map values const (
func toString(v any) string { typeNull byte = 0
typeString byte = 1
typeInt byte = 2
typeFloat byte = 3
typeBool byte = 4
typeBytes byte = 5
)
// sizeAny calculates the size needed for any value
func sizeAny(v any) int {
if v == nil { if v == nil {
return "" return 1 // Just the type byte
} }
switch t := v.(type) {
// 1 byte for type + size of the value
switch val := v.(type) {
case string: case string:
return t return 1 + bstd.SizeString(val)
case []byte:
return string(t)
case int: case int:
return "i:" + string(rune(t)) return 1 + bstd.SizeInt64()
case int64:
return 1 + bstd.SizeInt64()
case float64:
return 1 + bstd.SizeFloat64()
case bool: case bool:
if t { return 1 + bstd.SizeBool()
return "b:t" case []byte:
} return 1 + bstd.SizeBytes(val)
return "b:f"
default: default:
return "u:" // unknown type // Convert unhandled types to string
return 1 + bstd.SizeString("unknown")
} }
} }
func fromString(s string) any { // marshalAny serializes any value
if s == "" { func marshalAny(n int, b []byte, v any) int {
return nil if v == nil {
} b[n] = typeNull
if len(s) < 2 { return n + 1
return s
} }
prefix := s[:2] switch val := v.(type) {
switch prefix { case string:
case "i:": b[n] = typeString
if len(s) > 2 { return bstd.MarshalString(n+1, b, val)
return int(rune(s[2])) case int:
} b[n] = typeInt
return 0 return bstd.MarshalInt64(n+1, b, int64(val))
case "b:": case int64:
if len(s) > 2 && s[2] == 't' { b[n] = typeInt
return true return bstd.MarshalInt64(n+1, b, val)
} case float64:
return false b[n] = typeFloat
case "u:": return bstd.MarshalFloat64(n+1, b, val)
return nil case bool:
b[n] = typeBool
return bstd.MarshalBool(n+1, b, val)
case []byte:
b[n] = typeBytes
return bstd.MarshalBytes(n+1, b, val)
default: default:
return s // Convert unhandled types to string
b[n] = typeString
return bstd.MarshalString(n+1, b, "unknown")
}
}
// unmarshalAny deserializes any value
func unmarshalAny(n int, b []byte) (int, any, error) {
if len(b) <= n {
return n, nil, benc.ErrBufTooSmall
}
typeId := b[n]
n++
switch typeId {
case typeNull:
return n, nil, nil
case typeString:
return bstd.UnmarshalString(n, b)
case typeInt:
var val int64
var err error
n, val, err = bstd.UnmarshalInt64(n, b)
return n, val, err
case typeFloat:
var val float64
var err error
n, val, err = bstd.UnmarshalFloat64(n, b)
return n, val, err
case typeBool:
var val bool
var err error
n, val, err = bstd.UnmarshalBool(n, b)
return n, val, err
case typeBytes:
return bstd.UnmarshalBytesCopied(n, b)
default:
// Unknown type, return nil
return n, nil, nil
} }
} }