mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-01-05 19:21:23 -06:00
[server][core] move OpenRead, OpenWrite, ReadDir, and Walk to Resource
This commit is contained in:
@@ -32,14 +32,15 @@ type Resource interface {
|
||||
FSContentSize() int64
|
||||
FSContentSHA256() string
|
||||
FSContentType() string
|
||||
|
||||
ReadDir(recursive bool) ([]Resource, error)
|
||||
OpenRead(start, length int64) (io.ReadCloser, error)
|
||||
}
|
||||
|
||||
type FileSystem interface {
|
||||
ReadDir(r Resource, recursive bool) ([]Resource, error)
|
||||
OpenRead(r Resource, start, length int64) (io.ReadCloser, error)
|
||||
}
|
||||
|
||||
func ServeCollection(w http.ResponseWriter, r *http.Request, fs FileSystem, file Resource) {
|
||||
func ServeCollection(w http.ResponseWriter, r *http.Request, file Resource) {
|
||||
if !strings.HasSuffix(r.URL.Path, "/") {
|
||||
http.Redirect(w, r, r.URL.String()+"/", http.StatusMovedPermanently)
|
||||
return
|
||||
@@ -50,7 +51,7 @@ func ServeCollection(w http.ResponseWriter, r *http.Request, fs FileSystem, file
|
||||
}
|
||||
w.Header().Set("Last-Modified", file.FSModified().Format(http.TimeFormat))
|
||||
|
||||
files, err := fs.ReadDir(file, false)
|
||||
files, err := file.ReadDir(false)
|
||||
if err != nil {
|
||||
http.Error(w, "Error reading directory", http.StatusInternalServerError)
|
||||
return
|
||||
@@ -83,7 +84,7 @@ func ServeCollection(w http.ResponseWriter, r *http.Request, fs FileSystem, file
|
||||
fmt.Fprintf(w, "</pre>\n")
|
||||
}
|
||||
|
||||
func ServeResource(w http.ResponseWriter, r *http.Request, fs FileSystem, file Resource) {
|
||||
func ServeResource(w http.ResponseWriter, r *http.Request, file Resource) {
|
||||
w.Header().Set("Etag", file.FSContentSHA256())
|
||||
w.Header().Set("Last-Modified", file.FSModified().Format(http.TimeFormat))
|
||||
w.Header().Set("Content-Type", file.FSContentType())
|
||||
@@ -119,9 +120,9 @@ func ServeResource(w http.ResponseWriter, r *http.Request, fs FileSystem, file R
|
||||
sendSize = ra.length
|
||||
code = http.StatusPartialContent
|
||||
w.Header().Set("Content-Range", ra.contentRange(file.FSContentSize()))
|
||||
reader, err = fs.OpenRead(file, ra.start, ra.length)
|
||||
reader, err = file.OpenRead(ra.start, ra.length)
|
||||
} else {
|
||||
reader, err = fs.OpenRead(file, 0, -1)
|
||||
reader, err = file.OpenRead(0, -1)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -18,5 +18,5 @@ func handleCatRequest(c *gin.Context) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
serve.ServeResource(c.Writer, c.Request, fs, r)
|
||||
serve.ServeResource(c.Writer, c.Request, r)
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func LsResponseFromResource(f fs.FileSystem, r fs.Resource) ResourceLsResponse {
|
||||
InheritedPermissions: r.InheritedPermissions,
|
||||
}
|
||||
if r.Dir {
|
||||
children, err := f.ReadDir(r, false)
|
||||
children, err := r.ReadDir(false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func handleUploadRequest(c *gin.Context) {
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
out, err := f.OpenWrite(res)
|
||||
out, err := res.OpenWrite()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2,13 +2,11 @@ package webdav
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/shroff/phylum/server/internal/api/auth"
|
||||
webdav "github.com/shroff/phylum/server/internal/api/webdav/impl"
|
||||
"github.com/shroff/phylum/server/internal/core/fs"
|
||||
"github.com/shroff/phylum/server/internal/core/user"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -67,29 +65,8 @@ func (h *handler) HandleRequest(c *gin.Context) {
|
||||
}
|
||||
webdavHandler := webdav.Handler{
|
||||
Prefix: h.prefix,
|
||||
FileSystem: adapter{FileSystem: fs},
|
||||
FileSystem: fs,
|
||||
LockSystem: h.lockSystem,
|
||||
}
|
||||
webdavHandler.ServeHTTP(c.Writer, c.Request)
|
||||
}
|
||||
|
||||
type adapter struct {
|
||||
fs.FileSystem
|
||||
}
|
||||
|
||||
func (a adapter) OpenWriteTouch(name string) (io.WriteCloser, error) {
|
||||
resource, err := a.ResourceByPath(name)
|
||||
|
||||
if errors.Is(err, fs.ErrResourceNotFound) {
|
||||
resource, err = a.CreateResourceByPath(name, false, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
} else if resource.Dir {
|
||||
return nil, fs.ErrResourceCollection
|
||||
}
|
||||
|
||||
return a.OpenWrite(resource)
|
||||
}
|
||||
|
||||
@@ -40,10 +40,6 @@ type FileSystem interface {
|
||||
CreateResourceByPath(name string, dir, recursive bool) (fs.Resource, error)
|
||||
Move(r fs.Resource, target string, overwrite bool) (fs.Resource, bool, error)
|
||||
Copy(r fs.Resource, target string, id uuid.UUID, recursive, overwrite bool) (fs.Resource, bool, error)
|
||||
ReadDir(r serve.Resource, recursive bool) ([]serve.Resource, error)
|
||||
ProcessResources(r serve.Resource, depth int, fn func(r serve.Resource) error) error
|
||||
OpenRead(r serve.Resource, start, length int64) (io.ReadCloser, error)
|
||||
OpenWriteTouch(name string) (io.WriteCloser, error)
|
||||
}
|
||||
|
||||
func (h *Handler) stripPrefix(p string) (string, int, error) {
|
||||
@@ -224,9 +220,9 @@ func (h *Handler) handleGetHeadPost(w http.ResponseWriter, r *http.Request) (sta
|
||||
return http.StatusNotFound, err
|
||||
}
|
||||
if file.Dir {
|
||||
serve.ServeCollection(w, r, h.FileSystem, file)
|
||||
serve.ServeCollection(w, r, file)
|
||||
} else {
|
||||
serve.ServeResource(w, r, h.FileSystem, file)
|
||||
serve.ServeResource(w, r, file)
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
@@ -267,13 +263,23 @@ func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request) (status int,
|
||||
// TODO(rost): Support the If-Match, If-None-Match headers? See bradfitz'
|
||||
// comments in http.checkEtag.
|
||||
|
||||
f, err := h.FileSystem.OpenWriteTouch(reqPath)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrParentNotFound) {
|
||||
return http.StatusConflict, err
|
||||
res, err := h.FileSystem.ResourceByPath(reqPath)
|
||||
|
||||
if errors.Is(err, fs.ErrResourceNotFound) {
|
||||
res, err = h.FileSystem.CreateResourceByPath(reqPath, false, false)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrParentNotFound) {
|
||||
return http.StatusConflict, err
|
||||
}
|
||||
return http.StatusNotFound, err
|
||||
}
|
||||
} else if err != nil {
|
||||
return http.StatusNotFound, err
|
||||
} else if res.Dir {
|
||||
return http.StatusConflict, fs.ErrResourceCollection
|
||||
}
|
||||
|
||||
f, err := res.OpenWrite()
|
||||
_, copyErr := io.Copy(f, r.Body)
|
||||
fi, statErr := h.FileSystem.ResourceByPath(reqPath)
|
||||
closeErr := f.Close()
|
||||
@@ -382,14 +388,13 @@ func (h *Handler) handleLock(w http.ResponseWriter, r *http.Request) (retStatus
|
||||
|
||||
// Create the resource if it didn't previously exist.
|
||||
if _, err := h.FileSystem.ResourceByPath(reqPath); err != nil {
|
||||
f, err := h.FileSystem.OpenWriteTouch(reqPath)
|
||||
_, err = h.FileSystem.CreateResourceByPath(reqPath, false, false)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrParentNotFound) {
|
||||
return http.StatusConflict, err
|
||||
}
|
||||
return http.StatusNotFound, err
|
||||
}
|
||||
f.Close()
|
||||
created = true
|
||||
}
|
||||
|
||||
@@ -485,7 +490,7 @@ func (h *Handler) handlePropfind(w http.ResponseWriter, r *http.Request) (status
|
||||
return mw.write(makePropstatResponse(href, pstats))
|
||||
}
|
||||
|
||||
walkErr := h.FileSystem.ProcessResources(fi, depth, writePropStat)
|
||||
walkErr := fi.Walk(depth, writePropStat)
|
||||
closeErr := mw.close()
|
||||
if walkErr != nil {
|
||||
return http.StatusInternalServerError, walkErr
|
||||
|
||||
@@ -28,7 +28,7 @@ func setupCatCommand() *cobra.Command {
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
in, err := f.OpenRead(r, 0, -1)
|
||||
in, err := r.OpenRead(0, -1)
|
||||
if err != nil {
|
||||
fmt.Println("cannot read'" + pathOrUUID + "': " + err.Error())
|
||||
os.Exit(3)
|
||||
|
||||
@@ -164,7 +164,7 @@ func copyContents(f fs.FileSystem, src string, id uuid.UUID) error {
|
||||
if r, err := f.ResourceByID(id); err != nil {
|
||||
return err
|
||||
} else {
|
||||
out, err := f.OpenWrite(r)
|
||||
out, err := r.OpenWrite()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func setupLsCommand() *cobra.Command {
|
||||
fmt.Println(formatRow(r.ID.String(), formatSize(r.ContentSize), r.ContentSHA256, ".", r.PermissionsString()))
|
||||
|
||||
if r.Dir {
|
||||
children, err := f.ReadDir(r, false)
|
||||
children, err := r.ReadDir(false)
|
||||
if err != nil {
|
||||
fmt.Println("cannot access '" + pathOrUUID + "': " + err.Error())
|
||||
os.Exit(1)
|
||||
|
||||
@@ -2,11 +2,9 @@ package fs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/shroff/phylum/server/internal/api/serve"
|
||||
"github.com/shroff/phylum/server/internal/core/db"
|
||||
"github.com/shroff/phylum/server/internal/core/storage"
|
||||
)
|
||||
@@ -26,12 +24,6 @@ type FileSystem interface {
|
||||
ResourceByPath(path string) (Resource, error)
|
||||
ResourceByPathOrUUID(pathOrUUID string) (Resource, error)
|
||||
|
||||
// open.go
|
||||
OpenRead(r serve.Resource, start, length int64) (io.ReadCloser, error)
|
||||
OpenWrite(r Resource) (io.WriteCloser, error)
|
||||
ReadDir(r serve.Resource, recursive bool) ([]serve.Resource, error)
|
||||
ProcessResources(r serve.Resource, depth int, fn func(serve.Resource) error) error
|
||||
|
||||
// copy_move.go
|
||||
Move(r Resource, target string, overwrite bool) (Resource, bool, error)
|
||||
Copy(r Resource, target string, id uuid.UUID, recursive, overwrite bool) (Resource, bool, error)
|
||||
|
||||
@@ -8,23 +8,19 @@ import (
|
||||
"github.com/shroff/phylum/server/internal/core/db"
|
||||
)
|
||||
|
||||
func (f filesystem) OpenRead(sr serve.Resource, start, length int64) (io.ReadCloser, error) {
|
||||
r, ok := sr.(Resource)
|
||||
if !ok {
|
||||
return nil, ErrUnexpectedType
|
||||
}
|
||||
func (r Resource) OpenRead(start, length int64) (io.ReadCloser, error) {
|
||||
if !r.hasPermission(PermissionRead) {
|
||||
return nil, ErrInsufficientPermissions
|
||||
}
|
||||
return f.cs.OpenRead(r.ID, start, length)
|
||||
return r.f.cs.OpenRead(r.ID, start, length)
|
||||
}
|
||||
|
||||
func (f filesystem) OpenWrite(r Resource) (io.WriteCloser, error) {
|
||||
func (r Resource) OpenWrite() (io.WriteCloser, error) {
|
||||
if !r.hasPermission(PermissionWrite) {
|
||||
return nil, ErrInsufficientPermissions
|
||||
}
|
||||
return f.cs.OpenWrite(r.ID, sha256.New, func(len int, sum, mime string) error {
|
||||
return f.db.UpdateResourceContents(f.ctx, db.UpdateResourceContentsParams{
|
||||
return r.f.cs.OpenWrite(r.ID, sha256.New, func(len int, sum, mime string) error {
|
||||
return r.f.db.UpdateResourceContents(r.f.ctx, db.UpdateResourceContentsParams{
|
||||
ID: r.ID,
|
||||
ContentType: mime,
|
||||
ContentSize: int64(len),
|
||||
@@ -33,18 +29,14 @@ func (f filesystem) OpenWrite(r Resource) (io.WriteCloser, error) {
|
||||
})
|
||||
}
|
||||
|
||||
func (f filesystem) ReadDir(sr serve.Resource, recursive bool) ([]serve.Resource, error) {
|
||||
r, ok := sr.(Resource)
|
||||
if !ok {
|
||||
return nil, ErrUnexpectedType
|
||||
}
|
||||
func (r Resource) ReadDir(recursive bool) ([]serve.Resource, error) {
|
||||
if !r.hasPermission(PermissionRead) {
|
||||
return nil, ErrInsufficientPermissions
|
||||
}
|
||||
if !r.Dir {
|
||||
return nil, ErrResourceNotCollection
|
||||
}
|
||||
children, err := f.db.ReadDir(f.ctx, db.ReadDirParams{
|
||||
children, err := r.f.db.ReadDir(r.f.ctx, db.ReadDirParams{
|
||||
ID: r.ID,
|
||||
IncludeRoot: false,
|
||||
Recursive: recursive,
|
||||
@@ -61,7 +53,7 @@ func (f filesystem) ReadDir(sr serve.Resource, recursive bool) ([]serve.Resource
|
||||
path = c.Path
|
||||
}
|
||||
result[i] = Resource{
|
||||
f: f,
|
||||
f: r.f,
|
||||
ID: c.ID,
|
||||
ParentID: c.Parent,
|
||||
Name: c.Name,
|
||||
@@ -82,7 +74,7 @@ func (f filesystem) ReadDir(sr serve.Resource, recursive bool) ([]serve.Resource
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (f filesystem) ProcessResources(r serve.Resource, depth int, fn func(serve.Resource) error) error {
|
||||
func (r Resource) Walk(depth int, fn func(serve.Resource) error) error {
|
||||
err := fn(r)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -91,7 +83,7 @@ func (f filesystem) ProcessResources(r serve.Resource, depth int, fn func(serve.
|
||||
return nil
|
||||
}
|
||||
|
||||
children, err := f.ReadDir(r, depth > 1)
|
||||
children, err := r.ReadDir(depth > 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user