mirror of
				https://github.com/datarhei/core.git
				synced 2025-10-31 11:26:52 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			173 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package api
 | |
| 
 | |
| import (
 | |
| 	"io"
 | |
| 	"net/http"
 | |
| 	"net/url"
 | |
| 	"sort"
 | |
| 
 | |
| 	"github.com/datarhei/core/v16/http/api"
 | |
| 	"github.com/datarhei/core/v16/http/handler"
 | |
| 	"github.com/datarhei/core/v16/http/handler/util"
 | |
| 	"github.com/datarhei/core/v16/io/fs"
 | |
| 
 | |
| 	"github.com/labstack/echo/v4"
 | |
| )
 | |
| 
 | |
| // The MemFSHandler type provides handlers for manipulating a filesystem
 | |
| type MemFSHandler struct {
 | |
| 	filesystem fs.Filesystem
 | |
| 	handler    *handler.MemFSHandler
 | |
| }
 | |
| 
 | |
| // NewMemFS return a new MemFS type. You have to provide a filesystem to act on.
 | |
| func NewMemFS(fs fs.Filesystem) *MemFSHandler {
 | |
| 	return &MemFSHandler{
 | |
| 		filesystem: fs,
 | |
| 		handler:    handler.NewMemFS(fs),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // GetFileAPI returns the file at the given path
 | |
| // @Summary Fetch a file from the memory filesystem
 | |
| // @Description Fetch a file from the memory filesystem
 | |
| // @ID memfs-3-get-file
 | |
| // @Produce application/data
 | |
| // @Produce json
 | |
| // @Param path path string true "Path to file"
 | |
| // @Success 200 {file} byte
 | |
| // @Success 301 {string} string
 | |
| // @Failure 404 {object} api.Error
 | |
| // @Security ApiKeyAuth
 | |
| // @Router /api/v3/fs/mem/{path} [get]
 | |
| func (h *MemFSHandler) GetFile(c echo.Context) error {
 | |
| 	return h.handler.GetFile(c)
 | |
| }
 | |
| 
 | |
| // PutFileAPI adds or overwrites a file at the given path
 | |
| // @Summary Add a file to the memory filesystem
 | |
| // @Description Writes or overwrites a file on the memory filesystem
 | |
| // @ID memfs-3-put-file
 | |
| // @Accept application/data
 | |
| // @Produce text/plain
 | |
| // @Produce json
 | |
| // @Param path path string true "Path to file"
 | |
| // @Param data body []byte true "File data"
 | |
| // @Success 201 {string} string
 | |
| // @Success 204 {string} string
 | |
| // @Failure 507 {object} api.Error
 | |
| // @Security ApiKeyAuth
 | |
| // @Router /api/v3/fs/mem/{path} [put]
 | |
| func (h *MemFSHandler) PutFile(c echo.Context) error {
 | |
| 	return h.handler.PutFile(c)
 | |
| }
 | |
| 
 | |
| // DeleteFileAPI removes a file from the filesystem
 | |
| // @Summary Remove a file from the memory filesystem
 | |
| // @Description Remove a file from the memory filesystem
 | |
| // @ID memfs-3-delete-file
 | |
| // @Produce text/plain
 | |
| // @Param path path string true "Path to file"
 | |
| // @Success 200 {string} string
 | |
| // @Failure 404 {object} api.Error
 | |
| // @Security ApiKeyAuth
 | |
| // @Router /api/v3/fs/mem/{path} [delete]
 | |
| func (h *MemFSHandler) DeleteFile(c echo.Context) error {
 | |
| 	return h.handler.DeleteFile(c)
 | |
| }
 | |
| 
 | |
| // PatchFile creates a symbolic link to a file in the filesystem
 | |
| // @Summary Create a link to a file in the memory filesystem
 | |
| // @Description Create a link to a file in the memory filesystem. The file linked to has to exist.
 | |
| // @ID memfs-3-patch
 | |
| // @Accept application/data
 | |
| // @Produce text/plain
 | |
| // @Produce json
 | |
| // @Param path path string true "Path to file"
 | |
| // @Param url body string true "Path to the file to link to"
 | |
| // @Success 201 {string} string
 | |
| // @Failure 400 {object} api.Error
 | |
| // @Security ApiKeyAuth
 | |
| // @Router /api/v3/fs/mem/{path} [patch]
 | |
| func (h *MemFSHandler) PatchFile(c echo.Context) error {
 | |
| 	path := util.PathWildcardParam(c)
 | |
| 
 | |
| 	c.Response().Header().Del(echo.HeaderContentType)
 | |
| 
 | |
| 	req := c.Request()
 | |
| 
 | |
| 	body, err := io.ReadAll(req.Body)
 | |
| 	if err != nil {
 | |
| 		return api.Err(http.StatusBadRequest, "Failed reading request body", "%s", err)
 | |
| 	}
 | |
| 
 | |
| 	u, err := url.Parse(string(body))
 | |
| 	if err != nil {
 | |
| 		return api.Err(http.StatusBadRequest, "Body doesn't contain a valid path", "%s", err)
 | |
| 	}
 | |
| 
 | |
| 	if err := h.filesystem.Symlink(u.Path, path); err != nil {
 | |
| 		return api.Err(http.StatusBadRequest, "Failed to create symlink", "%s", err)
 | |
| 	}
 | |
| 
 | |
| 	c.Response().Header().Set("Content-Location", req.URL.RequestURI())
 | |
| 
 | |
| 	return c.String(http.StatusCreated, "")
 | |
| }
 | |
| 
 | |
| // ListFiles lists all files on the filesystem
 | |
| // @Summary List all files on the memory filesystem
 | |
| // @Description List all files on the memory filesystem. The listing can be ordered by name, size, or date of last modification in ascending or descending order.
 | |
| // @ID memfs-3-list-files
 | |
| // @Produce json
 | |
| // @Param glob query string false "glob pattern for file names"
 | |
| // @Param sort query string false "none, name, size, lastmod"
 | |
| // @Param order query string false "asc, desc"
 | |
| // @Success 200 {array} api.FileInfo
 | |
| // @Security ApiKeyAuth
 | |
| // @Router /api/v3/fs/mem [get]
 | |
| func (h *MemFSHandler) ListFiles(c echo.Context) error {
 | |
| 	pattern := util.DefaultQuery(c, "glob", "")
 | |
| 	sortby := util.DefaultQuery(c, "sort", "none")
 | |
| 	order := util.DefaultQuery(c, "order", "asc")
 | |
| 
 | |
| 	files := h.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)
 | |
| }
 | 
