package files
import (
"fmt"
"io/fs"
"path/filepath"
"strings"
"alin.ovh/homestead/shared/storage"
"alin.ovh/x/log"
"github.com/Southclaws/fault"
"github.com/Southclaws/fault/fmsg"
)
type Reader struct {
root string
log *log.Logger
files map[string]*storage.File
}
func NewReader(path string, log *log.Logger) (*Reader, error) {
r := &Reader{
root: path,
log: log,
files: make(map[string]*storage.File),
}
if err := r.registerContentFiles(); err != nil {
return nil, fault.Wrap(err, fmsg.With("registering content files"))
}
return r, nil
}
func (r *Reader) GetFile(urlPath string) (*storage.File, error) {
return r.files[urlPath], nil
}
func (r *Reader) CanonicalisePath(path string) (cPath string, differs bool) {
cPath = path
switch {
case strings.HasSuffix(path, "/index.html"):
cPath, differs = strings.CutSuffix(path, "index.html")
case strings.HasSuffix(path, ".html"):
cPath, differs = strings.CutSuffix(path, ".html")
case !strings.HasSuffix(path, "/") && r.files[path+"/"] != nil:
cPath, differs = path+"/", true
case strings.HasSuffix(path, "/"):
if cPath, differs := strings.CutSuffix(path, "/"); differs && r.files[cPath] != nil {
return cPath, differs
}
}
return cPath, differs
}
func (r *Reader) registerFile(urlpath string, filepath string) error {
file, err := r.OpenFile(urlpath, filepath)
if err != nil {
return fault.Wrap(err, fmsg.With(fmt.Sprintf("could not register file %s", filepath)))
}
r.files[urlpath] = file
return nil
}
func (r *Reader) registerContentFiles() error {
err := filepath.WalkDir(r.root, func(filePath string, f fs.DirEntry, err error) error {
if err != nil {
return fault.Wrap(err, fmsg.With(fmt.Sprintf("failed to access path %s", filePath)))
}
if f.IsDir() {
return nil
}
relPath, err := filepath.Rel(r.root, filePath)
if err != nil {
return fault.Wrap(
err,
fmsg.With(fmt.Sprintf("failed to make path relative, path: %s", filePath)),
)
}
urlPath := fileNameToPathName("/" + relPath)
switch filepath.Ext(relPath) {
case ".br", ".gz", ".zstd":
return nil
}
r.log.Debug("registering file", "url", urlPath, "filename", relPath)
return r.registerFile(urlPath, filePath)
})
if err != nil {
return fault.Wrap(err, fmsg.With("could not walk directory"))
}
return nil
}
shared/storage/files/reader.go (view raw)