Merge fileInfo and file into resource

This commit is contained in:
Abhishek Shroff
2024-08-03 08:48:15 +05:30
parent ada63198a1
commit f5068c6189
8 changed files with 116 additions and 116 deletions

View File

@@ -1,77 +0,0 @@
package core
import (
"context"
"fmt"
"io"
"mime"
"path/filepath"
"time"
"github.com/google/uuid"
)
type FileInfo interface {
ID() uuid.UUID
Name() string
Size() int64
ModTime() time.Time
IsDir() bool
ETag() string
ContentType() string
}
type File interface {
FileInfo
OpenRead(ctx context.Context, start, length int64) (io.ReadCloser, error)
ReadDir(ctx context.Context) ([]FileInfo, error)
}
type fileInfo struct {
id uuid.UUID
name string
size int64
collection bool
modTime time.Time
etag string
}
type file struct {
fileInfo
silo Silo
}
func (f fileInfo) ID() uuid.UUID { return f.id }
func (f fileInfo) Name() string { return f.name }
func (f fileInfo) Size() int64 { return f.size }
func (f fileInfo) ModTime() time.Time { return f.modTime }
func (f fileInfo) IsDir() bool { return f.collection }
func (f fileInfo) ETag() string {
if f.etag != "" {
return f.etag
}
// The Apache http 2.4 web server by default concatenates the
// modification time and size of a file.
return fmt.Sprintf(`"%x%x"`, f.modTime.UnixMilli(), f.size)
}
func (f fileInfo) ContentType() string {
mimeType := mime.TypeByExtension(filepath.Ext(f.name))
if mimeType != "" {
return mimeType
}
return "application/octet-stream"
}
func (f file) OpenRead(ctx context.Context, start, length int64) (io.ReadCloser, error) {
return f.silo.OpenRead(ctx, f.id, start, length)
}
func (f file) ReadDir(ctx context.Context) ([]FileInfo, error) {
return f.silo.ReadDir(ctx, f.id, false, false)
}

View File

@@ -0,0 +1,76 @@
package core
import (
"context"
"fmt"
"io"
"mime"
"path/filepath"
"time"
"github.com/google/uuid"
)
type ResourceInfo interface {
ID() uuid.UUID
Name() string
Size() int64
ModTime() time.Time
IsDir() bool
ETag() string
ContentType() string
}
type Resource interface {
ResourceInfo
OpenRead(ctx context.Context, start, length int64) (io.ReadCloser, error)
ReadDir(ctx context.Context) ([]Resource, error)
}
type resource struct {
silo Silo
id uuid.UUID
parentID *uuid.UUID
name string
size int64
collection bool
modTime time.Time
etag string
}
func (r resource) ID() uuid.UUID { return r.id }
func (r resource) ParentID() *uuid.UUID { return r.parentID }
func (r resource) Name() string { return r.name }
func (r resource) Size() int64 { return r.size }
func (r resource) ModTime() time.Time { return r.modTime }
func (r resource) IsDir() bool { return r.collection }
func (r resource) ETag() string {
if r.etag != "" {
return r.etag
}
// The Apache http 2.4 web server by default concatenates the
// modification time and size of a file.
return fmt.Sprintf(`"%x%x"`, r.modTime.UnixMilli(), r.size)
}
func (r resource) ContentType() string {
mimeType := mime.TypeByExtension(filepath.Ext(r.name))
if mimeType != "" {
return mimeType
}
return "application/octet-stream"
}
func (f resource) OpenRead(ctx context.Context, start, length int64) (io.ReadCloser, error) {
return f.silo.OpenRead(ctx, f.id, start, length)
}
func (f resource) ReadDir(ctx context.Context) ([]Resource, error) {
return f.silo.ReadDir(ctx, f.id, false, false)
}

View File

