package servlet import ( "encoding/json" "fmt" "geniuscartel.xyz/vinegar/vinegarUtil" "log" "net" "net/http" "regexp" "strconv" "time" ) const ( defaultLruSize = int64(1024 * 1024 * 50) ContentTypeHeaderKey = "Content-Type" ContentEncodingHeaderKey = "Content-Encoding" AcceptEncodingHeaderKey = "Accept-Encoding" ) type ErrorResponse struct { Code int Message string } type ( VinegarWebServlet struct { Port string Router VinegarWebRouter ErrorRoutes map[int]*TemplateRoute interrupts chan struct{} errors chan error } VinegarHandlerFunction func(w http.ResponseWriter, req *http.Request) ) func NewServlet(port string) *VinegarWebServlet { errs := make(map[int]*TemplateRoute) srv := VinegarWebServlet{Port: port, ErrorRoutes: errs, interrupts: make(chan struct{}, 500)} return &srv } func NewServletRoute(routePattern string, handleFunc VinegarHandlerFunction) *VinegarWebRoute { pattern := regexp.MustCompile(routePattern) route := VinegarWebRoute{Pattern: pattern, Handler: handleFunc, Cache: vinegarUtil.NewLRU(defaultLruSize)} return &route } func (s *VinegarWebServlet) AddErrorRoute(code int, route *TemplateRoute) { route.Announce() s.ErrorRoutes[code] = route } func (s *VinegarWebServlet) ServeHTTP(w http.ResponseWriter, req *http.Request) { err := s.Router.RouteRequest(w, req) if err != nil { http.NotFound(w, req) } } func (s *VinegarWebServlet) Start() error { if len(s.Router.Routes) < 1 { log.Fatal("No routes found for server. Nothing to listen and serve.") } l, listenErr := net.Listen("tcp", s.Port) if listenErr != nil { return listenErr } go func() { err := http.Serve(l, s) if err != nil { s.errors <- err } }() log.Printf("Listening on [%s]\n", s.Port) running := true for running { select { case err := <-s.errors: log.Printf("server on port %s failed: %v", s.Port, err) case <-s.interrupts: err := l.Close() if err != nil { return err } running = false default: time.Sleep(5) } } return nil } func (s *VinegarWebServlet) Shutdown() { s.interrupts <- struct{}{} } func (r *VinegarWebRoute) Announce() { log.Printf("Added route for [%s]\n", r.Pattern.String()) } func (s *VinegarWebServlet) SendError(w http.ResponseWriter, req *http.Request, code int, msg string, aErr error) { fmt.Printf("[%d][%s]. Rendering template for code %d with message: %s\n", code, req.URL.Path, code, msg) out, _ := json.Marshal(aErr) fmt.Println(string(out)) tmpl, exists := s.ErrorRoutes[code] if exists { err := tmpl.TemplateManager.AddMixin("code", strconv.Itoa(code)) if err != nil { http.Error(w, msg, code) return } err = tmpl.TemplateManager.AddMixin("msg", msg) if err != nil { http.Error(w, msg, code) return } w.WriteHeader(code) bitties, err := tmpl.TemplateManager.RenderTemplate(fmt.Sprintf("%d.html", code)) _, err = w.Write([]byte(bitties)) if err != nil { http.Error(w, msg, code) return } return } http.Error(w, msg, code) return }