-
Notifications
You must be signed in to change notification settings - Fork 114
/
Copy pathrender.go
123 lines (105 loc) · 2.75 KB
/
render.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
package lessgo
import (
"encoding/json"
"errors"
"io"
"sync"
"time"
"github.com/henrylee2cn/lessgo/pongo2"
)
type (
Tpl struct {
template *pongo2.Template
modTime time.Time
}
// Pongo2Render is a custom lessgo template renderer using Pongo2.
Pongo2Render struct {
set *pongo2.TemplateSet
caching bool // false=disable caching, true=enable caching
tplCache map[string]*Tpl
tplContext pongo2.Context // Context hold globle func for tpl
sync.RWMutex
}
)
// New creates a new Pongo2Render instance with custom Options.
func NewPongo2Render(caching bool) *Pongo2Render {
return &Pongo2Render{
set: pongo2.NewSet("lessgo", pongo2.DefaultLoader),
caching: caching,
tplCache: make(map[string]*Tpl),
tplContext: make(pongo2.Context),
}
}
func (p *Pongo2Render) TemplateVariable(name string, v interface{}) {
switch d := v.(type) {
case func(in *pongo2.Value, param *pongo2.Value) (out *pongo2.Value, err *pongo2.Error):
pongo2.RegisterFilter(name, d)
case pongo2.FilterFunction:
pongo2.RegisterFilter(name, d)
default:
p.tplContext[name] = d
}
}
// Render should render the template to the io.Writer.
func (p *Pongo2Render) Render(w io.Writer, filename string, data interface{}, c *Context) error {
var data2 = pongo2.Context{}
if data == nil {
data2 = p.tplContext
} else {
switch d := data.(type) {
case pongo2.Context:
data2 = d
case map[string]interface{}:
data2 = pongo2.Context(d)
default:
b, _ := json.Marshal(data)
json.Unmarshal(b, &data2)
}
for k, v := range p.tplContext {
if _, ok := data2[k]; !ok {
data2[k] = v
}
}
}
var template *pongo2.Template
if p.caching {
template = pongo2.Must(p.FromCache(filename))
} else {
template = pongo2.Must(p.set.FromFile(filename))
}
return template.ExecuteWriter(data2, w)
}
func (p *Pongo2Render) FromCache(fname string) (*pongo2.Template, error) {
//从文件系统缓存中获取文件信息
fbytes, finfo, exist := lessgo.App.MemoryCache().GetCacheFile(fname)
// 文件已不存在
if !exist {
// 移除模板中缓存
p.Lock()
_, has := p.tplCache[fname]
if has {
delete(p.tplCache, fname)
}
p.Unlock()
// 返回错误
return nil, errors.New(fname + "is not found.")
}
// 查看模板缓存
p.RLock()
tpl, has := p.tplCache[fname]
p.RUnlock()
// 存在模板缓存且文件未更新时,直接读模板缓存
if has && p.tplCache[fname].modTime.Equal(finfo.ModTime()) {
return tpl.template, nil
}
// 缓存模板不存在或文件已更新时,均新建缓存模板
p.Lock()
defer p.Unlock()
// 创建新模板并缓存
newtpl, err := p.set.FromBytes(fname, fbytes)
if err != nil {
return nil, err
}
p.tplCache[fname] = &Tpl{template: newtpl, modTime: finfo.ModTime()}
return newtpl, nil
}