pages - types.go
1 package pages
2
3 import (
4 "html/template"
5 "net/http"
6 "os"
7 "sync"
8 "time"
9 )
10
11 const (
12 Static = "-static-"
13 StaticTemplate = "{{define \"title\"}}{{.Title}}{{end}}{{define \"style\"}}{{.Style}}{{end}}{{define \"body\"}}\n{{.Body}}{{end}}"
14 )
15
16 type staticData struct {
17 Title, Style string
18 Body template.HTML
19 }
20
21 type Bytes struct {
22 pages *Pages
23 staticData staticData
24 }
25
26 func (p *Pages) Bytes(title, style string, body template.HTML) *Bytes {
27 if _, ok := p.templates[Static]; !ok {
28 p.StaticString(StaticTemplate)
29 }
30 return &Bytes{
31 pages: p,
32 staticData: staticData{
33 Title: title,
34 Style: style,
35 Body: body,
36 },
37 }
38 }
39
40 func (b *Bytes) ServeHTTP(w http.ResponseWriter, r *http.Request) {
41 b.pages.Write(w, r, Static, &b.staticData)
42 }
43
44 type File struct {
45 pages *Pages
46 Filename string
47
48 mu sync.RWMutex
49 staticData *staticData
50 LastModified time.Time
51 }
52
53 func (p *Pages) File(title, style, filename string) *File {
54 if _, ok := p.templates[Static]; !ok {
55 p.StaticString(StaticTemplate)
56 }
57 return &File{
58 pages: p,
59 Filename: filename,
60 staticData: &staticData{
61 Title: title,
62 Style: style,
63 },
64 }
65 }
66
67 func (f *File) ServeHTTP(w http.ResponseWriter, r *http.Request) {
68 stats, err := os.Stat(f.Filename)
69 if err != nil {
70 w.WriteHeader(http.StatusInternalServerError)
71 return
72 }
73 if modtime := stats.ModTime(); modtime.After(f.LastModified) {
74 f.mu.Lock()
75 stats, err = os.Stat(f.Filename)
76 if err != nil {
77 f.mu.Unlock()
78 w.WriteHeader(http.StatusInternalServerError)
79 return
80 }
81
82 if modtime = stats.ModTime(); modtime.After(f.LastModified) { // in case another goroutine has changed it already
83 data, err := os.ReadFile(f.Filename)
84 if err != nil {
85 f.mu.Unlock()
86 w.WriteHeader(http.StatusInternalServerError)
87 return
88 } else {
89 f.staticData = &staticData{
90 Title: f.staticData.Title,
91 Style: f.staticData.Style,
92 Body: template.HTML(data),
93 }
94 f.LastModified = modtime
95 }
96 }
97 f.mu.Unlock()
98 }
99 f.mu.RLock()
100 staticData := f.staticData
101 f.mu.RUnlock()
102 f.pages.Write(w, r, Static, staticData)
103 }
104