155 lines
2.9 KiB
Go
155 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
|
|
Prio int
|
|
Errc 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("&"))
|
|
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, "&", "&")
|
|
p = strings.ReplaceAll(p, "'", "'")
|
|
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,
|
|
Prio: p.Prio,
|
|
Errc: p.Errc,
|
|
Running: p.Running,
|
|
})
|
|
}
|
|
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)
|
|
}
|