From a2b10cb1b90a61815c3757cf34fbed89ef4a21bc Mon Sep 17 00:00:00 2001 From: Abhishek Shroff Date: Sat, 9 Mar 2024 16:56:43 +0530 Subject: [PATCH] Consistent Naming --- internal/command/admin.go | 20 ++--- internal/command/command.go | 6 +- internal/command/serve.go | 2 +- internal/library/library.go | 90 +++++++++++++++++++ .../library_manager.go} | 24 ++--- internal/sql/resources.sql.go | 84 ++++++++--------- internal/vfs/vfs.go | 90 ------------------- internal/webdav/adapter.go | 82 ++++++++--------- internal/webdav/handler.go | 26 +++--- internal/webdav_xnet/adapter.go | 77 ++++++++-------- internal/webdav_xnet/file.go | 6 +- internal/webdav_xnet/handler.go | 26 +++--- sql/queries/resources.sql | 4 +- 13 files changed, 266 insertions(+), 271 deletions(-) create mode 100644 internal/library/library.go rename internal/{vfs/vfs_manager.go => library/library_manager.go} (52%) delete mode 100644 internal/vfs/vfs.go diff --git a/internal/command/admin.go b/internal/command/admin.go index d40ed550..ceff21ea 100644 --- a/internal/command/admin.go +++ b/internal/command/admin.go @@ -14,44 +14,44 @@ func setupAdminCommand() *cobra.Command { Short: "Server Administration", } cmd.AddCommand([]*cobra.Command{ - setupAdminVfsCommand(), + setupAdminLibraryCommand(), }...) return cmd } -func setupAdminVfsCommand() *cobra.Command { +func setupAdminLibraryCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "vfs", - Short: "VFS Management", + Use: "library", + Short: "Library Management", } cmd.AddCommand([]*cobra.Command{ - setupAdminVfsCreateCommand(), - setupAdminVfsDeleteCommand(), + setupAdminLibraryCreateCommand(), + setupAdminLibraryDeleteCommand(), }...) return cmd } -func setupAdminVfsCreateCommand() *cobra.Command { +func setupAdminLibraryCreateCommand() *cobra.Command { return &cobra.Command{ Use: "create name", Short: "Create Root Folder", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { - if err := vfsManager.CreateVfs(context.Background(), uuid.New(), args[0]); err != nil { + if err := libraryManager.Create(context.Background(), uuid.New(), args[0]); err != nil { log.Fatal(err) } }, } } -func setupAdminVfsDeleteCommand() *cobra.Command { +func setupAdminLibraryDeleteCommand() *cobra.Command { return &cobra.Command{ Use: "delete name", Short: "Delete Root Folder", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { - if err := vfsManager.DeleteVfs(context.Background(), args[0]); err != nil { + if err := libraryManager.Delete(context.Background(), args[0]); err != nil { log.Fatal(err) } }, diff --git a/internal/command/command.go b/internal/command/command.go index f43c0356..29e00e48 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -6,14 +6,14 @@ import ( "path" "github.com/jackc/pgx/v5" - "github.com/shroff/phylum/server/internal/vfs" + library "github.com/shroff/phylum/server/internal/library" "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" ) var debug bool = false -var vfsManager vfs.VfsManager +var libraryManager library.Manager func SetupCommand() { viper.SetEnvPrefix("phylum") @@ -62,7 +62,7 @@ func SetupCommand() { if err != nil { logrus.Fatal("Unable to connect to database: " + err.Error()) } - vfsManager = vfs.NewManager(conn) + libraryManager = library.NewManager(conn) } defer func() { diff --git a/internal/command/serve.go b/internal/command/serve.go index 2eccdf83..65aeccfb 100644 --- a/internal/command/serve.go +++ b/internal/command/serve.go @@ -54,7 +54,7 @@ func setupServeCommand() *cobra.Command { } func setupWebdav(r *gin.RouterGroup) { - handler := webdav.NewHandler(vfsManager, r.BasePath()) + handler := webdav.NewHandler(libraryManager, r.BasePath()) r.Handle("OPTIONS", "/*path", handler.HandleRequest) r.Handle("GET", "/*path", handler.HandleRequest) r.Handle("PUT", "/*path", handler.HandleRequest) diff --git a/internal/library/library.go b/internal/library/library.go new file mode 100644 index 00000000..f18a187a --- /dev/null +++ b/internal/library/library.go @@ -0,0 +1,90 @@ +package library + +import ( + "context" + "encoding/base64" + "hash" + "io" + "io/fs" + "os" + "strings" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" + "github.com/shroff/phylum/server/internal/sql" + "github.com/shroff/phylum/server/internal/storage" + "github.com/sirupsen/logrus" +) + +type Library struct { + queries sql.Queries + root uuid.UUID + cs storage.Storage +} + +func (l Library) Open(id uuid.UUID, flag int) (io.ReadWriteCloser, error) { + return l.cs.Open(id, flag, nil) +} + +func (l Library) ReadDir(ctx context.Context, id uuid.UUID, includeRoot bool, recursive bool) ([]sql.ReadDirRow, error) { + return l.queries.ReadDir(ctx, sql.ReadDirParams{ID: id, IncludeRoot: includeRoot, Recursive: recursive}) +} + +func (l Library) DeleteRecursive(ctx context.Context, id uuid.UUID, hardDelete bool) error { + query := l.queries.DeleteRecursive + if hardDelete { + query = l.queries.HardDeleteRecursive + } + deleted, err := query(ctx, id) + if err == nil && hardDelete { + for _, res := range deleted { + if !res.Dir { + l.cs.Delete(res.ID) + } + } + } + return err +} + +func (l Library) CreateResource(ctx context.Context, id uuid.UUID, parent uuid.UUID, name string, dir bool) error { + return l.queries.CreateResource(ctx, sql.CreateResourceParams{ID: id, Parent: &parent, Name: name, Dir: dir}) +} + +func (l Library) Move(ctx context.Context, id uuid.UUID, parent uuid.UUID, name string) error { + return l.queries.Rename(ctx, sql.RenameParams{ID: id, Parent: parent, Name: name}) +} + +func (l Library) UpdateContents(ctx context.Context, id uuid.UUID) (io.WriteCloser, error) { + return l.cs.Open(id, os.O_CREATE|os.O_RDWR|os.O_TRUNC, func(h hash.Hash, len int, err error) { + if err == nil { + etag := base64.StdEncoding.EncodeToString(h.Sum(nil)) + err = l.queries.UpdateResourceContents(ctx, sql.UpdateResourceContentsParams{ + ID: id, + Size: pgtype.Int4{Int32: int32(len), Valid: true}, + Etag: pgtype.Text{String: string(etag), Valid: true}, + }) + } + if err != nil { + logrus.Warn("Unable to update contents: " + err.Error()) + l.cs.Delete(id) + } + }) +} + +func (l Library) ResourceByPath(ctx context.Context, path string) (sql.ResourceByPathRow, error) { + path = strings.Trim(path, "/") + segments := strings.Split(path, "/") + if path == "" { + // Calling strings.Split on an empty string returns a slice of length 1. That breaks the query + segments = []string{} + } + + res, err := l.queries.ResourceByPath(ctx, sql.ResourceByPathParams{Search: segments, Root: l.root}) + if err != nil { + return sql.ResourceByPathRow{}, fs.ErrNotExist + } + + //TODO: Permissions checks + + return res, nil +} diff --git a/internal/vfs/vfs_manager.go b/internal/library/library_manager.go similarity index 52% rename from internal/vfs/vfs_manager.go rename to internal/library/library_manager.go index 50e98ebf..8742cc2c 100644 --- a/internal/vfs/vfs_manager.go +++ b/internal/library/library_manager.go @@ -1,4 +1,4 @@ -package vfs +package library import ( "context" @@ -10,41 +10,41 @@ import ( "github.com/shroff/phylum/server/internal/storage" ) -type VfsManager struct { +type Manager struct { queries sql.Queries cs storage.Storage } -func NewManager(conn *pgx.Conn) VfsManager { +func NewManager(conn *pgx.Conn) Manager { queries := *sql.New(conn) cs, err := storage.NewLocalStorage("srv") if err != nil { panic(err) } - return VfsManager{queries: queries, cs: cs} + return Manager{queries: queries, cs: cs} } -func (b VfsManager) GetVfs(ctx context.Context, name string) (*Vfs, error) { +func (b Manager) Get(ctx context.Context, name string) (*Library, error) { // TODO: Permissions checks - root, err := b.queries.FindRoot(ctx, name) + lib, err := b.queries.LibraryByName(ctx, name) if err != nil { return nil, err } - return &Vfs{queries: b.queries, root: root.ID, cs: b.cs}, nil + return &Library{queries: b.queries, root: lib.ID, cs: b.cs}, nil } -func (b VfsManager) CreateVfs(ctx context.Context, id uuid.UUID, name string) error { - if _, err := b.queries.FindRoot(ctx, name); err == nil { +func (b Manager) Create(ctx context.Context, id uuid.UUID, name string) error { + if _, err := b.queries.LibraryByName(ctx, name); err == nil { return fmt.Errorf("root directory already exists: %s", name) } else { return b.queries.CreateResource(ctx, sql.CreateResourceParams{ID: id, Parent: nil, Name: name, Dir: true}) } } -func (b VfsManager) DeleteVfs(ctx context.Context, name string) error { - if fs, err := b.GetVfs(ctx, name); err == nil { - return fs.DeleteRecursive(ctx, fs.root, true) +func (b Manager) Delete(ctx context.Context, name string) error { + if lib, err := b.Get(ctx, name); err == nil { + return lib.DeleteRecursive(ctx, lib.root, true) } else { return fmt.Errorf("root directory does not exist: %s", name) } diff --git a/internal/sql/resources.sql.go b/internal/sql/resources.sql.go index 3c08d2eb..0b87e693 100644 --- a/internal/sql/resources.sql.go +++ b/internal/sql/resources.sql.go @@ -82,48 +82,6 @@ func (q *Queries) DeleteRecursive(ctx context.Context, id uuid.UUID) ([]Resource return items, nil } -const findResource = `-- name: FindResource :one -SELECT id, parent, name, dir, created, modified, deleted, size, etag from resources WHERE id = $1 -` - -func (q *Queries) FindResource(ctx context.Context, id uuid.UUID) (Resource, error) { - row := q.db.QueryRow(ctx, findResource, id) - var i Resource - err := row.Scan( - &i.ID, - &i.Parent, - &i.Name, - &i.Dir, - &i.Created, - &i.Modified, - &i.Deleted, - &i.Size, - &i.Etag, - ) - return i, err -} - -const findRoot = `-- name: FindRoot :one -SELECT id, parent, name, dir, created, modified, deleted, size, etag from resources WHERE deleted IS NULL AND parent IS NULL AND name = $1 -` - -func (q *Queries) FindRoot(ctx context.Context, name string) (Resource, error) { - row := q.db.QueryRow(ctx, findRoot, name) - var i Resource - err := row.Scan( - &i.ID, - &i.Parent, - &i.Name, - &i.Dir, - &i.Created, - &i.Modified, - &i.Deleted, - &i.Size, - &i.Etag, - ) - return i, err -} - const hardDeleteRecursive = `-- name: HardDeleteRecursive :many WITH RECURSIVE nodes(id, parent) AS ( SELECT r.id, r.parent @@ -168,6 +126,27 @@ func (q *Queries) HardDeleteRecursive(ctx context.Context, id uuid.UUID) ([]Reso return items, nil } +const libraryByName = `-- name: LibraryByName :one +SELECT id, parent, name, dir, created, modified, deleted, size, etag from resources WHERE deleted IS NULL AND parent IS NULL AND name = $1 +` + +func (q *Queries) LibraryByName(ctx context.Context, name string) (Resource, error) { + row := q.db.QueryRow(ctx, libraryByName, name) + var i Resource + err := row.Scan( + &i.ID, + &i.Parent, + &i.Name, + &i.Dir, + &i.Created, + &i.Modified, + &i.Deleted, + &i.Size, + &i.Etag, + ) + return i, err +} + const readDir = `-- name: ReadDir :many WITH RECURSIVE nodes(id, parent, name, dir, created, modified, size, etag, depth, path) AS ( SELECT r.id, r.parent, r.name, r.dir, r.created, r.modified, r.size, r.etag, 0, ''::text @@ -252,6 +231,27 @@ func (q *Queries) Rename(ctx context.Context, arg RenameParams) error { return err } +const resourceById = `-- name: ResourceById :one +SELECT id, parent, name, dir, created, modified, deleted, size, etag from resources WHERE id = $1 +` + +func (q *Queries) ResourceById(ctx context.Context, id uuid.UUID) (Resource, error) { + row := q.db.QueryRow(ctx, resourceById, id) + var i Resource + err := row.Scan( + &i.ID, + &i.Parent, + &i.Name, + &i.Dir, + &i.Created, + &i.Modified, + &i.Deleted, + &i.Size, + &i.Etag, + ) + return i, err +} + const resourceByPath = `-- name: ResourceByPath :one WITH RECURSIVE nodes(id, parent, name, dir, created, modified, size, etag, depth, path, search) AS ( SELECT r.id, r.parent, r.name, r.dir, r.created, r.modified, r.size, r.etag, 0, ''::text, $1::text[] diff --git a/internal/vfs/vfs.go b/internal/vfs/vfs.go deleted file mode 100644 index f42114c6..00000000 --- a/internal/vfs/vfs.go +++ /dev/null @@ -1,90 +0,0 @@ -package vfs - -import ( - "context" - "encoding/base64" - "hash" - "io" - iofs "io/fs" - "os" - "strings" - - "github.com/google/uuid" - "github.com/jackc/pgx/v5/pgtype" - "github.com/shroff/phylum/server/internal/sql" - "github.com/shroff/phylum/server/internal/storage" - "github.com/sirupsen/logrus" -) - -type Vfs struct { - queries sql.Queries - root uuid.UUID - cs storage.Storage -} - -func (fs Vfs) Open(id uuid.UUID, flag int) (io.ReadWriteCloser, error) { - return fs.cs.Open(id, flag, nil) -} - -func (fs Vfs) ReadDir(ctx context.Context, id uuid.UUID, includeRoot bool, recursive bool) ([]sql.ReadDirRow, error) { - return fs.queries.ReadDir(ctx, sql.ReadDirParams{ID: id, IncludeRoot: includeRoot, Recursive: recursive}) -} - -func (fs Vfs) DeleteRecursive(ctx context.Context, id uuid.UUID, hardDelete bool) error { - query := fs.queries.DeleteRecursive - if hardDelete { - query = fs.queries.HardDeleteRecursive - } - deleted, err := query(ctx, id) - if err == nil && hardDelete { - for _, res := range deleted { - if !res.Dir { - fs.cs.Delete(res.ID) - } - } - } - return err -} - -func (fs Vfs) CreateResource(ctx context.Context, id uuid.UUID, parent uuid.UUID, name string, dir bool) error { - return fs.queries.CreateResource(ctx, sql.CreateResourceParams{ID: id, Parent: &parent, Name: name, Dir: dir}) -} - -func (fs Vfs) Move(ctx context.Context, id uuid.UUID, parent uuid.UUID, name string) error { - return fs.queries.Rename(ctx, sql.RenameParams{ID: id, Parent: parent, Name: name}) -} - -func (fs Vfs) UpdateContents(ctx context.Context, id uuid.UUID) (io.WriteCloser, error) { - return fs.cs.Open(id, os.O_CREATE|os.O_RDWR|os.O_TRUNC, func(h hash.Hash, len int, err error) { - if err == nil { - etag := base64.StdEncoding.EncodeToString(h.Sum(nil)) - err = fs.queries.UpdateResourceContents(ctx, sql.UpdateResourceContentsParams{ - ID: id, - Size: pgtype.Int4{Int32: int32(len), Valid: true}, - Etag: pgtype.Text{String: string(etag), Valid: true}, - }) - } - if err != nil { - logrus.Warn("Unable to update contents: " + err.Error()) - fs.cs.Delete(id) - } - }) -} - -func (fs Vfs) ResourceByPath(ctx context.Context, path string) (sql.ResourceByPathRow, error) { - path = strings.Trim(path, "/") - segments := strings.Split(path, "/") - if path == "" { - // Calling strings.Split on an empty string returns a slice of length 1. That breaks the query - segments = []string{} - } - - res, err := fs.queries.ResourceByPath(ctx, sql.ResourceByPathParams{Search: segments, Root: fs.root}) - if err != nil { - return sql.ResourceByPathRow{}, iofs.ErrNotExist - } - - //TODO: Permissions checks - - return res, nil -} diff --git a/internal/webdav/adapter.go b/internal/webdav/adapter.go index ad08c936..e8e612c9 100644 --- a/internal/webdav/adapter.go +++ b/internal/webdav/adapter.go @@ -4,37 +4,37 @@ import ( "context" "fmt" "io" - iofs "io/fs" + "io/fs" "net/http" "os" "strings" webdav "github.com/emersion/go-webdav" "github.com/google/uuid" + "github.com/shroff/phylum/server/internal/library" "github.com/shroff/phylum/server/internal/sql" - "github.com/shroff/phylum/server/internal/vfs" ) type adapter struct { - fs *vfs.Vfs + lib *library.Library prefix string } -func (p adapter) Open(ctx context.Context, name string) (io.ReadCloser, error) { - resource, err := p.resourceByPath(ctx, name) +func (a adapter) Open(ctx context.Context, name string) (io.ReadCloser, error) { + resource, err := a.resourceByPath(ctx, name) if err != nil { return nil, err } - return p.fs.Open(resource.ID, os.O_RDONLY) + return a.lib.Open(resource.ID, os.O_RDONLY) } -func (p adapter) Stat(ctx context.Context, name string) (*webdav.FileInfo, error) { - resource, err := p.resourceByPath(ctx, name) +func (a adapter) Stat(ctx context.Context, name string) (*webdav.FileInfo, error) { + resource, err := a.resourceByPath(ctx, name) if err != nil { return nil, err } val := &webdav.FileInfo{ - Path: string(p.prefix + resource.Path), + Path: string(a.prefix + resource.Path), Size: int64(resource.Size.Int32), ModTime: resource.Modified.Time, IsDir: resource.Dir, @@ -43,21 +43,21 @@ func (p adapter) Stat(ctx context.Context, name string) (*webdav.FileInfo, error } return val, nil } -func (p adapter) ReadDir(ctx context.Context, name string, recursive bool) ([]webdav.FileInfo, error) { - dir, err := p.resourceByPath(ctx, name) +func (a adapter) ReadDir(ctx context.Context, name string, recursive bool) ([]webdav.FileInfo, error) { + dir, err := a.resourceByPath(ctx, name) if err != nil { return nil, err } if !dir.Dir { - return nil, iofs.ErrInvalid + return nil, fs.ErrInvalid } - children, err := p.fs.ReadDir(ctx, dir.ID, false, recursive) + children, err := a.lib.ReadDir(ctx, dir.ID, false, recursive) if err != nil { return nil, err } result := make([]webdav.FileInfo, len(children)) - prefix := p.prefix + dir.Path + prefix := a.prefix + dir.Path for i, c := range children { result[i] = webdav.FileInfo{ Path: string(prefix + c.Path), @@ -70,86 +70,86 @@ func (p adapter) ReadDir(ctx context.Context, name string, recursive bool) ([]we } return result, nil } -func (p adapter) Create(ctx context.Context, name string) (io.WriteCloser, error) { +func (a adapter) Create(ctx context.Context, name string) (io.WriteCloser, error) { var id uuid.UUID - if resource, err := p.resourceByPath(ctx, name); err == nil { + if resource, err := a.resourceByPath(ctx, name); err == nil { id = resource.ID } else { name = strings.TrimRight(name, "/") index := strings.LastIndex(name, "/") parentPath := name[0:index] - parent, err := p.resourceByPath(ctx, parentPath) + parent, err := a.resourceByPath(ctx, parentPath) if err != nil { - return nil, iofs.ErrNotExist + return nil, fs.ErrNotExist } fileName := name[index+1:] id = uuid.New() - if err = p.fs.CreateResource(ctx, id, parent.ID, fileName, false); err != nil { + if err = a.lib.CreateResource(ctx, id, parent.ID, fileName, false); err != nil { return nil, err } } - return p.fs.UpdateContents(ctx, id) + return a.lib.UpdateContents(ctx, id) } -func (p adapter) RemoveAll(ctx context.Context, name string) error { - resource, err := p.resourceByPath(ctx, name) +func (a adapter) RemoveAll(ctx context.Context, name string) error { + resource, err := a.resourceByPath(ctx, name) if err != nil { - return iofs.ErrNotExist + return fs.ErrNotExist } - return p.fs.DeleteRecursive(ctx, resource.ID, false) + return a.lib.DeleteRecursive(ctx, resource.ID, false) } -func (p adapter) Mkdir(ctx context.Context, name string) error { - if _, err := p.resourceByPath(ctx, name); err == nil { - return iofs.ErrExist +func (a adapter) Mkdir(ctx context.Context, name string) error { + if _, err := a.resourceByPath(ctx, name); err == nil { + return fs.ErrExist } name = strings.TrimRight(name, "/") index := strings.LastIndex(name, "/") parentPath := name[0:index] - parent, err := p.resourceByPath(ctx, parentPath) + parent, err := a.resourceByPath(ctx, parentPath) if err != nil { - return iofs.ErrNotExist + return fs.ErrNotExist } dirName := name[index+1:] - err = p.fs.CreateResource(ctx, uuid.New(), parent.ID, dirName, true) + err = a.lib.CreateResource(ctx, uuid.New(), parent.ID, dirName, true) return err } -func (p adapter) Copy(ctx context.Context, name, dest string, options *webdav.CopyOptions) (created bool, err error) { +func (a adapter) Copy(ctx context.Context, name, dest string, options *webdav.CopyOptions) (created bool, err error) { // TODO: Implement return false, webdav.NewHTTPError(http.StatusMethodNotAllowed, fmt.Errorf("not implemented")) } -func (p adapter) Move(ctx context.Context, name, destName string, options *webdav.MoveOptions) (created bool, err error) { - src, err := p.resourceByPath(ctx, name) +func (a adapter) Move(ctx context.Context, name, destName string, options *webdav.MoveOptions) (created bool, err error) { + src, err := a.resourceByPath(ctx, name) if err != nil { - return false, iofs.ErrNotExist + return false, fs.ErrNotExist } - existing, err := p.resourceByPath(ctx, destName) + existing, err := a.resourceByPath(ctx, destName) if err == nil { if options.NoOverwrite { - return false, iofs.ErrExist + return false, fs.ErrExist } else { - p.fs.DeleteRecursive(ctx, existing.ID, false) + a.lib.DeleteRecursive(ctx, existing.ID, false) } } destName = strings.TrimRight(destName, "/") index := strings.LastIndex(destName, "/") parentPath := destName[0:index] - parent, err := p.resourceByPath(ctx, parentPath) + parent, err := a.resourceByPath(ctx, parentPath) destName = destName[index+1:] if err != nil { return false, webdav.NewHTTPError(http.StatusConflict, nil) } - if err = p.fs.Move(ctx, src.ID, parent.ID, destName); err != nil { + if err = a.lib.Move(ctx, src.ID, parent.ID, destName); err != nil { return false, err } return true, nil } -func (p adapter) resourceByPath(ctx context.Context, name string) (res sql.ResourceByPathRow, err error) { - return p.fs.ResourceByPath(ctx, strings.TrimPrefix(name, p.prefix)) +func (a adapter) resourceByPath(ctx context.Context, name string) (res sql.ResourceByPathRow, err error) { + return a.lib.ResourceByPath(ctx, strings.TrimPrefix(name, a.prefix)) } diff --git a/internal/webdav/handler.go b/internal/webdav/handler.go index 73fd846f..0b29ce85 100644 --- a/internal/webdav/handler.go +++ b/internal/webdav/handler.go @@ -6,36 +6,36 @@ import ( webdav "github.com/emersion/go-webdav" "github.com/gin-gonic/gin" - "github.com/shroff/phylum/server/internal/vfs" + "github.com/shroff/phylum/server/internal/library" "github.com/sirupsen/logrus" ) type handler struct { - vfsManager vfs.VfsManager - prefix string + libraryManager library.Manager + prefix string } -func NewHandler(vfsManager vfs.VfsManager, prefix string) *handler { +func NewHandler(libraryManager library.Manager, prefix string) *handler { logrus.Info("Setting up WebDAV access at " + prefix) return &handler{ - vfsManager: vfsManager, - prefix: prefix, + libraryManager: libraryManager, + prefix: prefix, } } func (h *handler) HandleRequest(c *gin.Context) { path := c.Params.ByName("path") - vfsName := strings.TrimLeft(path, "/") - if vfsName == "" { + libraryName := strings.TrimLeft(path, "/") + if libraryName == "" { // No path specified c.Writer.WriteHeader(404) return } - index := strings.Index(vfsName, "/") + index := strings.Index(libraryName, "/") if index != -1 { - vfsName = vfsName[0:index] + libraryName = libraryName[0:index] } - vfs, err := h.vfsManager.GetVfs(context.Background(), vfsName) + library, err := h.libraryManager.Get(context.Background(), libraryName) if err != nil { c.Writer.WriteHeader(404) return @@ -43,8 +43,8 @@ func (h *handler) HandleRequest(c *gin.Context) { webdavHandler := webdav.Handler{ FileSystem: adapter{ - fs: vfs, - prefix: h.prefix + "/" + vfsName, + lib: library, + prefix: h.prefix + "/" + libraryName, }, } webdavHandler.ServeHTTP(c.Writer, c.Request) diff --git a/internal/webdav_xnet/adapter.go b/internal/webdav_xnet/adapter.go index d77e9e3e..6b232fb2 100644 --- a/internal/webdav_xnet/adapter.go +++ b/internal/webdav_xnet/adapter.go @@ -3,23 +3,22 @@ package webdav import ( "context" "io" - iofs "io/fs" + "io/fs" "os" "strings" "time" "github.com/google/uuid" - "github.com/shroff/phylum/server/internal/sql" - "github.com/shroff/phylum/server/internal/vfs" + "github.com/shroff/phylum/server/internal/library" "golang.org/x/net/webdav" ) type adapter struct { - fs *vfs.Vfs + lib *library.Library } -func (p adapter) Stat(ctx context.Context, name string) (os.FileInfo, error) { - resource, err := p.resourceByPath(ctx, name) +func (a adapter) Stat(ctx context.Context, name string) (os.FileInfo, error) { + resource, err := a.lib.ResourceByPath(ctx, name) if err != nil { return nil, err } @@ -33,8 +32,8 @@ func (p adapter) Stat(ctx context.Context, name string) (os.FileInfo, error) { return val, nil } -func (p adapter) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (webdav.File, error) { - resource, err := p.resourceByPath(ctx, name) +func (a adapter) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (webdav.File, error) { + resource, err := a.lib.ResourceByPath(ctx, name) resourceId := resource.ID resourceName := resource.Name size := resource.Size.Int32 @@ -47,22 +46,22 @@ func (p adapter) OpenFile(ctx context.Context, name string, flag int, perm os.Fi name = strings.TrimRight(name, "/") index := strings.LastIndex(name, "/") parentPath := name[0:index] - parent, err := p.resourceByPath(ctx, parentPath) + parent, err := a.lib.ResourceByPath(ctx, parentPath) if err != nil { - return nil, iofs.ErrNotExist + return nil, fs.ErrNotExist } resourceName := name[index+1:] resourceId = uuid.New() dir = false modTime = time.Time{} - err = p.fs.CreateResource(ctx, resourceId, parent.ID, resourceName, dir) + err = a.lib.CreateResource(ctx, resourceId, parent.ID, resourceName, dir) if err != nil { return nil, err } } var src io.ReadWriteCloser if !dir { - src, err = p.fs.Open(resourceId, flag) + src, err = a.lib.Open(resourceId, flag) if err != nil { return nil, err } @@ -76,83 +75,79 @@ func (p adapter) OpenFile(ctx context.Context, name string, flag int, perm os.Fi resourceID: resourceId, }, src: src, - fs: p.fs, + lib: a.lib, }, nil } -func (p adapter) Create(ctx context.Context, name string) (io.WriteCloser, error) { +func (a adapter) Create(ctx context.Context, name string) (io.WriteCloser, error) { var id uuid.UUID - if resource, err := p.resourceByPath(ctx, name); err == nil { + if resource, err := a.lib.ResourceByPath(ctx, name); err == nil { id = resource.ID } else { name = strings.TrimRight(name, "/") index := strings.LastIndex(name, "/") parentPath := name[0:index] - parent, err := p.resourceByPath(ctx, parentPath) + parent, err := a.lib.ResourceByPath(ctx, parentPath) if err != nil { - return nil, iofs.ErrNotExist + return nil, fs.ErrNotExist } fileName := name[index+1:] id = uuid.New() - if err = p.fs.CreateResource(ctx, id, parent.ID, fileName, false); err != nil { + if err = a.lib.CreateResource(ctx, id, parent.ID, fileName, false); err != nil { return nil, err } } - return p.fs.UpdateContents(ctx, id) + return a.lib.UpdateContents(ctx, id) } -func (p adapter) RemoveAll(ctx context.Context, name string) error { - resource, err := p.resourceByPath(ctx, name) +func (a adapter) RemoveAll(ctx context.Context, name string) error { + resource, err := a.lib.ResourceByPath(ctx, name) if err != nil { - return iofs.ErrNotExist + return fs.ErrNotExist } - return p.fs.DeleteRecursive(ctx, resource.ID, false) + return a.lib.DeleteRecursive(ctx, resource.ID, false) } -func (p adapter) Mkdir(ctx context.Context, name string, mode iofs.FileMode) error { - if _, err := p.resourceByPath(ctx, name); err == nil { - return iofs.ErrExist +func (a adapter) Mkdir(ctx context.Context, name string, mode fs.FileMode) error { + if _, err := a.lib.ResourceByPath(ctx, name); err == nil { + return fs.ErrExist } name = strings.TrimRight(name, "/") index := strings.LastIndex(name, "/") parentPath := name[0:index] - parent, err := p.resourceByPath(ctx, parentPath) + parent, err := a.lib.ResourceByPath(ctx, parentPath) if err != nil { - return iofs.ErrNotExist + return fs.ErrNotExist } dirName := name[index+1:] - err = p.fs.CreateResource(ctx, uuid.New(), parent.ID, dirName, true) + err = a.lib.CreateResource(ctx, uuid.New(), parent.ID, dirName, true) return err } -func (p adapter) Rename(ctx context.Context, oldName, newName string) error { - src, err := p.resourceByPath(ctx, oldName) +func (a adapter) Rename(ctx context.Context, oldName, newName string) error { + src, err := a.lib.ResourceByPath(ctx, oldName) if err != nil { - return iofs.ErrNotExist + return fs.ErrNotExist } - _, err = p.resourceByPath(ctx, newName) + _, err = a.lib.ResourceByPath(ctx, newName) if err == nil { - return iofs.ErrExist + return fs.ErrExist } newName = strings.TrimRight(newName, "/") index := strings.LastIndex(newName, "/") parentPath := newName[0:index] - parent, err := p.resourceByPath(ctx, parentPath) + parent, err := a.lib.ResourceByPath(ctx, parentPath) newName = newName[index+1:] if err != nil { - return iofs.ErrNotExist + return fs.ErrNotExist } - if err = p.fs.Move(ctx, src.ID, parent.ID, newName); err != nil { + if err = a.lib.Move(ctx, src.ID, parent.ID, newName); err != nil { return err } return nil } - -func (p adapter) resourceByPath(ctx context.Context, name string) (res sql.ResourceByPathRow, err error) { - return p.fs.ResourceByPath(ctx, name) -} diff --git a/internal/webdav_xnet/file.go b/internal/webdav_xnet/file.go index 528d600e..5b1970d2 100644 --- a/internal/webdav_xnet/file.go +++ b/internal/webdav_xnet/file.go @@ -6,13 +6,13 @@ import ( "io" "io/fs" - "github.com/shroff/phylum/server/internal/vfs" + "github.com/shroff/phylum/server/internal/library" ) type file struct { fileInfo src io.ReadWriteCloser - fs *vfs.Vfs + lib *library.Library } func (f file) Seek(offset int64, whence int) (int64, error) { @@ -36,7 +36,7 @@ func (f file) Readdir(count int) ([]fs.FileInfo, error) { return nil, fmt.Errorf("readdir not supported for non-collection resources") } - children, err := f.fs.ReadDir(context.Background(), f.resourceID, false, false) + children, err := f.lib.ReadDir(context.Background(), f.resourceID, false, false) if err != nil { return nil, err } diff --git a/internal/webdav_xnet/handler.go b/internal/webdav_xnet/handler.go index 01016c4a..fd635809 100644 --- a/internal/webdav_xnet/handler.go +++ b/internal/webdav_xnet/handler.go @@ -5,45 +5,45 @@ import ( "strings" "github.com/gin-gonic/gin" - "github.com/shroff/phylum/server/internal/vfs" + "github.com/shroff/phylum/server/internal/library" "github.com/sirupsen/logrus" "golang.org/x/net/webdav" ) type handler struct { - vfsManager vfs.VfsManager - prefix string + libraryManager library.Manager + prefix string } -func NewHandler(vfsManager vfs.VfsManager, prefix string) *handler { +func NewHandler(libraryManager library.Manager, prefix string) *handler { logrus.Info("Setting up WebDAV access at " + prefix) return &handler{ - vfsManager: vfsManager, - prefix: prefix, + libraryManager: libraryManager, + prefix: prefix, } } func (h *handler) HandleRequest(c *gin.Context) { path := c.Params.ByName("path") - vfsName := strings.TrimLeft(path, "/") - if vfsName == "" { + libraryName := strings.TrimLeft(path, "/") + if libraryName == "" { // No path specified c.Writer.WriteHeader(404) return } - index := strings.Index(vfsName, "/") + index := strings.Index(libraryName, "/") if index != -1 { - vfsName = vfsName[0:index] + libraryName = libraryName[0:index] } - vfs, err := h.vfsManager.GetVfs(context.Background(), vfsName) + library, err := h.libraryManager.Get(context.Background(), libraryName) if err != nil { c.Writer.WriteHeader(404) return } webdavHandler := webdav.Handler{ - Prefix: h.prefix + "/" + vfsName, - FileSystem: adapter{fs: vfs}, + Prefix: h.prefix + "/" + libraryName, + FileSystem: adapter{lib: library}, LockSystem: webdav.NewMemLS(), } webdavHandler.ServeHTTP(c.Writer, c.Request) diff --git a/sql/queries/resources.sql b/sql/queries/resources.sql index d070d4b3..9957e0cd 100644 --- a/sql/queries/resources.sql +++ b/sql/queries/resources.sql @@ -1,7 +1,7 @@ --- name: FindResource :one +-- name: ResourceById :one SELECT * from resources WHERE id = $1; --- name: FindRoot :one +-- name: LibraryByName :one SELECT * from resources WHERE deleted IS NULL AND parent IS NULL AND name = $1; -- name: CreateResource :exec