Big refactor

This commit is contained in:
Ben Sarmiento
2023-11-14 01:55:00 +01:00
parent 5e723a9e8a
commit 16505ec33f
26 changed files with 1602 additions and 453 deletions

View File

@@ -1,33 +0,0 @@
package zfs
import (
"os"
"sync"
"time"
"bazil.org/fuse/fs"
"github.com/debridmediamanager.com/zurg/internal/config"
"github.com/debridmediamanager.com/zurg/internal/torrent"
"go.uber.org/zap"
)
type FS struct {
uid uint32
gid uint32
umask os.FileMode
directIO bool
lock sync.RWMutex
config config.ConfigInterface
tMgr *torrent.TorrentManager
log *zap.SugaredLogger
initTime time.Time
}
// Root returns the root path
func (f *FS) Root() (fs.Node, error) {
return Object{
fs: f,
objType: ROOT,
mtime: f.initTime,
}, nil
}

View File

@@ -1,54 +1,18 @@
package zfs
import (
"os"
"time"
"bazil.org/fuse"
"bazil.org/fuse/fs"
"github.com/debridmediamanager.com/zurg/internal/config"
"github.com/debridmediamanager.com/zurg/internal/torrent"
"github.com/debridmediamanager.com/zurg/pkg/logutil"
"golang.org/x/sys/unix"
"github.com/winfsp/cgofuse/fuse"
)
func Mount(mountpoint string, cfg config.ConfigInterface, tMgr *torrent.TorrentManager) error {
log := logutil.NewLogger().Named("zfs")
options := []fuse.MountOption{
fuse.AllowOther(),
fuse.AllowNonEmptyMount(),
fuse.MaxReadahead(uint32(128 << 10)),
fuse.DefaultPermissions(),
fuse.FSName("zurgfs"),
}
conn, err := fuse.Mount(mountpoint, options...)
if err != nil {
return err
}
defer conn.Close()
srv := fs.New(conn, nil)
filesys := &FS{
uid: uint32(unix.Geteuid()),
gid: uint32(unix.Getegid()),
umask: os.FileMode(0),
config: cfg,
tMgr: tMgr,
log: log,
initTime: time.Now(),
}
if err := srv.Serve(filesys); err != nil {
return err
}
func Mount(host *fuse.FileSystemHost, cfg config.ConfigInterface) error {
host.SetCapCaseInsensitive(false)
host.SetCapReaddirPlus(false)
host.Mount(cfg.GetMountPoint(), []string{})
return nil
}
func Unmount(mountpoint string) error {
fuse.Unmount(mountpoint)
func Unmount(host *fuse.FileSystemHost) error {
_ = host.Unmount()
return nil
}

View File

@@ -1,188 +0,0 @@
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
}

185
internal/zfs/zfs.go Normal file
View File

@@ -0,0 +1,185 @@
package zfs
import (
"strings"
"github.com/debridmediamanager.com/zurg/internal/config"
"github.com/debridmediamanager.com/zurg/internal/torrent"
"github.com/debridmediamanager.com/zurg/pkg/chunk"
"github.com/winfsp/cgofuse/fuse"
"go.uber.org/zap"
)
type ZurgFS struct {
fuse.FileSystemBase
TorrentManager *torrent.TorrentManager
Config config.ConfigInterface
Chunk *chunk.Manager
Log *zap.SugaredLogger
}
func NewZurgFS(tm *torrent.TorrentManager, cfg config.ConfigInterface, chunk *chunk.Manager, log *zap.SugaredLogger) *ZurgFS {
return &ZurgFS{
TorrentManager: tm,
Config: cfg,
Chunk: chunk,
Log: log,
}
}
func (fs *ZurgFS) Open(path string, flags int) (errc int, fh uint64) {
segments := splitIntoSegments(path)
switch len(segments) {
case 0:
return 0, 0
case 1:
if _, dirFound := fs.TorrentManager.DirectoryMap.Get(segments[0]); !dirFound {
return -fuse.ENOENT, ^uint64(0)
}
return 0, 0
case 2:
if directory, dirFound := fs.TorrentManager.DirectoryMap.Get(segments[0]); !dirFound {
return -fuse.ENOENT, ^uint64(0)
} else if _, torFound := directory.Get(segments[1]); !torFound {
return -fuse.ENOENT, ^uint64(0)
}
return 0, 0
case 3:
if directory, dirFound := fs.TorrentManager.DirectoryMap.Get(segments[0]); !dirFound {
return -fuse.ENOENT, ^uint64(0)
} else if torrent, torFound := directory.Get(segments[1]); !torFound {
return -fuse.ENOENT, ^uint64(0)
} else if file, fileFound := torrent.SelectedFiles.Get(segments[2]); !fileFound {
return -fuse.ENOENT, ^uint64(0)
} else {
return 0, file.ZurgFS
}
}
return -fuse.ENOENT, ^uint64(0)
}
func (fs *ZurgFS) Getattr(path string, stat *fuse.Stat_t, fh uint64) (errc int) {
segments := splitIntoSegments(path)
switch len(segments) {
case 0:
stat.Mode = fuse.S_IFDIR | 0555
return 0
case 1:
if _, dirFound := fs.TorrentManager.DirectoryMap.Get(segments[0]); !dirFound {
return -fuse.ENOENT
}
stat.Mode = fuse.S_IFDIR | 0555
return 0
case 2:
if directory, dirFound := fs.TorrentManager.DirectoryMap.Get(segments[0]); !dirFound {
return -fuse.ENOENT
} else if _, torFound := directory.Get(segments[1]); !torFound {
return -fuse.ENOENT
}
stat.Mode = fuse.S_IFDIR | 0555
return 0
case 3:
if directory, dirFound := fs.TorrentManager.DirectoryMap.Get(segments[0]); !dirFound {
return -fuse.ENOENT
} else if torrent, torFound := directory.Get(segments[1]); !torFound {
return -fuse.ENOENT
} else if file, fileFound := torrent.SelectedFiles.Get(segments[2]); !fileFound {
return -fuse.ENOENT
} else {
stat.Mode = fuse.S_IFREG | 0444
stat.Size = file.Bytes
return 0
}
}
return -fuse.ENOENT
}
func (fs *ZurgFS) Read(path string, buff []byte, ofst int64, fh uint64) (n int) {
segments := splitIntoSegments(path)
if len(segments) != 3 {
return -fuse.ENOENT
} else if directory, dirFound := fs.TorrentManager.DirectoryMap.Get(segments[0]); !dirFound {
return -fuse.ENOENT
} else if torrent, torFound := directory.Get(segments[1]); !torFound {
return -fuse.ENOENT
} else if file, fileFound := torrent.SelectedFiles.Get(segments[2]); !fileFound {
return -fuse.ENOENT
} else {
size := int64(len(buff))
if size < int64(fs.Config.GetNetworkBufferSize()) {
size = int64(fs.Config.GetNetworkBufferSize())
}
endofst := ofst + size
if endofst > file.Bytes {
endofst = file.Bytes
}
if endofst < ofst {
return 0
}
response, err := fs.Chunk.GetChunk(file, ofst, size)
if err != nil {
return -fuse.ENOENT
}
// response := universal.GetFileReader(torrent, file, ofst, int(size), fs.TorrentManager, fs.Config, fs.Log)
// if response == nil {
// return -fuse.ENOENT
// }
n = copy(buff, response[:endofst-ofst])
return n
}
}
func (fs *ZurgFS) Readdir(path string,
fill func(name string, stat *fuse.Stat_t, ofst int64) bool,
ofst int64,
fh uint64) (errc int) {
segments := splitIntoSegments(path)
switch len(segments) {
case 0:
fill(".", nil, 0)
fill("..", nil, 0)
for el := fs.TorrentManager.DirectoryMap.Front(); el != nil; el = el.Next() {
fill(el.Key, nil, 0)
}
case 1:
fill(".", nil, 0)
fill("..", nil, 0)
if directory, dirFound := fs.TorrentManager.DirectoryMap.Get(segments[0]); !dirFound {
return -fuse.ENOENT
} else {
for el := directory.Front(); el != nil; el = el.Next() {
fill(el.Key, nil, 0)
}
}
case 2:
fill(".", nil, 0)
fill("..", nil, 0)
if directory, dirFound := fs.TorrentManager.DirectoryMap.Get(segments[0]); !dirFound {
return -fuse.ENOENT
} else if torrent, torFound := directory.Get(segments[1]); !torFound {
return -fuse.ENOENT
} else {
for el := torrent.SelectedFiles.Front(); el != nil; el = el.Next() {
fill(el.Key, nil, 0)
}
}
default:
return -fuse.ENOENT
}
return 0
}
func splitIntoSegments(path string) []string {
segments := strings.Split(path, "/")
// remove empty segments
for i := 0; i < len(segments); i++ {
if segments[i] == "" {
segments = append(segments[:i], segments[i+1:]...)
i--
}
}
return segments
}