@@ -20,9 +20,9 @@ type Silo interface {
StorageName() string
OpenRead(ctx context.Context, id uuid.UUID, start, length int64) (io.ReadCloser, error)
OpenWrite(ctx context.Context, id uuid.UUID) (io.WriteCloser, error)
ReadDir(ctx context.Context, id uuid.UUID, includeRoot bool, recursive bool) ([]FileInfo, error)
ReadDir(ctx context.Context, id uuid.UUID, includeRoot bool, recursive bool) ([]Resource, error)
DeleteRecursive(ctx context.Context, id uuid.UUID, hardDelete bool) error
ResourceByPath(ctx context.Context, path string) (File, error)
ResourceByPath(ctx context.Context, path string) (Resource, error)
Move(ctx context.Context, id uuid.UUID, parent uuid.UUID, name string) error
CreateResource(ctx context.Context, id uuid.UUID, parent uuid.UUID, name string, dir bool) error
}
@@ -75,20 +75,22 @@ func (s *silo) OpenWrite(ctx context.Context, id uuid.UUID) (io.WriteCloser, err
})
}
func (s *silo) ReadDir(ctx context.Context, id uuid.UUID, includeRoot bool, recursive bool) ([]FileInfo, error) {
func (s *silo) ReadDir(ctx context.Context, id uuid.UUID, includeRoot bool, recursive bool) ([]Resource, error) {
children, err := s.db.Queries().ReadDir(ctx, sql.ReadDirParams{ID: id, IncludeRoot: includeRoot, Recursive: recursive})
if err != nil {
return nil, err
}
result := make([]FileInfo, len(children))
result := make([]Resource, len(children))
for i, c := range children {
result[i] = fileInfo{
result[i] = resource{
silo: s,
id: c.ID,
parentID: &id,
name: c.Name,
size: int64(c.Size.Int32),
modTime: c.Modified.Time,
collection: c.Dir,
id: c.ID,
etag: c.Etag.String,
}
}
@@ -138,7 +140,7 @@ func (s *silo) Move(ctx context.Context, id uuid.UUID, parent uuid.UUID, name st
return s.db.Queries().Rename(ctx, sql.RenameParams{ID: id, Parent: parent, Name: name})
}
func (s *silo) ResourceByPath(ctx context.Context, path string) (File, error) {
func (s *silo) ResourceByPath(ctx context.Context, path string) (Resource, error) {
path = strings.Trim(path, "/")
segments := strings.Split(path, "/")
if path == "" {
@@ -153,15 +155,14 @@ func (s *silo) ResourceByPath(ctx context.Context, path string) (File, error) {
//TODO: Permissions checks
return file{
fileInfo: fileInfo{
id: res.ID,
name: res.Name,
size: int64(res.Size.Int32),
collection: res.Dir,
modTime: res.Modified.Time,
etag: res.Etag.String,
},
silo: s,
return resource{
silo: s,
id: res.ID,
parentID: res.Parent,
name: res.Name,
size: int64(res.Size.Int32),
collection: res.Dir,
modTime: res.Modified.Time,
etag: res.Etag.String,
}, nil
}

View File

@@ -77,7 +77,7 @@ type adapter struct {
silo core.Silo
}
func (a adapter) Stat(ctx context.Context, name string) (core.File, error) {
func (a adapter) Stat(ctx context.Context, name string) (core.Resource, error) {
return a.silo.ResourceByPath(ctx, name)
}

View File

@@ -19,7 +19,7 @@ import (
// in a file path are separated by slash ('/', U+002F) characters, regardless
// of host operating system convention.
type FileSystem interface {
Stat(ctx context.Context, name string) (core.File, error)
Stat(ctx context.Context, name string) (core.Resource, error)
Mkdir(ctx context.Context, name string) error
RemoveAll(ctx context.Context, name string) error
Rename(ctx context.Context, oldName, newName string) error
@@ -146,14 +146,14 @@ func copyFiles(ctx context.Context, fs FileSystem, src, dst string, overwrite bo
return http.StatusNoContent, nil
}
type WalkFunc func(path string, info core.FileInfo, err error) error
type WalkFunc func(path string, info core.Resource, err error) error
// walkFS traverses filesystem fs starting at name up to depth levels.
//
// Allowed values for depth are 0, 1 or infiniteDepth. For each visited node,
// walkFS calls walkFn. If a visited file system node is a directory and
// walkFn returns filepath.SkipDir, walkFS will skip traversal of this node.
func walkFS(ctx context.Context, fs FileSystem, depth int, name string, info core.FileInfo, walkFn WalkFunc) error {
func walkFS(ctx context.Context, fs FileSystem, depth int, name string, info core.Resource, walkFn WalkFunc) error {
// This implementation is based on Walk's code in the standard path/filepath package.
err := walkFn(name, info, nil)
if err != nil {

View File

@@ -70,7 +70,7 @@ func makePropstats(x, y Propstat) []Propstat {
var liveProps = map[xml.Name]struct {
// findFn implements the propfind function of this property. If nil,
// it indicates a hidden property.
findFn func(core.FileInfo) string
findFn func(core.ResourceInfo) string
// dir is true if the property applies to directories.
dir bool
}{
@@ -265,34 +265,34 @@ func escapeXML(s string) string {
return s
}
func findResourceType(fi core.FileInfo) string {
func findResourceType(fi core.ResourceInfo) string {
if fi.IsDir() {
return `<D:collection xmlns:D="DAV:"/>`
}
return ""
}
func findDisplayName(fi core.FileInfo) string {
func findDisplayName(fi core.ResourceInfo) string {
return escapeXML(fi.Name())
}
func findContentLength(fi core.FileInfo) string {
func findContentLength(fi core.ResourceInfo) string {
return strconv.FormatInt(fi.Size(), 10)
}
func findLastModified(fi core.FileInfo) string {
func findLastModified(fi core.ResourceInfo) string {
return fi.ModTime().UTC().Format(http.TimeFormat)
}
func findContentType(fi core.FileInfo) string {
func findContentType(fi core.ResourceInfo) string {
return fi.ContentType()
}
func findETag(fi core.FileInfo) string {
func findETag(fi core.ResourceInfo) string {
return fi.ETag()
}
func findSupportedLock(fi core.FileInfo) string {
func findSupportedLock(fi core.ResourceInfo) string {
return `` +
`<D:lockentry xmlns:D="DAV:">` +
`<D:lockscope><D:exclusive/></D:lockscope>` +

View File

@@ -25,7 +25,7 @@ var htmlReplacer = strings.NewReplacer(
"'", "&#39;",
)
func serveCollection(w http.ResponseWriter, r *http.Request, file core.File) {
func serveCollection(w http.ResponseWriter, r *http.Request, file core.Resource) {
if !strings.HasSuffix(r.URL.Path, "/") {
http.Redirect(w, r, r.URL.String()+"/", http.StatusMovedPermanently)
return
@@ -59,7 +59,7 @@ func serveCollection(w http.ResponseWriter, r *http.Request, file core.File) {
fmt.Fprintf(w, "</pre>\n")
}
func serveResource(w http.ResponseWriter, r *http.Request, file core.File) {
func serveResource(w http.ResponseWriter, r *http.Request, file core.Resource) {
w.Header().Set("Etag", file.ETag())
w.Header().Set("Last-Modified", file.ModTime().Format(http.TimeFormat))
w.Header().Set("Content-Type", file.ContentType())
@@ -206,7 +206,7 @@ func parseRange(s string, size int64) ([]httpRange, error) {
// checkPreconditions evaluates request preconditions and reports whether a precondition
// resulted in sending StatusNotModified or StatusPreconditionFailed.
func checkPreconditions(w http.ResponseWriter, r *http.Request, ri core.FileInfo) (done bool, rangeHeader string) {
func checkPreconditions(w http.ResponseWriter, r *http.Request, ri core.ResourceInfo) (done bool, rangeHeader string) {
// This function carefully follows RFC 7232 section 6.
ch := checkIfMatch(r, ri)
if ch == condNone {
@@ -289,7 +289,7 @@ const (
condFalse
)
func checkIfMatch(r *http.Request, ri core.FileInfo) condResult {
func checkIfMatch(r *http.Request, ri core.ResourceInfo) condResult {
im := r.Header.Get("If-Match")
if im == "" {
return condNone
@@ -319,7 +319,7 @@ func checkIfMatch(r *http.Request, ri core.FileInfo) condResult {
return condFalse
}
func checkIfUnmodifiedSince(r *http.Request, ri core.FileInfo) condResult {
func checkIfUnmodifiedSince(r *http.Request, ri core.ResourceInfo) condResult {
ius := r.Header.Get("If-Unmodified-Since")
if ius == "" || isZeroTime(ri.ModTime()) {
return condNone
@@ -338,7 +338,7 @@ func checkIfUnmodifiedSince(r *http.Request, ri core.FileInfo) condResult {
return condFalse
}
func checkIfNoneMatch(r *http.Request, ri core.FileInfo) condResult {
func checkIfNoneMatch(r *http.Request, ri core.ResourceInfo) condResult {
inm := r.Header.Get("If-None-Match")
if inm == "" {
return condNone
@@ -368,7 +368,7 @@ func checkIfNoneMatch(r *http.Request, ri core.FileInfo) condResult {
return condTrue
}
func checkIfModifiedSince(r *http.Request, ri core.FileInfo) condResult {
func checkIfModifiedSince(r *http.Request, ri core.ResourceInfo) condResult {
if r.Method != "GET" && r.Method != "HEAD" {
return condNone
}
@@ -389,7 +389,7 @@ func checkIfModifiedSince(r *http.Request, ri core.FileInfo) condResult {
return condTrue
}
func checkIfRange(r *http.Request, ri core.FileInfo) condResult {
func checkIfRange(r *http.Request, ri core.ResourceInfo) condResult {
if r.Method != "GET" && r.Method != "HEAD" {
return condNone
}

View File

@@ -524,7 +524,7 @@ func (h *Handler) handlePropfind(w http.ResponseWriter, r *http.Request) (status
mw := multistatusWriter{w: w}
walkFn := func(reqPath string, info core.FileInfo, err error) error {
walkFn := func(reqPath string, info core.Resource, err error) error {
if err != nil {
return handlePropfindError(err, info)
}
@@ -625,7 +625,7 @@ func makePropstatResponse(href string, pstats []Propstat) *response {
return &resp
}
func handlePropfindError(err error, info core.FileInfo) error {
func handlePropfindError(err error, info core.ResourceInfo) error {
var skipResp error = nil
if info.IsDir() {
skipResp = filepath.SkipDir