Cleanup the API a bit add debug functions
This commit is contained in:
parent
7ed387dee5
commit
eab56d649f
49
context.go
49
context.go
|
@ -1,8 +1,11 @@
|
||||||
package snap
|
package snap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"git.thirdmartini.com/pub/snap/auth"
|
"git.thirdmartini.com/pub/snap/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -29,7 +32,6 @@ func (c *Context) Writer() http.ResponseWriter {
|
||||||
return c.w
|
return c.w
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (c *Context) GetUser() string {
|
func (c *Context) GetUser() string {
|
||||||
if c.auth == nil {
|
if c.auth == nil {
|
||||||
return ""
|
return ""
|
||||||
|
@ -41,12 +43,10 @@ func (c *Context) Error(code int, msg string) {
|
||||||
c.srv.renderError(c.w, code, msg)
|
c.srv.renderError(c.w, code, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (c *Context) Reply(msg string) {
|
func (c *Context) Reply(msg string) {
|
||||||
c.srv.reply(c.w, msg)
|
c.srv.reply(c.w, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (c *Context) ReplyObject(obj interface{}) {
|
func (c *Context) ReplyObject(obj interface{}) {
|
||||||
msg, err := json.Marshal(obj)
|
msg, err := json.Marshal(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -55,29 +55,35 @@ func (c *Context) ReplyObject(obj interface{}) {
|
||||||
c.Reply(string(msg))
|
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{}) {
|
func (c *Context) Render(tmpl string, content interface{}) {
|
||||||
c.srv.render(c.w, tmpl, content)
|
c.srv.render(c.w, tmpl, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (c *Context) RenderEx(tmpl string, content interface{}) {
|
func (c *Context) RenderEx(tmpl string, content interface{}) {
|
||||||
cnt := SnapContent {
|
cnt := SnapContent{
|
||||||
User: c.GetUser(),
|
User: c.GetUser(),
|
||||||
Theme: c.srv.theme,
|
Theme: c.srv.theme,
|
||||||
Content:content,
|
Content: content,
|
||||||
}
|
}
|
||||||
c.srv.render(c.w, tmpl, &cnt)
|
c.srv.render(c.w, tmpl, &cnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) GetVar(k string) ( string, bool) {
|
func (c *Context) GetVar(k string) (string, bool) {
|
||||||
v,ok := c.vars[k]
|
v, ok := c.vars[k]
|
||||||
return v, ok
|
return v, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) GetVarDefault(k string,def string) (string) {
|
func (c *Context) GetVarDefault(k string, def string) string {
|
||||||
v,ok := c.vars[k]
|
v, ok := c.vars[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
return def
|
return def
|
||||||
}
|
}
|
||||||
|
@ -91,3 +97,22 @@ func (c *Context) ParseForm() error {
|
||||||
func (c *Context) FormValue(k string) string {
|
func (c *Context) FormValue(k string) string {
|
||||||
return c.r.FormValue(k)
|
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)
|
||||||
|
}
|
45
server.go
45
server.go
|
@ -1,12 +1,13 @@
|
||||||
package snap
|
package snap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -64,11 +65,13 @@ func (s *Server) wrapper(handle func(c *Context)) http.HandlerFunc {
|
||||||
log.Debug("request: ", r.RequestURI)
|
log.Debug("request: ", r.RequestURI)
|
||||||
c := s.makeContext(nil, w, r)
|
c := s.makeContext(nil, w, r)
|
||||||
handle(c)
|
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
|
// This is a bit different then the standard template.parseFiles code in that it gives us hiarchial templates
|
||||||
// header.html
|
// header.html
|
||||||
// mydirectory/service.html ...
|
// mydirectory/service.html ...
|
||||||
|
@ -88,7 +91,7 @@ func (s *Server) parseTemplates(t *template.Template, filenames ...string) (*tem
|
||||||
}
|
}
|
||||||
data := string(b)
|
data := string(b)
|
||||||
name := strings.TrimPrefix(filename, s.templates+"/")
|
name := strings.TrimPrefix(filename, s.templates+"/")
|
||||||
log.Println("Template:", name)
|
// log.Println("Template:", name)
|
||||||
|
|
||||||
// First template becomes return value if not already defined,
|
// First template becomes return value if not already defined,
|
||||||
// and we use that one for subsequent New calls to associate
|
// 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 {
|
err := filepath.Walk(path.Join(s.path, s.templates), func(path string, info os.FileInfo, err error) error {
|
||||||
if strings.Contains(path, ".html") {
|
if strings.Contains(path, ".html") {
|
||||||
_,err := s.parseTemplates(tmpl, path)
|
_, err := s.parseTemplates(tmpl, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
_, err = tmpl.ParseFiles(path)
|
_, err = tmpl.ParseFiles(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
return 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))
|
return s.router.HandleFunc(path, s.authenticated(auth, f))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) HandleFunc(path string, f func(c *Context)) error {
|
func (s *Server) HandleFunc(path string, f func(c *Context)) *mux.Route {
|
||||||
s.router.HandleFunc(path, s.wrapper(f))
|
return s.router.HandleFunc(path, s.wrapper(f))
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) SetDebug(enable bool) {
|
func (s *Server) SetDebug(enable bool) {
|
||||||
|
@ -202,6 +204,9 @@ func (s *Server) SetTemplatePath(path string) {
|
||||||
s.templates = path
|
s.templates = path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) Router() *mux.Router {
|
||||||
|
return s.router
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) ServeTLS(keyPath string, certPath string) error {
|
func (s *Server) ServeTLS(keyPath string, certPath string) error {
|
||||||
srv := &http.Server{
|
srv := &http.Server{
|
||||||
|
@ -228,6 +233,22 @@ func (s *Server) Serve() error {
|
||||||
return srv.ListenAndServe()
|
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 {
|
func New(address string, path string, auth auth.AuthManager) *Server {
|
||||||
s := Server{
|
s := Server{
|
||||||
router: mux.NewRouter(),
|
router: mux.NewRouter(),
|
||||||
|
@ -238,6 +259,6 @@ func New(address string, path string, auth auth.AuthManager) *Server {
|
||||||
theme: "/static/css/default.css",
|
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
|
return &s
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue