Cleanup the API a bit add debug functions

This commit is contained in:
ssobolewski 2019-01-03 17:38:02 -07:00
parent 7ed387dee5
commit eab56d649f
3 changed files with 139 additions and 36 deletions

View File

@ -1,8 +1,11 @@
package snap
import (
"net/http"
"encoding/json"
"io/ioutil"
"net/http"
"strconv"
"git.thirdmartini.com/pub/snap/auth"
)
@ -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 {
cnt := SnapContent{
User: c.GetUser(),
Theme: c.srv.theme,
Content:content,
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
}
@ -91,3 +97,22 @@ 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)
}

57
debug.go Normal file
View File

@ -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)
}

View File

@ -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)
}
*/
*/
}
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
}