Refactoring and first steps to make multi OS compatible.
- Using cgofuse to be compatible with multiple OSes - Refactor to make possible better testing - Add a bunch of tests - Add code coverage Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
This commit is contained in:
parent
89af681694
commit
45f10e2f81
27 changed files with 1291 additions and 440 deletions
90
fuse/handler.go
Normal file
90
fuse/handler.go
Normal file
|
@ -0,0 +1,90 @@
|
|||
package fuse
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ajnavarro/distribyted/config"
|
||||
"github.com/ajnavarro/distribyted/fs"
|
||||
"github.com/ajnavarro/distribyted/stats"
|
||||
"github.com/anacrolix/torrent"
|
||||
"github.com/billziss-gh/cgofuse/fuse"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
c *torrent.Client
|
||||
s *stats.Torrent
|
||||
|
||||
hosts map[string]*fuse.FileSystemHost
|
||||
}
|
||||
|
||||
func NewHandler(c *torrent.Client, s *stats.Torrent) *Handler {
|
||||
return &Handler{
|
||||
c: c,
|
||||
s: s,
|
||||
hosts: make(map[string]*fuse.FileSystemHost),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Handler) Mount(mpc *config.MountPoint) error {
|
||||
var torrents []fs.Filesystem
|
||||
for _, mpcTorrent := range mpc.Torrents {
|
||||
var t *torrent.Torrent
|
||||
var err error
|
||||
|
||||
switch {
|
||||
case mpcTorrent.MagnetURI != "":
|
||||
t, err = s.c.AddMagnet(mpcTorrent.MagnetURI)
|
||||
break
|
||||
case mpcTorrent.TorrentPath != "":
|
||||
t, err = s.c.AddTorrentFromFile(mpcTorrent.TorrentPath)
|
||||
break
|
||||
default:
|
||||
err = fmt.Errorf("no magnet URI or torrent path provided")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// only get info if name is not available
|
||||
if t.Name() == "" {
|
||||
log.WithField("hash", t.InfoHash()).Info("getting torrent info")
|
||||
<-t.GotInfo()
|
||||
}
|
||||
|
||||
s.s.Add(mpc.Path, t)
|
||||
torrents = append(torrents, fs.NewTorrent(t))
|
||||
|
||||
log.WithField("name", t.Name()).WithField("path", mpc.Path).Info("torrent added to mountpoint")
|
||||
}
|
||||
|
||||
// TODO change permissions
|
||||
// if err := os.MkdirAll(mpc.Path, 0770); err != nil && !os.IsExist(err) {
|
||||
// return err
|
||||
// }
|
||||
|
||||
host := fuse.NewFileSystemHost(&FS{FSS: torrents})
|
||||
|
||||
go func() {
|
||||
ok := host.Mount(mpc.Path, nil)
|
||||
if !ok {
|
||||
log.WithField("path", mpc.Path).Error("error trying to mount filesystem")
|
||||
}
|
||||
}()
|
||||
|
||||
s.hosts[mpc.Path] = host
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Handler) Close() {
|
||||
for path, server := range s.hosts {
|
||||
log.WithField("path", path).Info("unmounting")
|
||||
ok := server.Unmount()
|
||||
if !ok {
|
||||
//TODO try to force unmount if possible
|
||||
log.WithField("path", path).Error("unmount failed")
|
||||
}
|
||||
}
|
||||
}
|
146
fuse/mount.go
Normal file
146
fuse/mount.go
Normal file
|
@ -0,0 +1,146 @@
|
|||
package fuse
|
||||
|
||||
import (
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/ajnavarro/distribyted/fs"
|
||||
"github.com/billziss-gh/cgofuse/fuse"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type FS struct {
|
||||
fuse.FileSystemBase
|
||||
|
||||
lock sync.Mutex
|
||||
FSS []fs.Filesystem
|
||||
}
|
||||
|
||||
func (fs *FS) Open(path string, flags int) (errc int, fh uint64) {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
func (fs *FS) Getattr(path string, stat *fuse.Stat_t, fh uint64) (errc int) {
|
||||
defer fs.synchronize()()
|
||||
|
||||
if path == "/" {
|
||||
stat.Mode = fuse.S_IFDIR | 0555
|
||||
return 0
|
||||
}
|
||||
|
||||
file, err := fs.findFile(path)
|
||||
if err != nil {
|
||||
logrus.WithField("path", path).WithError(err).Warn("error finding file")
|
||||
return -fuse.EIO
|
||||
}
|
||||
|
||||
if err == os.ErrNotExist {
|
||||
logrus.WithField("path", path).Warn("file does not exists")
|
||||
return -fuse.ENOENT
|
||||
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logrus.WithField("path", path).WithError(err).Error("error reading file")
|
||||
return -fuse.EIO
|
||||
}
|
||||
|
||||
if file.IsDir() {
|
||||
stat.Mode = fuse.S_IFDIR | 0555
|
||||
} else {
|
||||
stat.Mode = fuse.S_IFREG | 0444
|
||||
stat.Size = file.Size()
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (fs *FS) Read(path string, dest []byte, off int64, fh uint64) int {
|
||||
defer fs.synchronize()()
|
||||
|
||||
file, err := fs.findFile(path)
|
||||
if err == os.ErrNotExist {
|
||||
logrus.WithField("path", path).Warn("file does not exists")
|
||||
return -fuse.ENOENT
|
||||
|
||||
}
|
||||
if err != nil {
|
||||
logrus.WithField("path", path).WithError(err).Warn("error finding file")
|
||||
return -fuse.EIO
|
||||
}
|
||||
|
||||
end := int(math.Min(float64(len(dest)), float64(int64(file.Size())-off)))
|
||||
if end < 0 {
|
||||
end = 0
|
||||
}
|
||||
|
||||
buf := dest[:end]
|
||||
|
||||
n, err := file.ReadAt(buf, off)
|
||||
if err != nil && err != io.EOF {
|
||||
logrus.WithError(err).Error("error reading data")
|
||||
return -fuse.EIO
|
||||
}
|
||||
|
||||
dest = buf[:n]
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
func (fs *FS) Release(path string, fh uint64) (errc int) {
|
||||
defer fs.synchronize()()
|
||||
return 0
|
||||
}
|
||||
|
||||
func (fs *FS) Readdir(path string,
|
||||
fill func(name string, stat *fuse.Stat_t, ofst int64) bool,
|
||||
ofst int64,
|
||||
fh uint64) (errc int) {
|
||||
defer fs.synchronize()()
|
||||
|
||||
fill(".", nil, 0)
|
||||
fill("..", nil, 0)
|
||||
|
||||
for _, ifs := range fs.FSS {
|
||||
files, err := ifs.ReadDir(path)
|
||||
if err != nil {
|
||||
return -fuse.EIO
|
||||
}
|
||||
for p := range files {
|
||||
if !fill(p, nil, 0) {
|
||||
logrus.WithField("path", p).Error("error adding directory")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (fs *FS) findFile(path string) (fs.File, error) {
|
||||
for _, f := range fs.FSS {
|
||||
file, err := f.Open(path)
|
||||
if err == os.ErrNotExist {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO add file to list of opened files to be able to close it when not in use
|
||||
if file != nil {
|
||||
return file, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
|
||||
func (fs *FS) synchronize() func() {
|
||||
fs.lock.Lock()
|
||||
return func() {
|
||||
fs.lock.Unlock()
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue