[server][core] move OpenRead, OpenWrite, ReadDir, and Walk to Resource

This commit is contained in:
Abhishek Shroff
2024-10-25 00:55:33 +05:30
parent cf5e1b4c0f
commit cf62e5f904
11 changed files with 43 additions and 76 deletions

View File

@@ -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 {

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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
}