diff --git a/cmd/tstor/main.go b/cmd/tstor/main.go index 645e4a5..3131e8f 100644 --- a/cmd/tstor/main.go +++ b/cmd/tstor/main.go @@ -176,7 +176,7 @@ func run(configPath string) error { go func() { logFilename := filepath.Join(conf.Log.Path, dlog.FileName) - err = http.New(nil, nil, ts, logFilename, conf) + err = http.New(nil, service.NewStats(), ts, logFilename, conf) log.Error().Err(err).Msg("error initializing HTTP server") }() diff --git a/src/host/storage/repository.go b/src/host/storage/repository.go index b988485..07985e1 100644 --- a/src/host/storage/repository.go +++ b/src/host/storage/repository.go @@ -7,6 +7,7 @@ import ( "github.com/anacrolix/torrent" "github.com/anacrolix/torrent/metainfo" + atstorage "github.com/anacrolix/torrent/storage" "github.com/philippgille/gokv" "github.com/philippgille/gokv/badgerdb" "github.com/philippgille/gokv/encoding" @@ -17,7 +18,7 @@ type TorrentsRepository interface { ExcludedFiles(hash metainfo.Hash) ([]string, error) } -func NewTorrentMetaRepository(metaDir string, storage *FileStorage) (TorrentsRepository, error) { +func NewTorrentMetaRepository(metaDir string, storage atstorage.ClientImplCloser) (TorrentsRepository, error) { excludedFilesStore, err := badgerdb.NewStore(badgerdb.Options{ Dir: filepath.Join(metaDir, "excluded-files"), Codec: encoding.JSON, @@ -38,7 +39,7 @@ func NewTorrentMetaRepository(metaDir string, storage *FileStorage) (TorrentsRep type torrentRepositoryImpl struct { m sync.RWMutex excludedFiles gokv.Store - storage *FileStorage + storage atstorage.ClientImplCloser } var ErrNotFound = errors.New("not found") @@ -58,9 +59,11 @@ func (r *torrentRepositoryImpl) ExcludeFile(file *torrent.File) error { } excludedFiles = unique(append(excludedFiles, file.Path())) - err = r.storage.DeleteFile(file) - if err != nil { - return err + if storage, ok := r.storage.(FileStorageDeleter); ok { + err = storage.DeleteFile(file) + if err != nil { + return err + } } return r.excludedFiles.Set(hash.AsString(), excludedFiles) diff --git a/src/host/storage/storage.go b/src/host/storage/storage.go index b1719ac..33cfed4 100644 --- a/src/host/storage/storage.go +++ b/src/host/storage/storage.go @@ -9,7 +9,7 @@ import ( "github.com/anacrolix/torrent/storage" ) -func SetupStorage(cfg config.TorrentClient) (*FileStorage, storage.PieceCompletion, error) { +func SetupStorage(cfg config.TorrentClient) (storage.ClientImplCloser, storage.PieceCompletion, error) { pcp := filepath.Join(cfg.DataFolder, "piece-completion") if err := os.MkdirAll(pcp, 0744); err != nil { return nil, nil, fmt.Errorf("error creating piece completion folder: %w", err) @@ -39,13 +39,19 @@ func SetupStorage(cfg config.TorrentClient) (*FileStorage, storage.PieceCompleti // rp := storage.NewResourcePieces(fc.AsResourceProvider()) // st := &stc{rp} - filesDir := filepath.Join(cfg.DataFolder, "files") - if err := os.MkdirAll(pcp, 0744); err != nil { + // filesDir := filepath.Join(cfg.DataFolder, "files") + // if err := os.MkdirAll(filesDir, 0744); err != nil { + // return nil, nil, fmt.Errorf("error creating piece completion folder: %w", err) + // } + + //st := NewFileStorage(filesDir, pc) + + piecesDir := filepath.Join(cfg.DataFolder, "pieces") + if err := os.MkdirAll(piecesDir, 0744); err != nil { return nil, nil, fmt.Errorf("error creating piece completion folder: %w", err) } - // st := storage.NewMMapWithCompletion(filesDir, pc) - st := NewFileStorage(filesDir, pc) + st := storage.NewMMapWithCompletion(piecesDir, pc) return st, pc, nil } diff --git a/src/host/storage/storage_files.go b/src/host/storage/storage_files.go index e6d109f..04c837b 100644 --- a/src/host/storage/storage_files.go +++ b/src/host/storage/storage_files.go @@ -17,8 +17,13 @@ import ( "github.com/anacrolix/torrent/storage" ) +type FileStorageDeleter interface { + storage.ClientImplCloser + DeleteFile(file *torrent.File) error +} + // NewFileStorage creates a new ClientImplCloser that stores files using the OS native filesystem. -func NewFileStorage(baseDir string, pc storage.PieceCompletion) *FileStorage { +func NewFileStorage(baseDir string, pc storage.PieceCompletion) FileStorageDeleter { return &FileStorage{baseDir: baseDir, pieceCompletion: pc} } @@ -46,6 +51,13 @@ func (fs *FileStorage) DeleteFile(file *torrent.File) error { torrentDir := fs.torrentDir(info, infoHash) relFilePath := fs.filePath(file.FileInfo()) filePath := path.Join(torrentDir, relFilePath) + for i := file.BeginPieceIndex(); i < file.EndPieceIndex(); i++ { + pk := metainfo.PieceKey{InfoHash: infoHash, Index: i} + err := fs.pieceCompletion.Set(pk, false) + if err != nil { + return err + } + } return os.Remove(filePath) } diff --git a/src/host/vfs/resolver.go b/src/host/vfs/resolver.go index 919fe50..5685d0b 100644 --- a/src/host/vfs/resolver.go +++ b/src/host/vfs/resolver.go @@ -204,6 +204,9 @@ func listDirFromFiles[F File](m map[string]F, name string) ([]fs.DirEntry, error } } + slices.SortStableFunc(out, func(de1, de2 fs.DirEntry) int { + return strings.Compare(de1.Name(), de2.Name()) + }) out = slices.CompactFunc(out, func(de1, de2 fs.DirEntry) bool { return de1.Name() == de2.Name() }) diff --git a/src/host/vfs/torrent.go b/src/host/vfs/torrent.go index ccf38ef..43a6f21 100644 --- a/src/host/vfs/torrent.go +++ b/src/host/vfs/torrent.go @@ -6,6 +6,7 @@ import ( "io/fs" "path" "slices" + "strings" "sync" "time" @@ -54,11 +55,21 @@ func (fs *TorrentFs) files() (map[string]*torrentFile, error) { fs.filesCache = make(map[string]*torrentFile) for _, file := range files { - if slices.Contains(excludedFiles, file.Path()) { + p := file.Path() + + if slices.Contains(excludedFiles, p) { + continue + } + if strings.Contains(p, "/.pad/") { continue } - p := AbsPath(file.Path()) + p = AbsPath(file.Path()) + + // TODO make optional + // removing the torrent root directory of same name as torrent + p, _ = strings.CutPrefix(p, "/"+fs.t.Name()+"/") + p = AbsPath(p) fs.filesCache[p] = &torrentFile{ name: path.Base(p),