Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
217 lines
3.9 KiB
217 lines
3.9 KiB
package render |
|
|
|
import ( |
|
"bytes" |
|
"encoding/json" |
|
"encoding/xml" |
|
"html/template" |
|
"io" |
|
"net/http" |
|
) |
|
|
|
// Engine is the generic interface for all responses. |
|
type Engine interface { |
|
Render(io.Writer, interface{}) error |
|
} |
|
|
|
// Head defines the basic ContentType and Status fields. |
|
type Head struct { |
|
ContentType string |
|
Status int |
|
} |
|
|
|
// Data built-in renderer. |
|
type Data struct { |
|
Head |
|
} |
|
|
|
// HTML built-in renderer. |
|
type HTML struct { |
|
Head |
|
Name string |
|
Templates *template.Template |
|
} |
|
|
|
// JSON built-in renderer. |
|
type JSON struct { |
|
Head |
|
Indent bool |
|
UnEscapeHTML bool |
|
Prefix []byte |
|
StreamingJSON bool |
|
} |
|
|
|
// JSONP built-in renderer. |
|
type JSONP struct { |
|
Head |
|
Indent bool |
|
Callback string |
|
} |
|
|
|
// Text built-in renderer. |
|
type Text struct { |
|
Head |
|
} |
|
|
|
// XML built-in renderer. |
|
type XML struct { |
|
Head |
|
Indent bool |
|
Prefix []byte |
|
} |
|
|
|
// Write outputs the header content. |
|
func (h Head) Write(w http.ResponseWriter) { |
|
w.Header().Set(ContentType, h.ContentType) |
|
w.WriteHeader(h.Status) |
|
} |
|
|
|
// Render a data response. |
|
func (d Data) Render(w io.Writer, v interface{}) error { |
|
if hw, ok := w.(http.ResponseWriter); ok { |
|
c := hw.Header().Get(ContentType) |
|
if c != "" { |
|
d.Head.ContentType = c |
|
} |
|
d.Head.Write(hw) |
|
} |
|
|
|
w.Write(v.([]byte)) |
|
return nil |
|
} |
|
|
|
// Render a HTML response. |
|
func (h HTML) Render(w io.Writer, binding interface{}) error { |
|
// Retrieve a buffer from the pool to write to. |
|
out := bufPool.Get() |
|
err := h.Templates.ExecuteTemplate(out, h.Name, binding) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
if hw, ok := w.(http.ResponseWriter); ok { |
|
h.Head.Write(hw) |
|
} |
|
out.WriteTo(w) |
|
|
|
// Return the buffer to the pool. |
|
bufPool.Put(out) |
|
return nil |
|
} |
|
|
|
// Render a JSON response. |
|
func (j JSON) Render(w io.Writer, v interface{}) error { |
|
if j.StreamingJSON { |
|
return j.renderStreamingJSON(w, v) |
|
} |
|
|
|
var result []byte |
|
var err error |
|
|
|
if j.Indent { |
|
result, err = json.MarshalIndent(v, "", " ") |
|
result = append(result, '\n') |
|
} else { |
|
result, err = json.Marshal(v) |
|
} |
|
if err != nil { |
|
return err |
|
} |
|
|
|
// Unescape HTML if needed. |
|
if j.UnEscapeHTML { |
|
result = bytes.Replace(result, []byte("\\u003c"), []byte("<"), -1) |
|
result = bytes.Replace(result, []byte("\\u003e"), []byte(">"), -1) |
|
result = bytes.Replace(result, []byte("\\u0026"), []byte("&"), -1) |
|
} |
|
|
|
// JSON marshaled fine, write out the result. |
|
if hw, ok := w.(http.ResponseWriter); ok { |
|
j.Head.Write(hw) |
|
} |
|
if len(j.Prefix) > 0 { |
|
w.Write(j.Prefix) |
|
} |
|
w.Write(result) |
|
return nil |
|
} |
|
|
|
func (j JSON) renderStreamingJSON(w io.Writer, v interface{}) error { |
|
if hw, ok := w.(http.ResponseWriter); ok { |
|
j.Head.Write(hw) |
|
} |
|
if len(j.Prefix) > 0 { |
|
w.Write(j.Prefix) |
|
} |
|
|
|
return json.NewEncoder(w).Encode(v) |
|
} |
|
|
|
// Render a JSONP response. |
|
func (j JSONP) Render(w io.Writer, v interface{}) error { |
|
var result []byte |
|
var err error |
|
|
|
if j.Indent { |
|
result, err = json.MarshalIndent(v, "", " ") |
|
} else { |
|
result, err = json.Marshal(v) |
|
} |
|
if err != nil { |
|
return err |
|
} |
|
|
|
// JSON marshaled fine, write out the result. |
|
if hw, ok := w.(http.ResponseWriter); ok { |
|
j.Head.Write(hw) |
|
} |
|
w.Write([]byte(j.Callback + "(")) |
|
w.Write(result) |
|
w.Write([]byte(");")) |
|
|
|
// If indenting, append a new line. |
|
if j.Indent { |
|
w.Write([]byte("\n")) |
|
} |
|
return nil |
|
} |
|
|
|
// Render a text response. |
|
func (t Text) Render(w io.Writer, v interface{}) error { |
|
if hw, ok := w.(http.ResponseWriter); ok { |
|
c := hw.Header().Get(ContentType) |
|
if c != "" { |
|
t.Head.ContentType = c |
|
} |
|
t.Head.Write(hw) |
|
} |
|
|
|
w.Write([]byte(v.(string))) |
|
return nil |
|
} |
|
|
|
// Render an XML response. |
|
func (x XML) Render(w io.Writer, v interface{}) error { |
|
var result []byte |
|
var err error |
|
|
|
if x.Indent { |
|
result, err = xml.MarshalIndent(v, "", " ") |
|
result = append(result, '\n') |
|
} else { |
|
result, err = xml.Marshal(v) |
|
} |
|
if err != nil { |
|
return err |
|
} |
|
|
|
// XML marshaled fine, write out the result. |
|
if hw, ok := w.(http.ResponseWriter); ok { |
|
x.Head.Write(hw) |
|
} |
|
if len(x.Prefix) > 0 { |
|
w.Write(x.Prefix) |
|
} |
|
w.Write(result) |
|
return nil |
|
}
|
|
|