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
31 return &Bytes{
32 pages: p,
33 staticData: staticData{
34 Title: title,
35 Style: style,
36 Body: body,
37 },
38 }
39 }
40
41 func (b *Bytes) ServeHTTP(w http.ResponseWriter, r *http.Request) {
42 b.pages.Write(w, r, Static, &b.staticData)
43 }
44
45 type File struct {
46 pages *Pages
47 Filename string
48
49 mu sync.RWMutex
50 staticData *staticData
51 LastModified time.Time
52 }
53
54 func (p *Pages) File(title, style, filename string) *File {
55 if _, ok := p.templates[Static]; !ok {
56 p.StaticString(StaticTemplate)
57 }
58
59 return &File{
60 pages: p,
61 Filename: filename,
62 staticData: &staticData{
63 Title: title,
64 Style: style,
65 },
66 }
67 }
68
69 func (f *File) ServeHTTP(w http.ResponseWriter, r *http.Request) {
70 stats, err := os.Stat(f.Filename)
71 if err != nil {
72 w.WriteHeader(http.StatusInternalServerError)
73
74 return
75 }
76
77 if modtime := stats.ModTime(); modtime.After(f.LastModified) {
78 f.mu.Lock()
79
80 stats, err = os.Stat(f.Filename)
81 if err != nil {
82 f.mu.Unlock()
83 w.WriteHeader(http.StatusInternalServerError)
84
85 return
86 }
87
88 if modtime = stats.ModTime(); modtime.After(f.LastModified) { // in case another goroutine has changed it already
89 if data, err := os.ReadFile(f.Filename); err != nil {
90 f.mu.Unlock()
91 w.WriteHeader(http.StatusInternalServerError)
92
93 return
94 } else {
95 f.staticData = &staticData{
96 Title: f.staticData.Title,
97 Style: f.staticData.Style,
98 Body: template.HTML(data),
99 }
100 f.LastModified = modtime
101 }
102 }
103
104 f.mu.Unlock()
105 }
106
107 f.mu.RLock()
108 staticData := f.staticData
109 f.mu.RUnlock()
110
111 f.pages.Write(w, r, Static, staticData)
112 }
113