Cleanup the API a bit add debug functions
This commit is contained in:
parent
7ed387dee5
commit
eab56d649f
65
context.go
65
context.go
|
@ -1,23 +1,26 @@
|
|||
package snap
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"git.thirdmartini.com/pub/snap/auth"
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
srv *Server
|
||||
srv *Server
|
||||
auth *auth.AuthData
|
||||
|
||||
w http.ResponseWriter
|
||||
r *http.Request
|
||||
w http.ResponseWriter
|
||||
r *http.Request
|
||||
vars map[string]string
|
||||
}
|
||||
|
||||
type SnapContent struct {
|
||||
User string
|
||||
Theme string
|
||||
User string
|
||||
Theme string
|
||||
Content interface{}
|
||||
}
|
||||
|
||||
|
@ -29,7 +32,6 @@ func (c *Context) Writer() http.ResponseWriter {
|
|||
return c.w
|
||||
}
|
||||
|
||||
|
||||
func (c *Context) GetUser() string {
|
||||
if c.auth == nil {
|
||||
return ""
|
||||
|
@ -41,12 +43,10 @@ func (c *Context) Error(code int, msg string) {
|
|||
c.srv.renderError(c.w, code, msg)
|
||||
}
|
||||
|
||||
|
||||
func (c *Context) Reply(msg string) {
|
||||
c.srv.reply(c.w, msg)
|
||||
}
|
||||
|
||||
|
||||
func (c *Context) ReplyObject(obj interface{}) {
|
||||
msg, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
|
@ -55,29 +55,35 @@ func (c *Context) ReplyObject(obj interface{}) {
|
|||
c.Reply(string(msg))
|
||||
}
|
||||
|
||||
|
||||
func (c *Context) GetObject(obj interface{}) error {
|
||||
data, err := ioutil.ReadAll(c.r.Body)
|
||||
defer c.r.Body.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, obj)
|
||||
}
|
||||
|
||||
func (c *Context) Render(tmpl string, content interface{}) {
|
||||
c.srv.render(c.w, tmpl, content)
|
||||
}
|
||||
|
||||
|
||||
func (c *Context) RenderEx(tmpl string, content interface{}) {
|
||||
cnt := SnapContent {
|
||||
User: c.GetUser(),
|
||||
Theme: c.srv.theme,
|
||||
Content:content,
|
||||
cnt := SnapContent{
|
||||
User: c.GetUser(),
|
||||
Theme: c.srv.theme,
|
||||
Content: content,
|
||||
}
|
||||
c.srv.render(c.w, tmpl, &cnt)
|
||||
}
|
||||
|
||||
func (c *Context) GetVar(k string) ( string, bool) {
|
||||
v,ok := c.vars[k]
|
||||
func (c *Context) GetVar(k string) (string, bool) {
|
||||
v, ok := c.vars[k]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
func (c *Context) GetVarDefault(k string,def string) (string) {
|
||||
v,ok := c.vars[k]
|
||||
func (c *Context) GetVarDefault(k string, def string) string {
|
||||
v, ok := c.vars[k]
|
||||
if !ok {
|
||||
return def
|
||||
}
|
||||
|
@ -90,4 +96,23 @@ func (c *Context) ParseForm() error {
|
|||
|
||||
func (c *Context) FormValue(k string) string {
|
||||
return c.r.FormValue(k)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) FormValueUint64(k string) uint64 {
|
||||
str := c.r.FormValue(k)
|
||||
|
||||
val, err := strconv.ParseUint(str, 10, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
func (c *Context) Redirect(url string) {
|
||||
http.Redirect(c.w, c.r, url, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func (c *Context) QueryValue(key string) string {
|
||||
return c.r.URL.Query().Get(key)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package snap
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"expvar"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
"runtime"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func stackHandler(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/sovereign/debug/pprof/goroutine?debug=2", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// copy pasted from http://golang.org/src/expvar/expvar.go#L308
|
||||
func varsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
buf := make([]byte, 0, 16384)
|
||||
body := bytes.NewBuffer(buf)
|
||||
|
||||
fmt.Fprintf(body, "{")
|
||||
expvar.Do(func(kv expvar.KeyValue) {
|
||||
fmt.Fprintf(body, "%q: %s,", kv.Key, kv.Value)
|
||||
})
|
||||
|
||||
fmt.Fprintf(body, "%q: %d", "NumGoRoutines", runtime.NumGoroutine())
|
||||
fmt.Fprintf(body, "}")
|
||||
|
||||
var prettyJSON bytes.Buffer
|
||||
err := json.Indent(&prettyJSON, body.Bytes(), "", " ")
|
||||
if err != nil {
|
||||
log.Println(err, string(body.Bytes()))
|
||||
}
|
||||
|
||||
w.Write(prettyJSON.Bytes())
|
||||
}
|
||||
|
||||
func setupDebugHandler(r *mux.Router) {
|
||||
r.HandleFunc("/stack", stackHandler)
|
||||
r.HandleFunc("/vars", varsHandler)
|
||||
r.HandleFunc("/pprof/", http.HandlerFunc(pprof.Index))
|
||||
r.HandleFunc("/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
|
||||
r.HandleFunc("/pprof/profile", http.HandlerFunc(pprof.Profile))
|
||||
r.HandleFunc("/pprof/symbol", http.HandlerFunc(pprof.Symbol))
|
||||
r.HandleFunc("/pprof/trace", http.HandlerFunc(pprof.Trace))
|
||||
r.HandleFunc("/pprof/goroutine", pprof.Handler("goroutine").ServeHTTP)
|
||||
r.HandleFunc("/pprof/allocs", pprof.Handler("allocs").ServeHTTP)
|
||||
r.HandleFunc("/pprof/block", pprof.Handler("block").ServeHTTP)
|
||||
r.HandleFunc("/pprof/heap", pprof.Handler("heap").ServeHTTP)
|
||||
r.HandleFunc("/pprof/mutex", pprof.Handler("mutex").ServeHTTP)
|
||||
}
|
53
server.go
53
server.go
|
@ -1,12 +1,13 @@
|
|||
package snap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -64,11 +65,13 @@ func (s *Server) wrapper(handle func(c *Context)) http.HandlerFunc {
|
|||
log.Debug("request: ", r.RequestURI)
|
||||
c := s.makeContext(nil, w, r)
|
||||
handle(c)
|
||||
|
||||
// discard the rest of the body content
|
||||
io.Copy(ioutil.Discard, r.Body)
|
||||
defer r.Body.Close()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This is a bit different then the standard template.parseFiles code in that it gives us hiarchial templates
|
||||
// header.html
|
||||
// mydirectory/service.html ...
|
||||
|
@ -88,7 +91,7 @@ func (s *Server) parseTemplates(t *template.Template, filenames ...string) (*tem
|
|||
}
|
||||
data := string(b)
|
||||
name := strings.TrimPrefix(filename, s.templates+"/")
|
||||
log.Println("Template:", name)
|
||||
// log.Println("Template:", name)
|
||||
|
||||
// First template becomes return value if not already defined,
|
||||
// and we use that one for subsequent New calls to associate
|
||||
|
@ -118,16 +121,16 @@ func (s *Server) loadTemplates() *template.Template {
|
|||
|
||||
err := filepath.Walk(path.Join(s.path, s.templates), func(path string, info os.FileInfo, err error) error {
|
||||
if strings.Contains(path, ".html") {
|
||||
_,err := s.parseTemplates(tmpl, path)
|
||||
_, err := s.parseTemplates(tmpl, path)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
/*
|
||||
_, err = tmpl.ParseFiles(path)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
*/
|
||||
/*
|
||||
_, err = tmpl.ParseFiles(path)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
*/
|
||||
}
|
||||
return err
|
||||
})
|
||||
|
@ -182,9 +185,8 @@ func (s *Server) HandleFuncCustomAuth(auth auth.AuthManager, path string, f func
|
|||
return s.router.HandleFunc(path, s.authenticated(auth, f))
|
||||
}
|
||||
|
||||
func (s *Server) HandleFunc(path string, f func(c *Context)) error {
|
||||
s.router.HandleFunc(path, s.wrapper(f))
|
||||
return nil
|
||||
func (s *Server) HandleFunc(path string, f func(c *Context)) *mux.Route {
|
||||
return s.router.HandleFunc(path, s.wrapper(f))
|
||||
}
|
||||
|
||||
func (s *Server) SetDebug(enable bool) {
|
||||
|
@ -202,6 +204,9 @@ func (s *Server) SetTemplatePath(path string) {
|
|||
s.templates = path
|
||||
}
|
||||
|
||||
func (s *Server) Router() *mux.Router {
|
||||
return s.router
|
||||
}
|
||||
|
||||
func (s *Server) ServeTLS(keyPath string, certPath string) error {
|
||||
srv := &http.Server{
|
||||
|
@ -228,6 +233,22 @@ func (s *Server) Serve() error {
|
|||
return srv.ListenAndServe()
|
||||
}
|
||||
|
||||
func (s *Server) WithStaticFiles(prefix string, path string) *Server {
|
||||
s.router.PathPrefix(prefix).Handler(http.StripPrefix(prefix, http.FileServer(http.Dir(path))))
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Server) WithTheme(themeURL string) *Server {
|
||||
s.theme = themeURL
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Server) WithDebug(debugURL string) *Server {
|
||||
sub := s.router.PathPrefix("/sovereign/debug").Subrouter()
|
||||
setupDebugHandler(sub)
|
||||
return s
|
||||
}
|
||||
|
||||
func New(address string, path string, auth auth.AuthManager) *Server {
|
||||
s := Server{
|
||||
router: mux.NewRouter(),
|
||||
|
@ -238,6 +259,6 @@ func New(address string, path string, auth auth.AuthManager) *Server {
|
|||
theme: "/static/css/default.css",
|
||||
}
|
||||
|
||||
s.router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(s.path+"static/"))))
|
||||
//s.router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(s.path+"static/"))))
|
||||
return &s
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue