refactor
This commit is contained in:
parent
6783fcf251
commit
dab96a3980
14 changed files with 77 additions and 49 deletions
|
|
@ -2,8 +2,7 @@ module sse-with-state
|
||||||
|
|
||||||
go 1.23.0
|
go 1.23.0
|
||||||
|
|
||||||
require github.com/maddalax/htmgo/framework v0.0.0-20241006162137-150c87b4560b
|
require github.com/maddalax/htmgo/framework v0.0.0-20241014151703-8503dffa4e7d
|
||||||
require github.com/maddalax/htmgo/extensions/ws v0.0.0-20241006162137-150c87b4560b
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/go-chi/chi/v5 v5.1.0 // indirect
|
github.com/go-chi/chi/v5 v5.1.0 // indirect
|
||||||
|
|
@ -11,5 +10,7 @@ require (
|
||||||
github.com/gobwas/pool v0.2.1 // indirect
|
github.com/gobwas/pool v0.2.1 // indirect
|
||||||
github.com/gobwas/ws v1.4.0 // indirect
|
github.com/gobwas/ws v1.4.0 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/maddalax/htmgo/extensions/websocket v0.0.0-20241016202901-6783fcf25143 // indirect
|
||||||
|
github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect
|
||||||
golang.org/x/sys v0.6.0 // indirect
|
golang.org/x/sys v0.6.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,16 @@ github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=
|
||||||
github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
|
github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/maddalax/htmgo/extensions/websocket v0.0.0-20241016202901-6783fcf25143 h1:Qzz4xsn2yfUV11La2lfXk90pSBpV0erp/gQoou1vh/k=
|
||||||
|
github.com/maddalax/htmgo/extensions/websocket v0.0.0-20241016202901-6783fcf25143/go.mod h1:r6/VqntLp7VlAUpIXy3MWZMHs2EkPKJP5rJdDL8lFP4=
|
||||||
github.com/maddalax/htmgo/framework v0.0.0-20241006162137-150c87b4560b h1:LzZTNwIGe0RHiEJZlpnpN8GRnKg2lCZppMX+JIyeF/g=
|
github.com/maddalax/htmgo/framework v0.0.0-20241006162137-150c87b4560b h1:LzZTNwIGe0RHiEJZlpnpN8GRnKg2lCZppMX+JIyeF/g=
|
||||||
github.com/maddalax/htmgo/framework v0.0.0-20241006162137-150c87b4560b/go.mod h1:HYKI49Pb6oyY2opSJdTt145B1vWgfWIDohvlolynv80=
|
github.com/maddalax/htmgo/framework v0.0.0-20241006162137-150c87b4560b/go.mod h1:HYKI49Pb6oyY2opSJdTt145B1vWgfWIDohvlolynv80=
|
||||||
|
github.com/maddalax/htmgo/framework v0.0.0-20241014151703-8503dffa4e7d h1:oysEaiKB7/WbvEklkyQ7SEE1xmDeGLrBUvF3BAsBUns=
|
||||||
|
github.com/maddalax/htmgo/framework v0.0.0-20241014151703-8503dffa4e7d/go.mod h1:HYKI49Pb6oyY2opSJdTt145B1vWgfWIDohvlolynv80=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4=
|
||||||
|
github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
websocket "github.com/maddalax/htmgo/extensions/ws"
|
"github.com/maddalax/htmgo/extensions/websocket"
|
||||||
|
ws2 "github.com/maddalax/htmgo/extensions/websocket/opts"
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
"github.com/maddalax/htmgo/framework/h"
|
||||||
"github.com/maddalax/htmgo/framework/service"
|
"github.com/maddalax/htmgo/framework/service"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
|
@ -16,8 +17,11 @@ func main() {
|
||||||
ServiceLocator: locator,
|
ServiceLocator: locator,
|
||||||
LiveReload: true,
|
LiveReload: true,
|
||||||
Register: func(app *h.App) {
|
Register: func(app *h.App) {
|
||||||
websocket.EnableExtension(app, websocket.WsExtensionOpts{
|
websocket.EnableExtension(app, ws2.ExtensionOpts{
|
||||||
WsPath: "/ws",
|
WsPath: "/ws",
|
||||||
|
SessionId: func(ctx *h.RequestContext) string {
|
||||||
|
return ctx.QueryParam("sessionId")
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
sub, err := fs.Sub(GetStaticAssets(), "assets/dist")
|
sub, err := fs.Sub(GetStaticAssets(), "assets/dist")
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,19 @@ package pages
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/maddalax/htmgo/extensions/websocket/state"
|
|
||||||
"github.com/maddalax/htmgo/extensions/websocket/ws"
|
"github.com/maddalax/htmgo/extensions/websocket/ws"
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
"github.com/maddalax/htmgo/framework/h"
|
||||||
|
"github.com/maddalax/htmgo/framework/session"
|
||||||
"sse-with-state/partials"
|
"sse-with-state/partials"
|
||||||
)
|
)
|
||||||
|
|
||||||
func IndexPage(ctx *h.RequestContext) *h.Page {
|
func IndexPage(ctx *h.RequestContext) *h.Page {
|
||||||
sessionId := state.GetSessionId(ctx)
|
sessionId := session.GetSessionId(ctx)
|
||||||
return h.NewPage(
|
return h.NewPage(
|
||||||
RootPage(
|
RootPage(
|
||||||
ctx,
|
ctx,
|
||||||
h.Div(
|
h.Div(
|
||||||
h.Attribute("ws-connect", fmt.Sprintf("/ws/test?sessionId=%s", sessionId)),
|
h.Attribute("ws-connect", fmt.Sprintf("/ws?sessionId=%s", sessionId)),
|
||||||
h.Class("flex flex-col gap-4 items-center pt-24 min-h-screen bg-neutral-100"),
|
h.Class("flex flex-col gap-4 items-center pt-24 min-h-screen bg-neutral-100"),
|
||||||
h.H3(h.Id("intro-text"), h.Text("Repeater Example"), h.Class("text-2xl")),
|
h.H3(h.Id("intro-text"), h.Text("Repeater Example"), h.Class("text-2xl")),
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
package pages
|
package pages
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/maddalax/htmgo/extensions/websocket/state"
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
"github.com/maddalax/htmgo/framework/h"
|
||||||
|
"github.com/maddalax/htmgo/framework/session"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RootPage(ctx *h.RequestContext, children ...h.Ren) h.Ren {
|
func RootPage(ctx *h.RequestContext, children ...h.Ren) h.Ren {
|
||||||
s := state.NewState(ctx)
|
s := session.NewState(ctx)
|
||||||
return h.Html(
|
return h.Html(
|
||||||
h.Attribute("data-session-id", string(s.SessionId)),
|
h.Attribute("data-session-id", string(s.SessionId)),
|
||||||
h.HxExtension(h.BaseExtensions()),
|
h.HxExtension(h.BaseExtensions()),
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package partials
|
package partials
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/maddalax/htmgo/extensions/websocket/state"
|
|
||||||
"github.com/maddalax/htmgo/extensions/websocket/ws"
|
"github.com/maddalax/htmgo/extensions/websocket/ws"
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
"github.com/maddalax/htmgo/framework/h"
|
||||||
|
"github.com/maddalax/htmgo/framework/session"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Counter struct {
|
type Counter struct {
|
||||||
|
|
@ -12,8 +12,8 @@ type Counter struct {
|
||||||
Decrement func()
|
Decrement func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func UseCounter(sessionId state.SessionId, id string) Counter {
|
func UseCounter(sessionId session.Id, id string) Counter {
|
||||||
get, set := state.Use(sessionId, id, 0)
|
get, set := session.UseState(sessionId, id, 0)
|
||||||
|
|
||||||
var increment = func() {
|
var increment = func() {
|
||||||
set(get() + 1)
|
set(get() + 1)
|
||||||
|
|
@ -38,7 +38,7 @@ func CounterForm(ctx *h.RequestContext, props CounterProps) *h.Element {
|
||||||
if props.Id == "" {
|
if props.Id == "" {
|
||||||
props.Id = h.GenId(6)
|
props.Id = h.GenId(6)
|
||||||
}
|
}
|
||||||
counter := UseCounter(state.GetSessionId(ctx), props.Id)
|
counter := UseCounter(session.GetSessionId(ctx), props.Id)
|
||||||
|
|
||||||
return h.Div(
|
return h.Div(
|
||||||
h.Attribute("hx-swap", "none"),
|
h.Attribute("hx-swap", "none"),
|
||||||
|
|
|
||||||
|
|
@ -2,22 +2,28 @@ package websocket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/maddalax/htmgo/extensions/websocket/internal/wsutil"
|
"github.com/maddalax/htmgo/extensions/websocket/internal/wsutil"
|
||||||
|
"github.com/maddalax/htmgo/extensions/websocket/opts"
|
||||||
"github.com/maddalax/htmgo/extensions/websocket/ws"
|
"github.com/maddalax/htmgo/extensions/websocket/ws"
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
"github.com/maddalax/htmgo/framework/h"
|
||||||
"github.com/maddalax/htmgo/framework/service"
|
"github.com/maddalax/htmgo/framework/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WsExtensionOpts struct {
|
func EnableExtension(app *h.App, opts opts.ExtensionOpts) {
|
||||||
WsPath string
|
|
||||||
}
|
|
||||||
|
|
||||||
func EnableExtension(app *h.App, opts WsExtensionOpts) {
|
|
||||||
if app.Opts.ServiceLocator == nil {
|
if app.Opts.ServiceLocator == nil {
|
||||||
app.Opts.ServiceLocator = service.NewLocator()
|
app.Opts.ServiceLocator = service.NewLocator()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts.WsPath == "" {
|
||||||
|
panic("websocket: WsPath is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.SessionId == nil {
|
||||||
|
panic("websocket: SessionId func is required")
|
||||||
|
}
|
||||||
|
|
||||||
service.Set[wsutil.SocketManager](app.Opts.ServiceLocator, service.Singleton, func() *wsutil.SocketManager {
|
service.Set[wsutil.SocketManager](app.Opts.ServiceLocator, service.Singleton, func() *wsutil.SocketManager {
|
||||||
return wsutil.NewSocketManager()
|
return wsutil.NewSocketManager(&opts)
|
||||||
})
|
})
|
||||||
ws.StartListener(app.Opts.ServiceLocator)
|
ws.StartListener(app.Opts.ServiceLocator)
|
||||||
app.Router.Handle(opts.WsPath, wsutil.WsHttpHandler())
|
app.Router.Handle(opts.WsPath, wsutil.WsHttpHandler(&opts))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gobwas/ws"
|
"github.com/gobwas/ws"
|
||||||
"github.com/gobwas/ws/wsutil"
|
"github.com/gobwas/ws/wsutil"
|
||||||
|
ws2 "github.com/maddalax/htmgo/extensions/websocket/opts"
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
"github.com/maddalax/htmgo/framework/h"
|
||||||
"github.com/maddalax/htmgo/framework/service"
|
"github.com/maddalax/htmgo/framework/service"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
|
@ -13,13 +14,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func WsHttpHandler() http.HandlerFunc {
|
func WsHttpHandler(opts *ws2.ExtensionOpts) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
cc := r.Context().Value(h.RequestContextKey).(*h.RequestContext)
|
cc := r.Context().Value(h.RequestContextKey).(*h.RequestContext)
|
||||||
locator := cc.ServiceLocator()
|
locator := cc.ServiceLocator()
|
||||||
manager := service.Get[SocketManager](locator)
|
manager := service.Get[SocketManager](locator)
|
||||||
|
|
||||||
sessionId := r.URL.Query().Get("sessionId")
|
sessionId := opts.SessionId(cc)
|
||||||
|
|
||||||
if sessionId == "" {
|
if sessionId == "" {
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package wsutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/maddalax/htmgo/extensions/websocket/opts"
|
||||||
"github.com/puzpuzpuz/xsync/v3"
|
"github.com/puzpuzpuz/xsync/v3"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -40,12 +41,14 @@ type SocketManager struct {
|
||||||
sockets *xsync.MapOf[string, *xsync.MapOf[string, SocketConnection]]
|
sockets *xsync.MapOf[string, *xsync.MapOf[string, SocketConnection]]
|
||||||
idToRoom *xsync.MapOf[string, string]
|
idToRoom *xsync.MapOf[string, string]
|
||||||
listeners []chan SocketEvent
|
listeners []chan SocketEvent
|
||||||
|
opts *opts.ExtensionOpts
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSocketManager() *SocketManager {
|
func NewSocketManager(opts *opts.ExtensionOpts) *SocketManager {
|
||||||
return &SocketManager{
|
return &SocketManager{
|
||||||
sockets: xsync.NewMapOf[string, *xsync.MapOf[string, SocketConnection]](),
|
sockets: xsync.NewMapOf[string, *xsync.MapOf[string, SocketConnection]](),
|
||||||
idToRoom: xsync.NewMapOf[string, string](),
|
idToRoom: xsync.NewMapOf[string, string](),
|
||||||
|
opts: opts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
8
extensions/websocket/opts/opts.go
Normal file
8
extensions/websocket/opts/opts.go
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
package opts
|
||||||
|
|
||||||
|
import "github.com/maddalax/htmgo/framework/h"
|
||||||
|
|
||||||
|
type ExtensionOpts struct {
|
||||||
|
WsPath string
|
||||||
|
SessionId func(ctx *h.RequestContext) string
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@ package ws
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/maddalax/htmgo/extensions/websocket/internal/wsutil"
|
"github.com/maddalax/htmgo/extensions/websocket/internal/wsutil"
|
||||||
"github.com/maddalax/htmgo/extensions/websocket/state"
|
"github.com/maddalax/htmgo/framework/session"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -62,7 +62,7 @@ func (h *MessageHandler) OnServerSideEvent(e ServerSideEvent) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MessageHandler) OnClientSideEvent(handlerId string, sessionId state.SessionId) {
|
func (h *MessageHandler) OnClientSideEvent(handlerId string, sessionId session.Id) {
|
||||||
cb, ok := handlers.Load(handlerId)
|
cb, ok := handlers.Load(handlerId)
|
||||||
if ok {
|
if ok {
|
||||||
cb(HandlerData{
|
cb(HandlerData{
|
||||||
|
|
@ -78,7 +78,7 @@ func (h *MessageHandler) OnDomElementRemoved(handlerId string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MessageHandler) OnSocketDisconnected(event wsutil.SocketEvent) {
|
func (h *MessageHandler) OnSocketDisconnected(event wsutil.SocketEvent) {
|
||||||
sessionId := state.SessionId(event.SessionId)
|
sessionId := session.Id(event.SessionId)
|
||||||
hashes, ok := sessionIdToHashes.Load(sessionId)
|
hashes, ok := sessionIdToHashes.Load(sessionId)
|
||||||
if ok {
|
if ok {
|
||||||
for hash := range hashes {
|
for hash := range hashes {
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ package ws
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/maddalax/htmgo/extensions/websocket/internal/wsutil"
|
"github.com/maddalax/htmgo/extensions/websocket/internal/wsutil"
|
||||||
"github.com/maddalax/htmgo/extensions/websocket/state"
|
|
||||||
"github.com/maddalax/htmgo/framework/service"
|
"github.com/maddalax/htmgo/framework/service"
|
||||||
|
"github.com/maddalax/htmgo/framework/session"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -34,7 +34,7 @@ func StartListener(locator *service.Locator) {
|
||||||
case wsutil.MessageEvent:
|
case wsutil.MessageEvent:
|
||||||
handlerId := event.Payload["id"].(string)
|
handlerId := event.Payload["id"].(string)
|
||||||
eventName := event.Payload["event"].(string)
|
eventName := event.Payload["event"].(string)
|
||||||
sessionId := state.SessionId(event.SessionId)
|
sessionId := session.Id(event.SessionId)
|
||||||
if eventName == "dom-element-removed" {
|
if eventName == "dom-element-removed" {
|
||||||
handler.OnDomElementRemoved(handlerId)
|
handler.OnDomElementRemoved(handlerId)
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,15 @@ package ws
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/maddalax/htmgo/extensions/websocket/internal/wsutil"
|
"github.com/maddalax/htmgo/extensions/websocket/internal/wsutil"
|
||||||
"github.com/maddalax/htmgo/extensions/websocket/state"
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
"github.com/maddalax/htmgo/framework/h"
|
||||||
|
"github.com/maddalax/htmgo/framework/session"
|
||||||
"github.com/puzpuzpuz/xsync/v3"
|
"github.com/puzpuzpuz/xsync/v3"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HandlerData struct {
|
type HandlerData struct {
|
||||||
SessionId state.SessionId
|
SessionId session.Id
|
||||||
Socket *wsutil.SocketConnection
|
Socket *wsutil.SocketConnection
|
||||||
Manager *wsutil.SocketManager
|
Manager *wsutil.SocketManager
|
||||||
}
|
}
|
||||||
|
|
@ -20,13 +20,13 @@ type Handler func(data HandlerData)
|
||||||
type ServerSideEvent struct {
|
type ServerSideEvent struct {
|
||||||
Event string
|
Event string
|
||||||
Payload map[string]any
|
Payload map[string]any
|
||||||
SessionId state.SessionId
|
SessionId session.Id
|
||||||
}
|
}
|
||||||
type KeyHash = string
|
type KeyHash = string
|
||||||
|
|
||||||
var handlers = xsync.NewMapOf[KeyHash, Handler]()
|
var handlers = xsync.NewMapOf[KeyHash, Handler]()
|
||||||
var sessionIdToHashes = xsync.NewMapOf[state.SessionId, map[KeyHash]bool]()
|
var sessionIdToHashes = xsync.NewMapOf[session.Id, map[KeyHash]bool]()
|
||||||
var hashesToSessionId = xsync.NewMapOf[KeyHash, state.SessionId]()
|
var hashesToSessionId = xsync.NewMapOf[KeyHash, session.Id]()
|
||||||
var serverEventNamesToHash = xsync.NewMapOf[string, map[KeyHash]bool]()
|
var serverEventNamesToHash = xsync.NewMapOf[string, map[KeyHash]bool]()
|
||||||
|
|
||||||
var socketMessageListener = make(chan wsutil.SocketEvent, 100)
|
var socketMessageListener = make(chan wsutil.SocketEvent, 100)
|
||||||
|
|
@ -44,7 +44,7 @@ func AddServerSideHandler(ctx *h.RequestContext, event string, handler Handler)
|
||||||
if callingHandler.Load() {
|
if callingHandler.Load() {
|
||||||
return h.NewAttributeMap()
|
return h.NewAttributeMap()
|
||||||
}
|
}
|
||||||
sessionId := state.GetSessionId(ctx)
|
sessionId := session.GetSessionId(ctx)
|
||||||
hash := makeId()
|
hash := makeId()
|
||||||
handlers.LoadOrStore(hash, handler)
|
handlers.LoadOrStore(hash, handler)
|
||||||
m, _ := serverEventNamesToHash.LoadOrCompute(event, func() map[KeyHash]bool {
|
m, _ := serverEventNamesToHash.LoadOrCompute(event, func() map[KeyHash]bool {
|
||||||
|
|
@ -59,19 +59,19 @@ func AddServerSideHandler(ctx *h.RequestContext, event string, handler Handler)
|
||||||
func AddClientSideHandler(ctx *h.RequestContext, event string, handler Handler) *h.AttributeMapOrdered {
|
func AddClientSideHandler(ctx *h.RequestContext, event string, handler Handler) *h.AttributeMapOrdered {
|
||||||
hash := makeId()
|
hash := makeId()
|
||||||
handlers.LoadOrStore(hash, handler)
|
handlers.LoadOrStore(hash, handler)
|
||||||
sessionId := state.GetSessionId(ctx)
|
sessionId := session.GetSessionId(ctx)
|
||||||
storeHashForSession(sessionId, hash)
|
storeHashForSession(sessionId, hash)
|
||||||
storeSessionIdForHash(sessionId, hash)
|
storeSessionIdForHash(sessionId, hash)
|
||||||
return h.AttributePairs("data-handler-id", hash, "data-handler-event", event)
|
return h.AttributePairs("data-handler-id", hash, "data-handler-event", event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func storeHashForSession(sessionId state.SessionId, hash KeyHash) {
|
func storeHashForSession(sessionId session.Id, hash KeyHash) {
|
||||||
m, _ := sessionIdToHashes.LoadOrCompute(sessionId, func() map[KeyHash]bool {
|
m, _ := sessionIdToHashes.LoadOrCompute(sessionId, func() map[KeyHash]bool {
|
||||||
return make(map[KeyHash]bool)
|
return make(map[KeyHash]bool)
|
||||||
})
|
})
|
||||||
m[hash] = true
|
m[hash] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func storeSessionIdForHash(sessionId state.SessionId, hash KeyHash) {
|
func storeSessionIdForHash(sessionId session.Id, hash KeyHash) {
|
||||||
hashesToSessionId.Store(hash, sessionId)
|
hashesToSessionId.Store(hash, sessionId)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,17 @@
|
||||||
package state
|
package session
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/maddalax/htmgo/extensions/websocket/internal"
|
|
||||||
"github.com/maddalax/htmgo/framework/h"
|
"github.com/maddalax/htmgo/framework/h"
|
||||||
"github.com/puzpuzpuz/xsync/v3"
|
"github.com/puzpuzpuz/xsync/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SessionId string
|
type Id string
|
||||||
|
|
||||||
var cache = xsync.NewMapOf[SessionId, *xsync.MapOf[string, any]]()
|
var cache = xsync.NewMapOf[Id, *xsync.MapOf[string, any]]()
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
SessionId SessionId
|
SessionId Id
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewState(ctx *h.RequestContext) *State {
|
func NewState(ctx *h.RequestContext) *State {
|
||||||
|
|
@ -23,28 +22,28 @@ func NewState(ctx *h.RequestContext) *State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSessionId(ctx *h.RequestContext) SessionId {
|
func GetSessionId(ctx *h.RequestContext) Id {
|
||||||
sessionIdRaw := ctx.Get("session-id")
|
sessionIdRaw := ctx.Get("session-id")
|
||||||
sessionId := ""
|
sessionId := ""
|
||||||
|
|
||||||
if sessionIdRaw == "" || sessionIdRaw == nil {
|
if sessionIdRaw == "" || sessionIdRaw == nil {
|
||||||
sessionId = fmt.Sprintf("session-id-%s", internal.RandSeq(30))
|
sessionId = fmt.Sprintf("session-id-%s", h.GenId(30))
|
||||||
ctx.Set("session-id", sessionId)
|
ctx.Set("session-id", sessionId)
|
||||||
} else {
|
} else {
|
||||||
sessionId = sessionIdRaw.(string)
|
sessionId = sessionIdRaw.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
return SessionId(sessionId)
|
return Id(sessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Update[T any](sessionId SessionId, key string, compute func(prev T) T) T {
|
func Update[T any](sessionId Id, key string, compute func(prev T) T) T {
|
||||||
actual := Get[T](sessionId, key, *new(T))
|
actual := Get[T](sessionId, key, *new(T))
|
||||||
next := compute(actual)
|
next := compute(actual)
|
||||||
Set(sessionId, key, next)
|
Set(sessionId, key, next)
|
||||||
return next
|
return next
|
||||||
}
|
}
|
||||||
|
|
||||||
func Get[T any](sessionId SessionId, key string, fallback T) T {
|
func Get[T any](sessionId Id, key string, fallback T) T {
|
||||||
actual, _ := cache.LoadOrCompute(sessionId, func() *xsync.MapOf[string, any] {
|
actual, _ := cache.LoadOrCompute(sessionId, func() *xsync.MapOf[string, any] {
|
||||||
return xsync.NewMapOf[string, any]()
|
return xsync.NewMapOf[string, any]()
|
||||||
})
|
})
|
||||||
|
|
@ -55,14 +54,14 @@ func Get[T any](sessionId SessionId, key string, fallback T) T {
|
||||||
return fallback
|
return fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
func Set(sessionId SessionId, key string, value any) {
|
func Set(sessionId Id, key string, value any) {
|
||||||
actual, _ := cache.LoadOrCompute(sessionId, func() *xsync.MapOf[string, any] {
|
actual, _ := cache.LoadOrCompute(sessionId, func() *xsync.MapOf[string, any] {
|
||||||
return xsync.NewMapOf[string, any]()
|
return xsync.NewMapOf[string, any]()
|
||||||
})
|
})
|
||||||
actual.Store(key, value)
|
actual.Store(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Use[T any](sessionId SessionId, key string, initial T) (func() T, func(T)) {
|
func UseState[T any](sessionId Id, key string, initial T) (func() T, func(T)) {
|
||||||
var get = func() T {
|
var get = func() T {
|
||||||
return Get[T](sessionId, key, initial)
|
return Get[T](sessionId, key, initial)
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue