-
Notifications
You must be signed in to change notification settings - Fork 13
/
template_renderers.go
139 lines (115 loc) · 3.15 KB
/
template_renderers.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package handler
import (
"net/http"
"sync"
"time"
"github.com/djthorpe/gopi/v3"
)
/////////////////////////////////////////////////////////////////////
// TYPES
type renderers struct {
sync.RWMutex
r map[string]gopi.HttpRenderer
c map[string]content
}
type content struct {
modified time.Time
content interface{}
}
/////////////////////////////////////////////////////////////////////
// LIFECYCLE
func NewRenderers() *renderers {
this := new(renderers)
this.r = make(map[string]gopi.HttpRenderer)
this.c = make(map[string]content)
return this
}
/////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
func (this *renderers) Register(name string, renderer gopi.HttpRenderer) error {
this.RWMutex.Lock()
defer this.RWMutex.Unlock()
if renderer == nil {
return gopi.ErrBadParameter.WithPrefix("Register")
} else if _, exists := this.r[name]; exists {
return gopi.ErrDuplicateEntry.WithPrefix("Register", name)
} else {
this.r[name] = renderer
}
// Return success
return nil
}
func (this *renderers) Get(req *http.Request) (interface{}, time.Time) {
if req == nil || req.URL == nil {
return nil, time.Time{}
} else {
return this.get(keyForRequest(req))
}
}
func (this *renderers) Set(req *http.Request, content interface{}, modified time.Time) {
if req != nil && req.URL != nil {
this.set(keyForRequest(req), content, modified)
}
}
func (this *renderers) Renderer(name string) gopi.HttpRenderer {
this.RWMutex.RLock()
defer this.RWMutex.RUnlock()
if r, exists := this.r[name]; exists {
return r
} else {
return nil
}
}
func (this *renderers) Render(renderer gopi.HttpRenderer, req *http.Request) (interface{}, time.Time, error) {
// Check renderer
if renderer == nil {
return nil, time.Time{}, gopi.ErrNotFound
}
// Get existing content and modified date
key := keyForRequest(req)
if content, modified := this.get(key); content != nil {
// Serve from cache if not modified
if renderer.IsModifiedSince(req, modified) == false {
return content, modified, nil
}
}
// Generate content
if content, modified, err := renderer.ServeContent(req); err != nil {
// If error then remove content from cache
this.set(key, nil, time.Time{})
// Return the error
return nil, time.Time{}, err
} else {
if content == nil {
// Delete content from cache if content is nil
this.set(key, nil, time.Time{})
} else if modified.IsZero() == false {
this.set(key, content, modified)
}
// Return content
return content, modified, nil
}
}
/////////////////////////////////////////////////////////////////////
// PRIVATE METHODS
func (this *renderers) get(key string) (interface{}, time.Time) {
this.RWMutex.RLock()
defer this.RWMutex.RUnlock()
if cached, exists := this.c[key]; exists {
return cached.content, cached.modified
} else {
return nil, time.Time{}
}
}
func (this *renderers) set(key string, value interface{}, modified time.Time) {
this.RWMutex.Lock()
defer this.RWMutex.Unlock()
if value != nil && modified.IsZero() == false {
this.c[key] = content{modified, value}
} else {
delete(this.c, key)
}
}
func keyForRequest(req *http.Request) string {
return req.URL.String()
}