3b890713 by astaxie

add template test and cache module

1 parent db329a48
...@@ -13,6 +13,8 @@ import ( ...@@ -13,6 +13,8 @@ import (
13 "strconv" 13 "strconv"
14 ) 14 )
15 15
16 const VERSION = "0.0.3"
17
16 var ( 18 var (
17 BeeApp *App 19 BeeApp *App
18 AppName string 20 AppName string
...@@ -218,5 +220,6 @@ func Run() { ...@@ -218,5 +220,6 @@ func Run() {
218 GlobalSessions, _ = session.NewManager(SessionProvider, SessionName, SessionGCMaxLifetime) 220 GlobalSessions, _ = session.NewManager(SessionProvider, SessionName, SessionGCMaxLifetime)
219 go GlobalSessions.GC() 221 go GlobalSessions.GC()
220 } 222 }
223 BuildTemplate(ViewsPath)
221 BeeApp.Run() 224 BeeApp.Run()
222 } 225 }
......
1 package beego
2
3 import (
4 "errors"
5 "fmt"
6 "strconv"
7 "time"
8 )
9
10 const (
11 Kb = 1024
12 Mb = 1024 * 1024
13 Gb = 1024 * 1024 * 1024
14 )
15
16 var (
17 DefaultEvery int = 60 // 1 minute
18 )
19
20 var (
21 InvalidCacheItem = errors.New("invalid cache item")
22 ItemIsDirectory = errors.New("can't cache a directory")
23 ItemNotInCache = errors.New("item not in cache")
24 ItemTooLarge = errors.New("item too large for cache")
25 WriteIncomplete = errors.New("incomplete write of cache item")
26 )
27
28 type BeeItem struct {
29 val interface{}
30 Lastaccess time.Time
31 expired int
32 }
33
34 func (itm *BeeItem) Access() interface{} {
35 itm.Lastaccess = time.Now()
36 return itm.val
37 }
38
39 type BeeCache struct {
40 dur time.Duration
41 items map[string]*BeeItem
42 Every int // Run an expiration check Every seconds
43 }
44
45 // NewDefaultCache returns a new FileCache with sane defaults.
46 func NewBeeCache() *BeeCache {
47 cache := BeeCache{time.Since(time.Now()),
48 nil,
49 DefaultEvery}
50 return &cache
51 }
52
53 func (bc *BeeCache) Get(name string) interface{} {
54 itm, ok := bc.items[name]
55 if !ok {
56 return nil
57 }
58 return itm.Access()
59 }
60
61 func (bc *BeeCache) Put(name string, value interface{}, expired int) error {
62 t := BeeItem{val: value, Lastaccess: time.Now(), expired: expired}
63 if bc.IsExist(name) {
64 return errors.New("the key is exist")
65 } else {
66 bc.items[name] = &t
67 }
68 return nil
69 }
70
71 func (bc *BeeCache) Delete(name string) (ok bool, err error) {
72 _, ok = bc.items[name]
73 if !ok {
74 return
75 }
76 delete(bc.items, name)
77 _, valid := bc.items[name]
78 if valid {
79 ok = false
80 }
81 return
82 }
83
84 func (bc *BeeCache) IsExist(name string) bool {
85 _, ok := bc.items[name]
86 return ok
87 }
88
89 // Start activates the file cache; it will
90 func (bc *BeeCache) Start() error {
91 dur, err := time.ParseDuration(fmt.Sprintf("%ds", bc.Every))
92 if err != nil {
93 return err
94 }
95 bc.dur = dur
96 bc.items = make(map[string]*BeeItem, 0)
97 go bc.vaccuum()
98 return nil
99 }
100
101 func (bc *BeeCache) vaccuum() {
102 if bc.Every < 1 {
103 return
104 }
105 for {
106 <-time.After(time.Duration(bc.dur))
107 if bc.items == nil {
108 return
109 }
110 for name, _ := range bc.items {
111 if bc.item_expired(name) {
112 delete(bc.items, name)
113 }
114 }
115 }
116 }
117
118 // item_expired returns true if an item is expired.
119 func (bc *BeeCache) item_expired(name string) bool {
120 itm, ok := bc.items[name]
121 if !ok {
122 return true
123 }
124 dur := time.Now().Sub(itm.Lastaccess)
125 sec, err := strconv.Atoi(fmt.Sprintf("%0.0f", dur.Seconds()))
126 if err != nil {
127 return true
128 } else if sec >= itm.expired {
129 return true
130 }
131 return false
132 }
...@@ -15,7 +15,6 @@ import ( ...@@ -15,7 +15,6 @@ import (
15 15
16 type Controller struct { 16 type Controller struct {
17 Ctx *Context 17 Ctx *Context
18 Tpl *template.Template
19 Data map[interface{}]interface{} 18 Data map[interface{}]interface{}
20 ChildName string 19 ChildName string
21 TplNames string 20 TplNames string
...@@ -39,8 +38,6 @@ type ControllerInterface interface { ...@@ -39,8 +38,6 @@ type ControllerInterface interface {
39 38
40 func (c *Controller) Init(ctx *Context, cn string) { 39 func (c *Controller) Init(ctx *Context, cn string) {
41 c.Data = make(map[interface{}]interface{}) 40 c.Data = make(map[interface{}]interface{})
42 c.Tpl = template.New(cn + ctx.Request.Method)
43 c.Tpl = c.Tpl.Funcs(beegoTplFuncMap)
44 c.Layout = "" 41 c.Layout = ""
45 c.TplNames = "" 42 c.TplNames = ""
46 c.ChildName = cn 43 c.ChildName = cn
...@@ -91,17 +88,14 @@ func (c *Controller) Render() error { ...@@ -91,17 +88,14 @@ func (c *Controller) Render() error {
91 if c.TplNames == "" { 88 if c.TplNames == "" {
92 c.TplNames = c.ChildName + "/" + c.Ctx.Request.Method + "." + c.TplExt 89 c.TplNames = c.ChildName + "/" + c.Ctx.Request.Method + "." + c.TplExt
93 } 90 }
94 t, err := c.Tpl.ParseFiles(path.Join(ViewsPath, c.TplNames), path.Join(ViewsPath, c.Layout))
95 if err != nil {
96 Trace("template ParseFiles err:", err)
97 }
98 _, file := path.Split(c.TplNames) 91 _, file := path.Split(c.TplNames)
92 subdir := path.Dir(c.TplNames)
99 newbytes := bytes.NewBufferString("") 93 newbytes := bytes.NewBufferString("")
100 t.ExecuteTemplate(newbytes, file, c.Data) 94 BeeTemplates[subdir].ExecuteTemplate(newbytes, file, c.Data)
101 tplcontent, _ := ioutil.ReadAll(newbytes) 95 tplcontent, _ := ioutil.ReadAll(newbytes)
102 c.Data["LayoutContent"] = template.HTML(string(tplcontent)) 96 c.Data["LayoutContent"] = template.HTML(string(tplcontent))
103 _, file = path.Split(c.Layout) 97 _, file = path.Split(c.Layout)
104 err = t.ExecuteTemplate(c.Ctx.ResponseWriter, file, c.Data) 98 err := BeeTemplates[subdir].ExecuteTemplate(c.Ctx.ResponseWriter, file, c.Data)
105 if err != nil { 99 if err != nil {
106 Trace("template Execute err:", err) 100 Trace("template Execute err:", err)
107 } 101 }
...@@ -109,12 +103,9 @@ func (c *Controller) Render() error { ...@@ -109,12 +103,9 @@ func (c *Controller) Render() error {
109 if c.TplNames == "" { 103 if c.TplNames == "" {
110 c.TplNames = c.ChildName + "/" + c.Ctx.Request.Method + "." + c.TplExt 104 c.TplNames = c.ChildName + "/" + c.Ctx.Request.Method + "." + c.TplExt
111 } 105 }
112 t, err := c.Tpl.ParseFiles(path.Join(ViewsPath, c.TplNames))
113 if err != nil {
114 Trace("template ParseFiles err:", err)
115 }
116 _, file := path.Split(c.TplNames) 106 _, file := path.Split(c.TplNames)
117 err = t.ExecuteTemplate(c.Ctx.ResponseWriter, file, c.Data) 107 subdir := path.Dir(c.TplNames)
108 err := BeeTemplates[subdir].ExecuteTemplate(c.Ctx.ResponseWriter, file, c.Data)
118 if err != nil { 109 if err != nil {
119 Trace("template Execute err:", err) 110 Trace("template Execute err:", err)
120 } 111 }
......
...@@ -3,18 +3,27 @@ package beego ...@@ -3,18 +3,27 @@ package beego
3 //@todo add template funcs 3 //@todo add template funcs
4 4
5 import ( 5 import (
6 "fmt"
7 "errors" 6 "errors"
7 "fmt"
8 "github.com/russross/blackfriday" 8 "github.com/russross/blackfriday"
9 "html/template" 9 "html/template"
10 "os"
11 "path"
12 "path/filepath"
10 "strings" 13 "strings"
11 "time" 14 "time"
12 ) 15 )
13 16
14 var beegoTplFuncMap template.FuncMap 17 var (
18 beegoTplFuncMap template.FuncMap
19 BeeTemplates map[string]*template.Template
20 BeeTemplateExt string
21 )
15 22
16 func init() { 23 func init() {
24 BeeTemplates = make(map[string]*template.Template)
17 beegoTplFuncMap = make(template.FuncMap) 25 beegoTplFuncMap = make(template.FuncMap)
26 BeeTemplateExt = "tpl"
18 beegoTplFuncMap["markdown"] = MarkDown 27 beegoTplFuncMap["markdown"] = MarkDown
19 beegoTplFuncMap["dateformat"] = DateFormat 28 beegoTplFuncMap["dateformat"] = DateFormat
20 beegoTplFuncMap["date"] = Date 29 beegoTplFuncMap["date"] = Date
...@@ -87,8 +96,61 @@ func Compare(a, b interface{}) (equal bool) { ...@@ -87,8 +96,61 @@ func Compare(a, b interface{}) (equal bool) {
87 // AddFuncMap let user to register a func in the template 96 // AddFuncMap let user to register a func in the template
88 func AddFuncMap(key string, funname interface{}) error { 97 func AddFuncMap(key string, funname interface{}) error {
89 if _, ok := beegoTplFuncMap[key]; ok { 98 if _, ok := beegoTplFuncMap[key]; ok {
90 return errors.New("funcmap already has the key") 99 return errors.New("funcmap already has the key")
91 } 100 }
92 beegoTplFuncMap[key] = funname 101 beegoTplFuncMap[key] = funname
93 return nil 102 return nil
94 } 103 }
104
105 type templatefile struct {
106 root string
107 files map[string][]string
108 }
109
110 func (self *templatefile) visit(paths string, f os.FileInfo, err error) error {
111 if f == nil {
112 return err
113 }
114 if f.IsDir() {
115 return nil
116 } else if (f.Mode() & os.ModeSymlink) > 0 {
117 return nil
118 } else {
119 if strings.HasSuffix(paths, BeeTemplateExt) {
120 a := []byte(paths)
121 a = a[len([]byte(self.root)):]
122 subdir := path.Dir(strings.TrimLeft(string(a), "/"))
123 if _, ok := self.files[subdir]; ok {
124 self.files[subdir] = append(self.files[subdir], paths)
125 } else {
126 m := make([]string, 1)
127 m[0] = paths
128 self.files[subdir] = m
129 }
130
131 }
132 }
133 return nil
134 }
135
136 func SetGlobalTemplateExt(ext string) {
137 BeeTemplateExt = ext
138 }
139
140 func BuildTemplate(dir string) error {
141 self := templatefile{
142 root: dir,
143 files: make(map[string][]string),
144 }
145 err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
146 return self.visit(path, f, err)
147 })
148 if err != nil {
149 fmt.Printf("filepath.Walk() returned %v\n", err)
150 return err
151 }
152 for k, v := range self.files {
153 BeeTemplates[k] = template.Must(template.New("beegoTemplate" + k).Funcs(beegoTplFuncMap).ParseFiles(v...))
154 }
155 return nil
156 }
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!