vinegar/servlet/staticRoute.go
2022-08-15 13:45:30 -04:00

167 lines
4.7 KiB
Go

package servlet
import (
util "geniuscartel.xyz/vinegar/vinegarUtil"
"net/http"
"path"
"strings"
)
type (
FileRoute struct {
*VinegarRoute
srv *VinegarServlet
fileRoot string
UseCache bool
}
RouteConstructor func(servlet *VinegarServlet, urlPattern string, pathlike string, useCache bool) *FileRoute
)
var NewTextRoute RouteConstructor = func(servlet *VinegarServlet, urlPattern string, pathlike string, useCache bool) *FileRoute {
defaultPrune := strings.Replace(urlPattern, ".*", "", -1)
route := FileRoute{srv: servlet, fileRoot: pathlike, UseCache: useCache}
textRouteHandler := createCompressibleFileServletFunction(&route, defaultPrune, pathlike)
rootRoute := NewServletRoute(urlPattern, textRouteHandler) //i *still* kinda don't like this pattern
route.VinegarRoute = rootRoute
servlet.AddRoute(route.VinegarRoute)
return &route
}
var NewImageRoute RouteConstructor = func(servlet *VinegarServlet, urlPattern string, pathlike string, useCache bool) *FileRoute {
defaultPrune := strings.Replace(urlPattern, ".*", "", -1)
route := FileRoute{srv: servlet, fileRoot: pathlike, UseCache: useCache}
rootRoute := NewServletRoute(urlPattern, createUncompressedFileServletFunction(&route, defaultPrune, pathlike))
route.VinegarRoute = rootRoute //i *kinda* don't like this pattern
servlet.AddRoute(route.VinegarRoute)
return &route
}
var NewSingleFileRoute RouteConstructor = func(servlet *VinegarServlet, urlPattern string, pathlike string, useCache bool) *FileRoute {
route := FileRoute{
srv: servlet,
fileRoot: pathlike,
UseCache: useCache,
}
singleFileServletHandler := createSingleFileServletFunction(&route)
sfCache := util.NewSingleFileCache(pathlike)
parentRoute := NewServletRoute(urlPattern, singleFileServletHandler)
parentRoute.Handler = singleFileServletHandler
parentRoute.Cache = sfCache
route.VinegarRoute = parentRoute
servlet.AddRoute(route.VinegarRoute)
return &route
}
func createSingleFileServletFunction(route *FileRoute) VinegarHandlerFunction {
var fun VinegarHandlerFunction = func(w http.ResponseWriter, req *http.Request) {
var cache *util.LruEntry
var exists bool
if route.UseCache {
cache, exists = route.Cache.Get("")
} else {
cache, exists = route.Cache.GetFresh("")
}
if !exists {
route.srv.SendError(w, req, 404, "File not found.")
return
}
var content []byte
if clientAcceptsGzip(req) {
content = cache.CompressedContent
w.Header().Add(ContentEncodingHeaderKey, "gzip")
} else {
content = cache.Content
}
w.Header().Add(ContentTypeHeaderKey, cache.MimeType)
_, err := w.Write(content)
if err != nil {
panic(err)
}
}
return fun
}
func createCompressibleFileServletFunction(route *FileRoute, basePattern string, pathlike string) VinegarHandlerFunction {
var fun VinegarHandlerFunction = func(w http.ResponseWriter, req *http.Request) {
stub := strings.Replace(req.URL.Path, basePattern, "", 1)
cachedContent, exists := route.Cache.Get(stub)
//i don't like this logic below. we need to streamline this a lot better. it's a twisty jungle right now
resourcePath := path.Join(pathlike, stub)
if !exists {
content, fileExists := util.GetDiskContent(resourcePath)
if fileExists {
if route.UseCache {
route.Cache.Put(stub, resourcePath)
cachedContent, _ = route.Cache.Get(stub)
} else {
w.Header().Add(ContentTypeHeaderKey, util.GuessMimetype(stub))
w.Write(*content)
return
}
} else {
route.srv.SendError(w, req, 404, "Couldn't find your content.")
return
}
}
w.Header().Add(ContentTypeHeaderKey, cachedContent.MimeType)
var err error = nil
if clientAcceptsGzip(req) {
w.Header().Add(ContentEncodingHeaderKey, "gzip")
_, err = w.Write(cachedContent.CompressedContent)
} else {
_, err = w.Write(cachedContent.Content)
}
if err != nil {
panic(err)
}
}
return fun
}
func createUncompressedFileServletFunction(route *FileRoute, basePattern string, pathlike string) VinegarHandlerFunction {
var fun VinegarHandlerFunction = func(w http.ResponseWriter, req *http.Request) {
stub := strings.Replace(req.URL.Path, basePattern, "", 1)
resourcePath := path.Join(pathlike, stub)
entry, exists := route.Cache.Get(stub)
if !exists {
route.Cache.Put(stub, resourcePath)
entry, exists = route.Cache.Get(stub)
}
if exists {
w.Header().Add(ContentTypeHeaderKey, util.GuessMimetype(stub))
_, err := w.Write(entry.Content)
if err != nil {
panic(err)
}
return
} else {
route.srv.SendError(w, req, 404, "Couldn't find your content.")
}
}
return fun
}
func clientAcceptsGzip(req *http.Request) bool {
encodings := req.Header.Get(AcceptEncodingHeaderKey)
return strings.Contains(encodings, "gzip")
}