Consistent Naming

This commit is contained in:
Abhishek Shroff
2024-03-09 16:56:43 +05:30
parent bd23957bc1
commit a2b10cb1b9
13 changed files with 266 additions and 271 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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