edge/pkg/bundle/filesystem.go

102 lines
1.9 KiB
Go

package bundle
import (
"bytes"
"context"
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
type FileSystem struct {
prefix string
bundle Bundle
}
func (fs *FileSystem) Open(name string) (http.File, error) {
if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) ||
strings.Contains(name, "\x00") {
return nil, errors.New("http: invalid character in file path")
}
p := path.Join(fs.prefix, strings.TrimPrefix(name, "/"))
ctx := logger.With(
context.Background(),
logger.F("filename", name),
)
logger.Debug(ctx, "opening file")
readCloser, fileInfo, err := fs.bundle.File(p)
if err != nil {
if os.IsNotExist(err) {
return nil, err
}
logger.Error(ctx, "could not open bundle file", logger.E(err))
return nil, errors.Wrapf(err, "could not open bundle file '%s'", p)
}
defer readCloser.Close()
file := &File{
fi: fileInfo,
}
if fileInfo.IsDir() {
files, err := fs.bundle.Dir(p)
if err != nil {
logger.Error(ctx, "could not read bundle directory", logger.E(err))
return nil, errors.Wrapf(err, "could not read bundle directory '%s'", p)
}
file.files = files
} else {
data, err := ioutil.ReadAll(readCloser)
if err != nil {
logger.Error(ctx, "could not read bundle file", logger.E(err))
return nil, errors.Wrapf(err, "could not read bundle file '%s'", p)
}
file.Reader = bytes.NewReader(data)
}
return file, nil
}
func NewFileSystem(prefix string, bundle Bundle) *FileSystem {
return &FileSystem{prefix, bundle}
}
type File struct {
*bytes.Reader
fi os.FileInfo
files []os.FileInfo
}
// A noop-closer.
func (f *File) Close() error {
return nil
}
func (f *File) Readdir(count int) ([]os.FileInfo, error) {
if f.fi.IsDir() && f.files != nil {
return f.files, nil
}
return nil, os.ErrNotExist
}
func (f *File) Stat() (os.FileInfo, error) {
return f.fi, nil
}