189 lines
4.3 KiB
Go
189 lines
4.3 KiB
Go
package zfs
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"syscall"
|
|
"time"
|
|
|
|
"bazil.org/fuse"
|
|
"bazil.org/fuse/fs"
|
|
"github.com/debridmediamanager.com/zurg/internal/torrent"
|
|
"github.com/debridmediamanager.com/zurg/internal/universal"
|
|
)
|
|
|
|
// define variable as rootObject id
|
|
const (
|
|
ROOT = 0
|
|
DIRECTORY = 1
|
|
TORRENT = 2
|
|
FILE = 3
|
|
)
|
|
|
|
type Object struct {
|
|
fs *FS
|
|
objType int
|
|
parentName string
|
|
name string
|
|
torrent *torrent.Torrent
|
|
file *torrent.File
|
|
size uint64
|
|
mtime time.Time
|
|
}
|
|
|
|
// Attr returns the attributes for a directory
|
|
func (o Object) Attr(ctx context.Context, attr *fuse.Attr) error {
|
|
if o.objType == FILE {
|
|
attr.Mode = 0644
|
|
} else {
|
|
attr.Mode = os.ModeDir | 0755
|
|
}
|
|
attr.Size = o.size
|
|
|
|
attr.Uid = o.fs.uid
|
|
attr.Gid = o.fs.gid
|
|
|
|
attr.Ctime = o.mtime
|
|
attr.Mtime = o.mtime
|
|
|
|
attr.Blocks = (attr.Size + 511) >> 9
|
|
|
|
return nil
|
|
}
|
|
|
|
// ReadDirAll shows all files in the current directory
|
|
func (o Object) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
|
dirs := []fuse.Dirent{}
|
|
switch o.objType {
|
|
case ROOT:
|
|
for _, directory := range o.fs.config.GetDirectories() {
|
|
dirs = append(dirs, fuse.Dirent{
|
|
Name: directory,
|
|
Type: fuse.DT_Dir,
|
|
})
|
|
}
|
|
case DIRECTORY:
|
|
for el := o.fs.tMgr.TorrentMap.Front(); el != nil; el = el.Next() {
|
|
torrent := el.Value
|
|
if torrent.InProgress {
|
|
continue
|
|
}
|
|
dirs = append(dirs, fuse.Dirent{
|
|
Name: torrent.AccessKey,
|
|
Type: fuse.DT_Dir,
|
|
})
|
|
}
|
|
case TORRENT:
|
|
torrent, _ := o.fs.tMgr.TorrentMap.Get(o.name)
|
|
if torrent == nil || torrent.InProgress {
|
|
return nil, syscall.ENOENT
|
|
}
|
|
for el := torrent.SelectedFiles.Front(); el != nil; el = el.Next() {
|
|
file := el.Value
|
|
if file.Link == "" {
|
|
// log.Println("File has no link, skipping", file.Path)
|
|
continue
|
|
}
|
|
filename := filepath.Base(file.Path)
|
|
dirs = append(dirs, fuse.Dirent{
|
|
Name: filename,
|
|
Type: fuse.DT_File,
|
|
})
|
|
}
|
|
}
|
|
return dirs, nil
|
|
}
|
|
|
|
// Lookup tests if a file is existent in the current directory
|
|
func (o Object) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
|
switch o.objType {
|
|
case ROOT:
|
|
for _, directory := range o.fs.config.GetDirectories() {
|
|
if directory == name {
|
|
return Object{
|
|
fs: o.fs,
|
|
objType: DIRECTORY,
|
|
parentName: o.name,
|
|
name: name,
|
|
mtime: o.fs.initTime,
|
|
}, nil
|
|
}
|
|
}
|
|
case DIRECTORY:
|
|
torrent, _ := o.fs.tMgr.TorrentMap.Get(name)
|
|
if torrent == nil {
|
|
return nil, syscall.ENOENT
|
|
}
|
|
return Object{
|
|
fs: o.fs,
|
|
objType: TORRENT,
|
|
parentName: o.name,
|
|
name: name,
|
|
mtime: convertRFC3339toTime(torrent.LatestAdded),
|
|
}, nil
|
|
|
|
case TORRENT:
|
|
torrent, _ := o.fs.tMgr.TorrentMap.Get(o.name)
|
|
if torrent == nil {
|
|
return nil, syscall.ENOENT
|
|
}
|
|
file, _ := torrent.SelectedFiles.Get(name)
|
|
if file == nil {
|
|
return nil, syscall.ENOENT
|
|
}
|
|
return Object{
|
|
fs: o.fs,
|
|
objType: FILE,
|
|
parentName: o.name,
|
|
name: name,
|
|
torrent: torrent,
|
|
file: file,
|
|
size: uint64(file.Bytes),
|
|
mtime: convertRFC3339toTime(file.Added),
|
|
}, nil
|
|
}
|
|
return nil, syscall.ENOENT
|
|
}
|
|
|
|
// Open a file
|
|
func (o Object) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
|
|
resp.Flags |= fuse.OpenDirectIO
|
|
return o, nil
|
|
}
|
|
|
|
// Read reads some bytes or the whole file
|
|
func (o Object) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
|
|
reader := universal.GetFileReader(o.torrent, o.file, req.Offset, int(req.Size), o.fs.tMgr, o.fs.config, o.fs.log)
|
|
if reader == nil {
|
|
return syscall.EIO
|
|
}
|
|
defer reader.Close()
|
|
resp.Data = make([]byte, req.Size)
|
|
_, err := reader.Read(resp.Data)
|
|
if err != nil && err.Error() != "EOF" {
|
|
o.fs.log.Errorf("Error reading bytes from Real-Debrid: %v", err)
|
|
return syscall.EIO
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Remove deletes an element
|
|
func (o Object) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
|
|
return fmt.Errorf("Remove not yet implemented")
|
|
}
|
|
|
|
// Rename renames an element
|
|
func (o Object) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fs.Node) error {
|
|
return fmt.Errorf("Rename not yet implemented")
|
|
}
|
|
|
|
func convertRFC3339toTime(input string) time.Time {
|
|
t, err := time.Parse(time.RFC3339, input)
|
|
if err != nil {
|
|
return time.Now()
|
|
}
|
|
return t
|
|
}
|