mirror of
				https://github.com/datarhei/core.git
				synced 2025-10-31 03:16:21 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			165 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			165 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package handler
 | |
| 
 | |
| import (
 | |
| 	"net/http"
 | |
| 	"path/filepath"
 | |
| 	"sort"
 | |
| 
 | |
| 	"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)
 | |
| 	}
 | |
| 
 | |
| 	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 size < 0 {
 | |
| 		return api.Err(http.StatusNotFound, "File not found", path)
 | |
| 	}
 | |
| 
 | |
| 	if h.fs.Cache != nil {
 | |
| 		h.fs.Cache.Delete(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)
 | |
| }
 | 
