cachefs/pkg/srv/interceptor.go
2022-03-23 01:09:12 +01:00

152 lines
2.9 KiB
Go

// Copyright (C) 2022 Marius Schellenberger
package srv
import (
"bytes"
"encoding/xml"
"html/template"
"net/http"
"strings"
"cachefs/pkg/fs"
"golang.org/x/exp/slices"
)
type statusInterceptor struct {
w http.ResponseWriter
status int
}
func (s *statusInterceptor) Header() http.Header {
return s.w.Header()
}
func (s *statusInterceptor) Write(p []byte) (int, error) {
return s.w.Write(p)
}
func (s *statusInterceptor) WriteHeader(statusCode int) {
s.w.WriteHeader(statusCode)
s.status = statusCode
}
func (s *statusInterceptor) Status() int {
if s.status == 0 {
return http.StatusOK
}
return s.status
}
type dirContents struct {
AllPaths []string `xml:"a"`
Base string `xml:"-"`
Dirs dirs `xml:"-"`
Files files `xml:"-"`
}
type dir struct {
Name template.HTML
URI template.HTML
}
type dirs []dir
func (dirs) Less(i, j dir) bool { return i.Name < j.Name }
type file struct {
Name template.HTML
URI template.HTML
Anchor string
Status int
Running bool
}
type files []file
func (files) Less(i, j file) bool { return i.Name < j.Name }
type responseInterceptor struct {
buf bytes.Buffer
w http.ResponseWriter
status int
}
func (r *responseInterceptor) Header() http.Header {
return r.w.Header()
}
func (r *responseInterceptor) Write(p []byte) (int, error) {
return r.buf.Write(p)
}
func (r *responseInterceptor) WriteHeader(statusCode int) {
r.status = statusCode
}
func (r *responseInterceptor) Status() int {
if r.status == 0 {
return http.StatusOK
}
return r.status
}
func (r *responseInterceptor) GetPaths(path string, fs *fs.FS, relative bool) (dc dirContents, err error) {
buf := r.buf.Bytes()
buf = bytes.ReplaceAll(buf, []byte{'&'}, []byte("&#38;"))
err = xml.Unmarshal(buf, &dc)
if err != nil {
return
}
dc.Base = path
path = strings.TrimSuffix(path, "/")
for _, p := range dc.AllPaths {
p = strings.ReplaceAll(p, "&amp;", "&")
p = strings.ReplaceAll(p, "&#39;", "'")
name := template.HTML(p)
full := path + "/" + p
uri := template.HTML(full)
if relative {
uri = template.HTML(p)
}
if p[len(p)-1] == '/' {
dc.Dirs = append(dc.Dirs, dir{
Name: name,
URI: uri,
})
} else {
dc.Files = append(dc.Files, file{
Name: name,
URI: uri,
Anchor: anchor(p),
Status: fs.CacheStatus(full),
})
}
}
slices.SortFunc(dc.Dirs, dc.Dirs.Less)
slices.SortFunc(dc.Files, dc.Files.Less)
return
}
func getPreloads(path string, fs *fs.FS) (dc dirContents) {
dc.Base = path
for _, p := range fs.Preloads() {
dc.Files = append(dc.Files, file{
Name: template.HTML(p.Name),
URI: template.HTML(p.Name),
Status: p.Status,
Running: p.Running,
})
}
slices.SortFunc(dc.Files, dc.Files.Less)
return
}
func anchor(s string) string {
if i := strings.LastIndex(s, "/"); i > 0 && i+1 < len(s) {
s = s[i+1:]
}
s = strings.ReplaceAll(s, " ", "_")
return strings.ToLower(s)
}