forked from jaredwilkening/goweb
-
Notifications
You must be signed in to change notification settings - Fork 1
/
resthtmlformater.go
232 lines (199 loc) · 5.5 KB
/
resthtmlformater.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
package goweb
import (
"bytes"
"fmt"
"html/template"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
var document_root string
// Formatter for JSON
type RestHtmlFormattor struct {
root *template.Template
models map[string]*template.Template
suffix string
dotsuffix string
}
type MobileRestHtmlFormattor struct {
RestHtmlFormattor
}
type RestModelTemplate struct {
template.Template
}
func (r *RestHtmlFormattor) Init() {
r.suffix = "html"
r.dotsuffix = ".html"
r.init()
}
func (r *MobileRestHtmlFormattor) Init() {
r.suffix = "mbl"
r.dotsuffix = ".mbl"
r.init()
}
func (r *RestHtmlFormattor) init() {
r.root = template.New("REST_HTTP_ROOT")
r.root.Funcs(template.FuncMap{
"raw": RawHtml,
"dict": DictArgument,
"divisible": Divisible,
})
r.models = make(map[string]*template.Template)
r.initGlobalTemplate()
}
// Gets the "application/html" content type
func (f *RestHtmlFormattor) Match(cx *Context) bool {
return cx.Format == f.suffix
}
func parseFileWithName(parent *template.Template, name string, filepath string) error {
b, err := ioutil.ReadFile(filepath)
if err != nil {
return err
}
s := string(b)
// First template becomes return value if not already defined,
// and we use that one for subsequent New calls to associate
// all the templates together. Also, if this file has the same name
// as t, this file becomes the contents of t, so
// t, err := New(name).Funcs(xxx).ParseFiles(name)
// works. Otherwise we create a new template associated with t.
var tmpl *template.Template
if name == parent.Name() || name == "" {
tmpl = parent
} else {
tmpl = parent.New(name)
}
_, err = tmpl.Parse(s)
if err != nil {
return err
}
return nil
}
func (f *RestHtmlFormattor) initModelTemplate(url string) *template.Template {
temp, err := f.root.Clone()
if err == nil {
temp = temp.New(url)
//scan for the helpers
filepath.Walk(filepath.Join(document_root, url, "helper"), func(path string, info os.FileInfo, err error) error {
if err == nil && (!info.IsDir()) && strings.HasSuffix(info.Name(), f.dotsuffix) {
fmt.Println("Parse helper:", path)
name := strings.TrimSuffix(info.Name(), f.dotsuffix)
e := parseFileWithName(temp, "model/"+name, path)
if e != nil {
fmt.Printf("ERROR template.ParseFile: %v", e)
}
}
return nil
})
f.models[url] = temp
return temp
}
fmt.Println("error happened", err)
return nil
}
func (f *RestHtmlFormattor) initGlobalTemplate() {
f.root.New("")
//scan for the helpers
filepath.Walk(filepath.Join(document_root, "helper"), func(path string, info os.FileInfo, err error) error {
if err == nil && (!info.IsDir()) && strings.HasSuffix(info.Name(), f.dotsuffix) {
fmt.Println("Parse helper:", path)
name := strings.TrimSuffix(info.Name(), f.dotsuffix)
e := parseFileWithName(f.root, "global/"+name, path)
if e != nil {
fmt.Printf("ERROR template.ParseFile: %v", e)
}
}
return nil
})
}
//Set the root for the rest html formating, formating is based on the method name(lower case)
func SetDocumentRoot(root string) {
document_root = root
}
func (f *RestHtmlFormattor) getRestModelByContext(cx *Context) *template.Template {
var t *template.Template
var path string
if cx.Rest.Url == "" || cx.Rest.Method == "" {
path = filepath.Join(document_root, cx.PathWithOutSuffix)
if info, err := os.Stat(path); err == nil {
if info.IsDir() {
path = filepath.Join(document_root, cx.PathWithOutSuffix+"index"+f.dotsuffix)
}
} else {
path = path + f.dotsuffix
}
var urlpath = cx.PathWithOutSuffix + f.dotsuffix
// var path = filepath.Join(document_root, urlpath)
t = f.models[urlpath]
if t == nil {
cloned_rest_model, err := f.root.Clone()
if err == nil {
info, err := os.Stat(path)
if err == nil && info.IsDir() {
path = filepath.Join(path, "index"+f.dotsuffix)
}
err = parseFileWithName(cloned_rest_model, urlpath, path)
if err == nil {
t = cloned_rest_model.Lookup(urlpath)
} else {
fmt.Println("ERROR template.ParseFile: %v", err)
}
f.models[urlpath] = t
}
}
} else {
t = f.models[cx.Rest.Url]
if t == nil {
t = f.initModelTemplate(cx.Rest.Url)
}
return f.getMethodTemplate(t, &cx.Rest)
}
return t
}
func (f *RestHtmlFormattor) getMethodTemplate(m *template.Template, rest *RestContext) *template.Template {
t := m.Lookup(rest.Method + f.dotsuffix)
var err error
if t == nil {
t, err = m.New(rest.Method + f.dotsuffix).ParseFiles(filepath.Join(document_root, rest.Url, rest.Method+f.dotsuffix))
if err != nil {
fmt.Println("ERROR template.ParseFile: %v", err)
}
}
return t
}
// Readies response and converts input data into JSON
func (f *RestHtmlFormattor) Format(cx *Context, input interface{}) ([]uint8, error) {
//get the document root dir
cx.ResponseWriter.Header().Set("Content-Type", "text/html; charset=utf-8")
temp := f.getRestModelByContext(cx)
var err error
buffer := new(bytes.Buffer)
err = temp.Execute(buffer, input)
if err != nil {
fmt.Printf("ERROR template.Execute: %v", err)
return nil, err
}
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
func RawHtml(text string) template.HTML { return template.HTML(text) }
func Divisible(n, b int) bool {
return n%b == 0
}
func DictArgument(values ...interface{}) map[string]interface{} {
if len(values)%2 != 0 {
return nil
}
dict := make(map[string]interface{}, len(values)/2)
for i := 0; i < len(values); i += 2 {
key, ok := values[i].(string)
if !ok {
return nil
}
dict[key] = values[i+1]
}
return dict
}