package snap import ( "github.com/gorilla/mux" "html/template" "net/http" "os" "path/filepath" "strings" "time" "path" "fmt" "git.thirdmartini.com/pub/fancylog" "git.thirdmartini.com/pub/snap/auth" ) type Server interface { Serve() error ServeTLS(keyPath string, certPath string) error SetDebug(enable bool) HandleFunc(path string, f func(c *Context)) error HandleFuncAuthenticated(path string, f func(c *Context)) error } type server struct { address string path string debug bool auth auth.AuthManager router *mux.Router cachedTmpl *template.Template } func (s *server) plain(f func(c *Context)) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { c := &Context{ Username: "", r: r, w: w, srv: s, } f(c) } } func (s *server) authenticated(handle func(c *Context)) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { name, ok := s.auth.DoAuth( w, r ) if !ok { http.Error(w, "Not authorized", 401) } else { c:= &Context{ Username: name, r: r, w: w, srv: s, } handle(c) } } } func (s *server) wrapper(handle func(c *Context)) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { c:= &Context{ Username: "", r: r, w: w, srv: s, } handle(c) } } func (s *server) loadTemplates() *template.Template { tmpl := template.New("") err := filepath.Walk(path.Join(s.path, "templates"), func(path string, info os.FileInfo, err error) error { if strings.Contains(path, ".html") { _, err = tmpl.ParseFiles(path) if err != nil { log.Println(err) } } return err }) if err != nil { log.Fatal(err) } return tmpl } func (s *server) getTemplates() *template.Template { if s.debug { return s.loadTemplates() } if s.cachedTmpl == nil { s.cachedTmpl = s.loadTemplates() } return s.cachedTmpl } func (s *server) render(w http.ResponseWriter, tmpl string, content interface{} ) { s.getTemplates().ExecuteTemplate(w, tmpl, content) } func (s *server) HandleFuncAuthenticated(path string, f func(c *Context)) error { if s.auth == nil { return fmt.Errorf("no auth manager provided") } s.router.HandleFunc(path, s.authenticated(f)) return nil } func (s *server) HandleFunc(path string, f func(c *Context)) error { s.router.HandleFunc(path, s.wrapper(f)) return nil } func (s *server) SetDebug(enable bool) { s.debug = enable } func (s *server) ServeTLS(keyPath string, certPath string) error { srv := &http.Server{ Handler: s.router, Addr: s.address, // Good practice: enforce timeouts for servers you create! WriteTimeout: 15 * time.Second, ReadTimeout: 15 * time.Second, } return srv.ListenAndServeTLS(keyPath, certPath) } // Serve serve content forever func (s *server) Serve() error { srv := &http.Server{ Handler: s.router, Addr: s.address, // Good practice: enforce timeouts for servers you create! WriteTimeout: 15 * time.Second, ReadTimeout: 15 * time.Second, } return srv.ListenAndServe() } func New(address string, path string, auth auth.AuthManager) Server { s := server{ router: mux.NewRouter(), auth: auth, address: address, path: path, } s.router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(s.path+"static/")))) return &s }