mirror of
https://github.com/datarhei/core.git
synced 2025-09-27 04:16:25 +08:00
180 lines
4.1 KiB
Go
180 lines
4.1 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/datarhei/core/v16/http/api"
|
|
"github.com/datarhei/core/v16/http/fs"
|
|
"github.com/datarhei/core/v16/http/handler/util"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
)
|
|
|
|
// The FSHandler type provides handlers for manipulating a filesystem
|
|
type FSHandler struct {
|
|
fs fs.FS
|
|
}
|
|
|
|
// NewFS return a new FSHandler type. You have to provide a filesystem to act on.
|
|
func NewFS(fs fs.FS) *FSHandler {
|
|
return &FSHandler{
|
|
fs: fs,
|
|
}
|
|
}
|
|
|
|
func (h *FSHandler) GetFile(c echo.Context) error {
|
|
path := util.PathWildcardParam(c)
|
|
|
|
mimeType := c.Response().Header().Get(echo.HeaderContentType)
|
|
c.Response().Header().Del(echo.HeaderContentType)
|
|
|
|
file := h.fs.Filesystem.Open(path)
|
|
if file == nil {
|
|
return api.Err(http.StatusNotFound, "File not found", path)
|
|
}
|
|
|
|
stat, _ := file.Stat()
|
|
|
|
if len(h.fs.DefaultFile) != 0 {
|
|
if stat.IsDir() {
|
|
path = filepath.Join(path, h.fs.DefaultFile)
|
|
|
|
file.Close()
|
|
|
|
file = h.fs.Filesystem.Open(path)
|
|
if file == nil {
|
|
return api.Err(http.StatusNotFound, "File not found", path)
|
|
}
|
|
|
|
stat, _ = file.Stat()
|
|
}
|
|
}
|
|
|
|
defer file.Close()
|
|
|
|
c.Response().Header().Set("Last-Modified", stat.ModTime().UTC().Format("Mon, 02 Jan 2006 15:04:05 GMT"))
|
|
|
|
if path, ok := stat.IsLink(); ok {
|
|
path = filepath.Clean("/" + path)
|
|
|
|
if path[0] == '/' {
|
|
path = path[1:]
|
|
}
|
|
|
|
return c.Redirect(http.StatusMovedPermanently, path)
|
|
}
|
|
|
|
c.Response().Header().Set(echo.HeaderContentType, mimeType)
|
|
|
|
if c.Request().Method == "HEAD" {
|
|
return c.Blob(http.StatusOK, "application/data", nil)
|
|
}
|
|
|
|
return c.Stream(http.StatusOK, "application/data", file)
|
|
}
|
|
|
|
func (h *FSHandler) PutFile(c echo.Context) error {
|
|
path := util.PathWildcardParam(c)
|
|
|
|
c.Response().Header().Del(echo.HeaderContentType)
|
|
|
|
req := c.Request()
|
|
|
|
_, created, err := h.fs.Filesystem.WriteFileReader(path, req.Body)
|
|
if err != nil {
|
|
return api.Err(http.StatusBadRequest, "Bad request", "%s", err)
|
|
}
|
|
|
|
if h.fs.Cache != nil {
|
|
h.fs.Cache.Delete(path)
|
|
|
|
if len(h.fs.DefaultFile) != 0 {
|
|
if strings.HasSuffix(path, "/"+h.fs.DefaultFile) {
|
|
path := strings.TrimSuffix(path, h.fs.DefaultFile)
|
|
h.fs.Cache.Delete(path)
|
|
}
|
|
}
|
|
}
|
|
|
|
c.Response().Header().Set("Content-Location", req.URL.RequestURI())
|
|
|
|
if created {
|
|
return c.String(http.StatusCreated, "")
|
|
}
|
|
|
|
return c.NoContent(http.StatusNoContent)
|
|
}
|
|
|
|
func (h *FSHandler) DeleteFile(c echo.Context) error {
|
|
path := util.PathWildcardParam(c)
|
|
|
|
c.Response().Header().Del(echo.HeaderContentType)
|
|
|
|
size := h.fs.Filesystem.Remove(path)
|
|
|
|
if h.fs.Cache != nil {
|
|
h.fs.Cache.Delete(path)
|
|
|
|
if len(h.fs.DefaultFile) != 0 {
|
|
if strings.HasSuffix(path, "/"+h.fs.DefaultFile) {
|
|
path := strings.TrimSuffix(path, h.fs.DefaultFile)
|
|
h.fs.Cache.Delete(path)
|
|
}
|
|
}
|
|
}
|
|
|
|
if size < 0 {
|
|
return api.Err(http.StatusNotFound, "File not found", path)
|
|
}
|
|
|
|
return c.String(http.StatusOK, "Deleted: "+path)
|
|
}
|
|
|
|
func (h *FSHandler) ListFiles(c echo.Context) error {
|
|
pattern := util.DefaultQuery(c, "glob", "")
|
|
sortby := util.DefaultQuery(c, "sort", "none")
|
|
order := util.DefaultQuery(c, "order", "asc")
|
|
|
|
files := h.fs.Filesystem.List("/", pattern)
|
|
|
|
var sortFunc func(i, j int) bool
|
|
|
|
switch sortby {
|
|
case "name":
|
|
if order == "desc" {
|
|
sortFunc = func(i, j int) bool { return files[i].Name() > files[j].Name() }
|
|
} else {
|
|
sortFunc = func(i, j int) bool { return files[i].Name() < files[j].Name() }
|
|
}
|
|
case "size":
|
|
if order == "desc" {
|
|
sortFunc = func(i, j int) bool { return files[i].Size() > files[j].Size() }
|
|
} else {
|
|
sortFunc = func(i, j int) bool { return files[i].Size() < files[j].Size() }
|
|
}
|
|
default:
|
|
if order == "asc" {
|
|
sortFunc = func(i, j int) bool { return files[i].ModTime().Before(files[j].ModTime()) }
|
|
} else {
|
|
sortFunc = func(i, j int) bool { return files[i].ModTime().After(files[j].ModTime()) }
|
|
}
|
|
}
|
|
|
|
sort.Slice(files, sortFunc)
|
|
|
|
var fileinfos []api.FileInfo = make([]api.FileInfo, len(files))
|
|
|
|
for i, f := range files {
|
|
fileinfos[i] = api.FileInfo{
|
|
Name: f.Name(),
|
|
Size: f.Size(),
|
|
LastMod: f.ModTime().Unix(),
|
|
}
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, fileinfos)
|
|
}
|