2024-10-16 20:43:34 +00:00
|
|
|
package session
|
2024-10-08 17:48:28 +00:00
|
|
|
|
|
|
|
|
import (
|
2024-10-09 14:57:51 +00:00
|
|
|
"fmt"
|
2024-10-08 17:48:28 +00:00
|
|
|
"github.com/maddalax/htmgo/framework/h"
|
|
|
|
|
"github.com/puzpuzpuz/xsync/v3"
|
|
|
|
|
)
|
|
|
|
|
|
2024-10-16 20:43:34 +00:00
|
|
|
type Id string
|
2024-10-08 17:48:28 +00:00
|
|
|
|
2024-10-16 20:43:34 +00:00
|
|
|
var cache = xsync.NewMapOf[Id, *xsync.MapOf[string, any]]()
|
2024-10-08 17:48:28 +00:00
|
|
|
|
|
|
|
|
type State struct {
|
2024-10-16 20:43:34 +00:00
|
|
|
SessionId Id
|
2024-10-08 17:48:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewState(ctx *h.RequestContext) *State {
|
|
|
|
|
id := GetSessionId(ctx)
|
|
|
|
|
cache.Store(id, xsync.NewMapOf[string, any]())
|
|
|
|
|
return &State{
|
|
|
|
|
SessionId: id,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-04 15:34:20 +00:00
|
|
|
func CreateSession(ctx *h.RequestContext) Id {
|
|
|
|
|
sessionId := fmt.Sprintf("session-id-%s", h.GenId(30))
|
|
|
|
|
ctx.Set("session-id", sessionId)
|
|
|
|
|
return Id(sessionId)
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-16 20:43:34 +00:00
|
|
|
func GetSessionId(ctx *h.RequestContext) Id {
|
2024-10-09 14:57:51 +00:00
|
|
|
sessionIdRaw := ctx.Get("session-id")
|
2024-10-08 17:48:28 +00:00
|
|
|
sessionId := ""
|
|
|
|
|
|
2024-10-09 14:57:51 +00:00
|
|
|
if sessionIdRaw == "" || sessionIdRaw == nil {
|
2024-11-04 15:34:20 +00:00
|
|
|
panic("session id is not set, please use session.CreateSession(ctx) in middleware to create a session id")
|
2024-10-09 14:57:51 +00:00
|
|
|
} else {
|
|
|
|
|
sessionId = sessionIdRaw.(string)
|
2024-10-08 17:48:28 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-16 20:43:34 +00:00
|
|
|
return Id(sessionId)
|
2024-10-08 17:48:28 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-16 20:43:34 +00:00
|
|
|
func Update[T any](sessionId Id, key string, compute func(prev T) T) T {
|
2024-10-08 17:48:28 +00:00
|
|
|
actual := Get[T](sessionId, key, *new(T))
|
|
|
|
|
next := compute(actual)
|
|
|
|
|
Set(sessionId, key, next)
|
|
|
|
|
return next
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-16 20:43:34 +00:00
|
|
|
func Get[T any](sessionId Id, key string, fallback T) T {
|
2024-10-08 17:48:28 +00:00
|
|
|
actual, _ := cache.LoadOrCompute(sessionId, func() *xsync.MapOf[string, any] {
|
|
|
|
|
return xsync.NewMapOf[string, any]()
|
|
|
|
|
})
|
|
|
|
|
value, exists := actual.Load(key)
|
|
|
|
|
if exists {
|
|
|
|
|
return value.(T)
|
|
|
|
|
}
|
|
|
|
|
return fallback
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-16 20:43:34 +00:00
|
|
|
func Set(sessionId Id, key string, value any) {
|
2024-10-08 17:48:28 +00:00
|
|
|
actual, _ := cache.LoadOrCompute(sessionId, func() *xsync.MapOf[string, any] {
|
|
|
|
|
return xsync.NewMapOf[string, any]()
|
|
|
|
|
})
|
|
|
|
|
actual.Store(key, value)
|
|
|
|
|
}
|
2024-10-16 20:23:36 +00:00
|
|
|
|
2024-10-16 20:43:34 +00:00
|
|
|
func UseState[T any](sessionId Id, key string, initial T) (func() T, func(T)) {
|
2024-10-16 20:23:36 +00:00
|
|
|
var get = func() T {
|
|
|
|
|
return Get[T](sessionId, key, initial)
|
|
|
|
|
}
|
|
|
|
|
var set = func(value T) {
|
|
|
|
|
Set(sessionId, key, value)
|
|
|
|
|
}
|
|
|
|
|
return get, set
|
|
|
|
|
}
|