From cf62e5f9049fbf6872b252822b1dc2ae72c78951 Mon Sep 17 00:00:00 2001 From: Abhishek Shroff Date: Fri, 25 Oct 2024 00:55:33 +0530 Subject: [PATCH] [server][core] move OpenRead, OpenWrite, ReadDir, and Walk to Resource --- server/internal/api/serve/serve_resource.go | 15 +++++----- server/internal/api/v1/fs/cat.go | 2 +- server/internal/api/v1/fs/ls.go | 2 +- server/internal/api/v1/fs/upload.go | 2 +- server/internal/api/webdav/handler.go | 25 +---------------- server/internal/api/webdav/impl/webdav.go | 31 ++++++++++++--------- server/internal/command/fs/cat.go | 2 +- server/internal/command/fs/import.go | 2 +- server/internal/command/fs/ls.go | 2 +- server/internal/core/fs/fs.go | 8 ------ server/internal/core/fs/open.go | 28 +++++++------------ 11 files changed, 43 insertions(+), 76 deletions(-) diff --git a/server/internal/api/serve/serve_resource.go b/server/internal/api/serve/serve_resource.go index 2a9f1c66..ce35956a 100644 --- a/server/internal/api/serve/serve_resource.go +++ b/server/internal/api/serve/serve_resource.go @@ -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, "\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 { diff --git a/server/internal/api/v1/fs/cat.go b/server/internal/api/v1/fs/cat.go index 598acc3f..bbb0cb39 100644 --- a/server/internal/api/v1/fs/cat.go +++ b/server/internal/api/v1/fs/cat.go @@ -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) } diff --git a/server/internal/api/v1/fs/ls.go b/server/internal/api/v1/fs/ls.go index caeb2011..61a6d412 100644 --- a/server/internal/api/v1/fs/ls.go +++ b/server/internal/api/v1/fs/ls.go @@ -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) } diff --git a/server/internal/api/v1/fs/upload.go b/server/internal/api/v1/fs/upload.go index 4397f229..322a1437 100644 --- a/server/internal/api/v1/fs/upload.go +++ b/server/internal/api/v1/fs/upload.go @@ -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 } diff --git a/server/internal/api/webdav/handler.go b/server/internal/api/webdav/handler.go index 90e78fbc..7fd608e5 100644 --- a/server/internal/api/webdav/handler.go +++ b/server/internal/api/webdav/handler.go @@ -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) -} diff --git a/server/internal/api/webdav/impl/webdav.go b/server/internal/api/webdav/impl/webdav.go index c74dee90..3e3e5f6b 100644 --- a/server/internal/api/webdav/impl/webdav.go +++ b/server/internal/api/webdav/impl/webdav.go @@ -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 diff --git a/server/internal/command/fs/cat.go b/server/internal/command/fs/cat.go index 3534f55a..2887b992 100644 --- a/server/internal/command/fs/cat.go +++ b/server/internal/command/fs/cat.go @@ -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) diff --git a/server/internal/command/fs/import.go b/server/internal/command/fs/import.go index 76001640..5222da10 100644 --- a/server/internal/command/fs/import.go +++ b/server/internal/command/fs/import.go @@ -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 } diff --git a/server/internal/command/fs/ls.go b/server/internal/command/fs/ls.go index f70a6287..202a0049 100644 --- a/server/internal/command/fs/ls.go +++ b/server/internal/command/fs/ls.go @@ -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) diff --git a/server/internal/core/fs/fs.go b/server/internal/core/fs/fs.go index d457ca72..5d71a3f2 100644 --- a/server/internal/core/fs/fs.go +++ b/server/internal/core/fs/fs.go @@ -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) diff --git a/server/internal/core/fs/open.go b/server/internal/core/fs/open.go index 94eb3049..0dcc6ac8 100644 --- a/server/internal/core/fs/open.go +++ b/server/internal/core/fs/open.go @@ -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 }