-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcave.go
120 lines (103 loc) · 2.51 KB
/
cave.go
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
package cave
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"math/rand"
"net/http"
"strings"
"text/template"
"time"
"github.com/gorilla/websocket"
)
type OnSubmiter interface {
OnSubmit(name string, form map[string]string)
}
type OnClicker interface {
OnClick(name string)
}
type Renderer interface {
Render() string
}
// MAYBE
type OnMounter interface {
OnMount(req *http.Request)
}
type Form struct{}
type Cave struct {
template *template.Template
registry map[string]RendererFunc
}
func New() *Cave {
rand.Seed(time.Now().UnixNano())
return &Cave{}
}
func (cave *Cave) component(name string) (interface{}, error) {
cmp, ok := cave.registry[name]
if !ok {
return nil, fmt.Errorf("component with name %q doesn't exist in the registry", name)
}
var buf bytes.Buffer
// this is a bit ad-hoc. liveview has lots of metadata here. think on this
fmt.Fprintf(&buf, "<div cave-component=\"%s-%d\">", name, rand.Uint64())
if _, err := renderOnce(cmp(), &buf); err != nil {
return nil, err
}
fmt.Fprintf(&buf, "</div>")
return buf.String(), nil
}
func (cave *Cave) AddTemplateFile(name, filePath string) error {
if cave.template == nil {
cave.template = template.New(name)
cave.template.Funcs(template.FuncMap{
"component": cave.component,
})
} else {
cave.template.New(name)
}
contents, err := ioutil.ReadFile(filePath)
if err != nil {
return err
}
if _, err := cave.template.Parse(string(contents)); err != nil {
return err
}
return nil
}
type RendererFunc func() Renderer
func (cave *Cave) AddComponent(name string, rf RendererFunc) {
if cave.registry == nil {
cave.registry = map[string]RendererFunc{}
}
cave.registry[name] = rf
}
func (cave *Cave) Render(layout string, w io.Writer) error {
if err := cave.template.ExecuteTemplate(w, layout, nil); err != nil {
return err
}
return nil
}
func (cave *Cave) ServeJS(w http.ResponseWriter, req *http.Request) {
w.Header().Add("Content-Encoding", "gzip")
w.Header().Add("Content-Type", "application/javascript")
if strings.HasSuffix(req.URL.Path, ".map") {
fmt.Fprint(w, bundlejsmap)
} else {
fmt.Fprint(w, bundlejs)
}
}
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func (cave *Cave) ServeWS(w http.ResponseWriter, req *http.Request) {
conn, err := upgrader.Upgrade(w, req, nil)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
wss := &websocketSession{cave: cave, req: req, conn: conn}
wss.handleMessages()
_ = wss.conn.WriteMessage(websocket.CloseMessage, []byte{})
}