-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
83 lines (75 loc) · 2.29 KB
/
main.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
// Package autorefresh provides a mechanism for attaching browser refreshing to your templates during development.
// When it is detected that your program has restarted (e.g., by using a live-reload tool like "air"), it will
// trigger the browser page to refresh itself automatically.
package autorefresh
import (
"errors"
"fmt"
"html/template"
"net/http"
"time"
"github.com/coder/websocket"
)
const Script string = `
<script>
function setupReloadSocket(reload = false) {
const reloadWebsocket = new WebSocket({{ path }});
let doReloadNext = reload;
reloadWebsocket.onopen = function () {
if (reload === true) {
window.location.reload();
} else {
doReloadNext = true;
}
};
reloadWebsocket.onerror = function onError() {
setTimeout(() => setupReloadSocket(doReloadNext), {{ refreshRate }});
};
reloadWebsocket.onclose = function onClose() {
setTimeout(() => setupReloadSocket(doReloadNext), {{ refreshRate }});
};
}
setupReloadSocket();
</script>
`
type PageReloader struct {
Template *template.Template
Path string
RefreshRate uint
}
var (
ErrInvalidParameters = errors.New("Invalid parameters")
ErrTemplateParsing = errors.New("Failed to parse template")
)
func New(t *template.Template, path string, refreshRate uint) (*PageReloader, error) {
// If there was no template passed, create our own and let it get used in some other way
if t == nil {
t = template.New("autorefresh")
}
if refreshRate < 100 {
return nil, fmt.Errorf("%w: refreshRate must be at least 100ms", ErrInvalidParameters)
}
t, err := t.Funcs(template.FuncMap{
"path": func() string { return path },
"refreshRate": func() uint { return refreshRate },
}).Parse(Script)
if err != nil {
return nil, fmt.Errorf("%w: %w", ErrTemplateParsing, err)
}
return &PageReloader{Path: path, Template: t, RefreshRate: refreshRate}, nil
}
func (p *PageReloader) ServeHTTP(w http.ResponseWriter, r *http.Request) {
socket, err := websocket.Accept(w, r, nil)
if err != nil {
_, _ = w.Write([]byte("could not open websocket"))
w.WriteHeader(http.StatusInternalServerError)
return
}
defer socket.Close(websocket.StatusGoingAway, "server closing websocket")
ctx := r.Context()
socketCtx := socket.CloseRead(ctx)
for {
_ = socket.Ping(socketCtx)
time.Sleep(time.Second * 2)
}
}