vinegar/servlet/server.go
2023-08-01 10:29:57 -04:00

137 lines
3.0 KiB
Go

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
}