-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy pathhandler.go
More file actions
126 lines (111 loc) · 4.2 KB
/
handler.go
File metadata and controls
126 lines (111 loc) · 4.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package live
import (
"context"
"fmt"
"io"
"log/slog"
)
//var _ Handler = &BaseHandler{}
// HandlerConfig applies config to a handler.
type HandlerConfig func(h *Handler) error
// MountHandler the func that is called by a handler to gather data to
// be rendered in a template. This is called on first GET and then later when
// the web socket first connects. It should return the state to be maintained
// in the socket.
type MountHandler func(ctx context.Context, c *Socket) (any, error)
// UnmountHandler the func that is called by a handler to report that a connection
// is closed. This is called on websocket close. Can be used to track number of
// connected users.
type UnmountHandler func(c *Socket) error
// RenderHandler the func that is called to render the current state of the
// data for the socket.
type RenderHandler func(ctx context.Context, rc *RenderContext) (io.Reader, error)
// ErrorHandler if an error occurs during the mount and render cycle
// a handler of this type will be called.
type ErrorHandler func(ctx context.Context, err error)
// EventHandler a function to handle events, returns the data that should
// be set to the socket after handling.
type EventHandler func(context.Context, *Socket, Params) (any, error)
// SelfHandler a function to handle self events, returns the data that should
// be set to the socket after handling.
type SelfHandler func(context.Context, *Socket, any) (any, error)
// Handler.
type Handler struct {
// MountHandler a user should provide the mount function. This is what
// is called on initial GET request and later when the websocket connects.
// Data to render the handler should be fetched here and returned.
MountHandler MountHandler
// UnmountHandler used to track websocket disconnections.
UnmountHandler UnmountHandler
// Render is called to generate the HTML of a Socket. It is defined
// by default and will render any template provided.
RenderHandler RenderHandler
// Error is called when an error occurs during the mount and render
// stages of the handler lifecycle.
ErrorHandler ErrorHandler
// eventHandlers the map of client event handlers.
eventHandlers map[string]EventHandler
// selfHandlers the map of handler event handlers.
selfHandlers map[string]SelfHandler
// paramsHandlers a slice of handlers which respond to a change in URL parameters.
paramsHandlers []EventHandler
}
// NewHandler sets up a base handler for live.
func NewHandler(configs ...HandlerConfig) *Handler {
h := &Handler{
eventHandlers: make(map[string]EventHandler),
selfHandlers: make(map[string]SelfHandler),
paramsHandlers: []EventHandler{},
MountHandler: func(ctx context.Context, s *Socket) (any, error) {
return nil, nil
},
UnmountHandler: func(s *Socket) error {
return nil
},
RenderHandler: func(ctx context.Context, rc *RenderContext) (io.Reader, error) {
return nil, ErrNoRenderer
},
ErrorHandler: func(ctx context.Context, err error) {
w := Writer(ctx)
if w != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
}
},
}
for _, conf := range configs {
if err := conf(h); err != nil {
slog.Warn("apply config", "err", err)
}
}
return h
}
// HandleEvent handles an event that comes from the client. For example a click
// from `live-click="myevent"`.
func (h *Handler) HandleEvent(t string, handler EventHandler) {
h.eventHandlers[t] = handler
}
// HandleSelf handles an event that comes from the server side socket. For example calling
// h.Self(socket, msg) will be handled here.
func (h *Handler) HandleSelf(t string, handler SelfHandler) {
h.selfHandlers[t] = handler
}
// HandleParams handles a URL query parameter change. This is useful for handling
// things like pagination, or some filtering.
func (h *Handler) HandleParams(handler EventHandler) {
h.paramsHandlers = append(h.paramsHandlers, handler)
}
func (h *Handler) getEvent(t string) (EventHandler, error) {
handler, ok := h.eventHandlers[t]
if !ok {
return nil, fmt.Errorf("no event handler for %s: %w", t, ErrNoEventHandler)
}
return handler, nil
}
func (h *Handler) getSelf(t string) (SelfHandler, error) {
handler, ok := h.selfHandlers[t]
if !ok {
return nil, fmt.Errorf("no self handler for %s: %w", t, ErrNoEventHandler)
}
return handler, nil
}