From 5f292a059191130044660c2f910b8d2d4e937bf0 Mon Sep 17 00:00:00 2001 From: royalcat Date: Tue, 17 Oct 2023 21:30:10 +0300 Subject: [PATCH] [feature] file exclude --- .github/workflows/docker.yaml | 3 -- src/host/torrent/service.go | 4 +++ src/host/vfs/resolver.go | 55 ++++++++++++++++++++++------------- src/host/vfs/resolver_test.go | 26 +++++++++++++++++ src/host/vfs/torrent.go | 32 +++++++++----------- src/host/vfs/utils.go | 41 -------------------------- src/host/vfs/utils_test.go | 33 --------------------- 7 files changed, 79 insertions(+), 115 deletions(-) delete mode 100644 src/host/vfs/utils_test.go diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index 3c7e138..ff0ca42 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -24,9 +24,6 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 diff --git a/src/host/torrent/service.go b/src/host/torrent/service.go index de87544..b251aff 100644 --- a/src/host/torrent/service.go +++ b/src/host/torrent/service.go @@ -47,6 +47,10 @@ func (s *Service) NewTorrentFs(f vfs.File) (vfs.Filesystem, error) { } <-t.GotInfo() t.AllowDataDownload() + for _, f := range t.Files() { + f.SetPriority(torrent.PiecePriorityReadahead) + } + return vfs.NewTorrentFs(t, s.readTimeout), nil } diff --git a/src/host/vfs/resolver.go b/src/host/vfs/resolver.go index ba72174..df1ffd8 100644 --- a/src/host/vfs/resolver.go +++ b/src/host/vfs/resolver.go @@ -2,6 +2,7 @@ package vfs import ( "fmt" + "io/fs" "strings" "sync" ) @@ -119,28 +120,42 @@ PARTS_LOOP: } -// func (r *resolver) resolveFile(name string, fs Filesystem) (File, error) { -// fsPath, nestedFs, nestedFsPath, err := r.resolvePath(name, fs) -// if err != nil { -// return nil, err -// } +var ErrNotExist = fs.ErrNotExist -// if nestedFs == nil { -// return fs.Open(fsPath) -// } +func getFile[F File](m map[string]F, name string) (File, error) { + name = clean(name) + if name == Separator { + return &Dir{}, nil + } -// return nestedFs.Open(nestedFsPath) -// } + f, ok := m[name] + if ok { + return f, nil + } -// func (r *resolver) resolveDir(name string, fs Filesystem) (map[string]File, error) { -// fsPath, nestedFs, nestedFsPath, err := r.resolvePath(name, fs) -// if err != nil { -// return nil, err -// } + for p := range m { + if strings.HasPrefix(p, name) { + return &Dir{}, nil + } + } -// if nestedFs == nil { -// return fs.ReadDir(fsPath) -// } + return nil, ErrNotExist +} -// return nestedFs.ReadDir(nestedFsPath) -// } +func listFilesInDir[F File](m map[string]F, name string) (map[string]File, error) { + name = clean(name) + + out := map[string]File{} + for p, f := range m { + if strings.HasPrefix(p, name) { + parts := strings.Split(trimRelPath(p, name), Separator) + if len(parts) == 1 { + out[parts[0]] = f + } else { + out[parts[0]] = &Dir{} + } + } + } + + return out, nil +} diff --git a/src/host/vfs/resolver_test.go b/src/host/vfs/resolver_test.go index c1df6d5..401459f 100644 --- a/src/host/vfs/resolver_test.go +++ b/src/host/vfs/resolver_test.go @@ -144,3 +144,29 @@ func TestArchiveFactories(t *testing.T) { require.NoError(err) require.NotNil(fs) } + +func TestFiles(t *testing.T) { + t.Parallel() + require := require.New(t) + + files := map[string]*Dummy{ + "/test/file.txt": &Dummy{}, + } + { + file, err := getFile(files, "/test") + require.Nil(err) + require.Equal(&Dir{}, file) + } + { + file, err := getFile(files, "/test/file.txt") + require.Nil(err) + require.Equal(&Dummy{}, file) + } + + { + out, err := listFilesInDir(files, "/test") + require.Nil(err) + require.Contains(out, "file.txt") + require.Equal(&Dummy{}, out["file.txt"]) + } +} diff --git a/src/host/vfs/torrent.go b/src/host/vfs/torrent.go index d6e051a..2089f03 100644 --- a/src/host/vfs/torrent.go +++ b/src/host/vfs/torrent.go @@ -33,6 +33,10 @@ func (fs *TorrentFs) files() map[string]*torrentFile { files := make(map[string]*torrentFile) <-fs.t.GotInfo() for _, file := range fs.t.Files() { + if file.Priority() == torrent.PiecePriorityNone { + continue + } + p := clean(file.Path()) files[p] = &torrentFile{ readerFunc: file.NewReader, @@ -73,6 +77,12 @@ func (fs *TorrentFs) ReadDir(name string) (map[string]File, error) { return listFilesInDir(fs.files(), fsPath) } +func (fs *TorrentFs) Unlink(name string) error { + file := fs.t.Files()[0] + file.SetPriority(torrent.PiecePriorityNone) + return nil +} + type reader interface { iio.Reader missinggo.ReadContexter @@ -111,18 +121,11 @@ func readAtLeast(r missinggo.ReadContexter, timeout int, buf []byte, min int) (n for n < min && err == nil { var nn int - ctx, cancel := context.WithCancel(context.Background()) - timer := time.AfterFunc( - time.Duration(timeout)*time.Second, - func() { - cancel() - }, - ) + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second) + defer cancel() nn, err = r.ReadContext(ctx, buf[n:]) n += nn - - timer.Stop() } if n >= min { err = nil @@ -175,15 +178,8 @@ func (d *torrentFile) Close() error { func (d *torrentFile) Read(p []byte) (n int, err error) { d.load() - ctx, cancel := context.WithCancel(context.Background()) - timer := time.AfterFunc( - time.Duration(d.timeout)*time.Second, - func() { - cancel() - }, - ) - - defer timer.Stop() + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(d.timeout)*time.Second) + defer cancel() return d.reader.ReadContext(ctx, p) } diff --git a/src/host/vfs/utils.go b/src/host/vfs/utils.go index 49feac7..7f36933 100644 --- a/src/host/vfs/utils.go +++ b/src/host/vfs/utils.go @@ -1,51 +1,10 @@ package vfs import ( - "io/fs" "path" "strings" ) -var ErrNotExist = fs.ErrNotExist - -func getFile[F File](m map[string]F, name string) (File, error) { - name = clean(name) - if name == Separator { - return &Dir{}, nil - } - - f, ok := m[name] - if ok { - return f, nil - } - - for p := range m { - if strings.HasPrefix(p, name) { - return &Dir{}, nil - } - } - - return nil, ErrNotExist -} - -func listFilesInDir[F File](m map[string]F, name string) (map[string]File, error) { - name = clean(name) - - out := map[string]File{} - for p, f := range m { - if strings.HasPrefix(p, name) { - parts := strings.Split(trimRelPath(p, name), Separator) - if len(parts) == 1 { - out[parts[0]] = f - } else { - out[parts[0]] = &Dir{} - } - } - } - - return out, nil -} - func trimRelPath(p, t string) string { return strings.Trim(strings.TrimPrefix(p, t), "/") } diff --git a/src/host/vfs/utils_test.go b/src/host/vfs/utils_test.go deleted file mode 100644 index 29ec21b..0000000 --- a/src/host/vfs/utils_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package vfs - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestFiles(t *testing.T) { - t.Parallel() - require := require.New(t) - - files := map[string]*Dummy{ - "/test/file.txt": &Dummy{}, - } - { - file, err := getFile(files, "/test") - require.Nil(err) - require.Equal(&Dir{}, file) - } - { - file, err := getFile(files, "/test/file.txt") - require.Nil(err) - require.Equal(&Dummy{}, file) - } - - { - out, err := listFilesInDir(files, "/test") - require.Nil(err) - require.Contains(out, "file.txt") - require.Equal(&Dummy{}, out["file.txt"]) - } -}