diff --git a/daemons/atorrent/.gqlgen.yml b/daemons/atorrent/.gqlgen.yml
deleted file mode 100644
index 0af5731..0000000
--- a/daemons/atorrent/.gqlgen.yml
+++ /dev/null
@@ -1,64 +0,0 @@
-schema:
-  - graphql/*.graphql
-  - graphql/**/*.graphql
-  - ../../graphql/types/*.graphql
-
-exec:
-  filename: delivery/graphql/generated.go
-model:
-  filename: delivery/graphql/models_gen.go
-resolver:
-  type: Resolver
-  layout: follow-schema
-  dir: delivery/graphql
-
-autobind:
-  - "git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
-
-models:
-  DateTime:
-    model: github.com/99designs/gqlgen/graphql.Time
-  Int:
-    model: github.com/99designs/gqlgen/graphql.Int64
-  UInt:
-    model:
-      - github.com/99designs/gqlgen/graphql.Uint
-  Torrent:
-    extraFields:
-      T:
-        type: "*git.kmsign.ru/royalcat/tstor/daemons/atorrent.Controller"
-  TorrentFile:
-    extraFields:
-      F:
-        type: "*git.kmsign.ru/royalcat/tstor/daemons/atorrent.FileController"
-  TorrentPeer:
-    extraFields:
-      F:
-        type: "*github.com/anacrolix/torrent.PeerConn"
-  SimpleDir:
-    extraFields:
-      Path:
-        type: string
-      FS:
-        type: "git.kmsign.ru/royalcat/tstor/src/vfs.Filesystem"
-  TorrentFS:
-    extraFields:
-      FS:
-        type: "*git.kmsign.ru/royalcat/tstor/daemons/atorrent.TorrentFS"
-  TorrentOps:
-    extraFields:
-      InfoHash:
-        type: "string"
-  TorrentPriority:
-    model: "github.com/anacrolix/torrent/types.PiecePriority"
-    enum_values:
-      NONE:
-        value: "github.com/anacrolix/torrent/types.PiecePriorityNone"
-      NORMAL:
-        value: "github.com/anacrolix/torrent/types.PiecePriorityNormal"
-      HIGH:
-        value: "github.com/anacrolix/torrent/types.PiecePriorityHigh"
-      READAHEAD:
-        value: "github.com/anacrolix/torrent/types.PiecePriorityReadahead"
-      NOW:
-        value: "github.com/anacrolix/torrent/types.PiecePriorityNow"
diff --git a/daemons/atorrent/client.go b/daemons/atorrent/client.go
deleted file mode 100644
index e0e6b98..0000000
--- a/daemons/atorrent/client.go
+++ /dev/null
@@ -1,110 +0,0 @@
-package atorrent
-
-import (
-	"crypto/rand"
-	"log/slog"
-	"os"
-
-	"git.kmsign.ru/royalcat/tstor/src/config"
-	"git.kmsign.ru/royalcat/tstor/src/logwrap"
-	"github.com/anacrolix/dht/v2/bep44"
-	tlog "github.com/anacrolix/log"
-	"github.com/anacrolix/torrent"
-	"github.com/anacrolix/torrent/storage"
-	"github.com/anacrolix/torrent/types/infohash"
-)
-
-func newClientConfig(st storage.ClientImpl, fis bep44.Store, cfg *config.TorrentClient, id [20]byte) *torrent.ClientConfig {
-	l := slog.With("component", "torrent-client")
-
-	// TODO download and upload limits
-	torrentCfg := torrent.NewDefaultClientConfig()
-	torrentCfg.PeerID = string(id[:])
-	torrentCfg.DefaultStorage = st
-	// torrentCfg.AlwaysWantConns = true
-	torrentCfg.DropMutuallyCompletePeers = true
-	// torrentCfg.TorrentPeersLowWater = 100
-	// torrentCfg.TorrentPeersHighWater = 1000
-	// torrentCfg.AcceptPeerConnections = true
-	torrentCfg.Seed = true
-	torrentCfg.DisableAggressiveUpload = false
-
-	torrentCfg.PeriodicallyAnnounceTorrentsToDht = true
-	// torrentCfg.ConfigureAnacrolixDhtServer = func(cfg *dht.ServerConfig) {
-	// 	cfg.Store = fis
-	// 	cfg.Exp = dhtTTL
-	// 	cfg.PeerStore = fis
-	// }
-
-	tl := tlog.NewLogger("torrent-client")
-	tl.SetHandlers(&logwrap.Torrent{L: l})
-
-	torrentCfg.Logger = tl
-	torrentCfg.Callbacks.NewPeer = append(torrentCfg.Callbacks.NewPeer, func(p *torrent.Peer) {
-		l.With(peerAttrs(p)...).Debug("new peer")
-	})
-	torrentCfg.Callbacks.PeerClosed = append(torrentCfg.Callbacks.PeerClosed, func(p *torrent.Peer) {
-		l.With(peerAttrs(p)...).Debug("peer closed")
-	})
-	torrentCfg.Callbacks.CompletedHandshake = func(pc *torrent.PeerConn, ih infohash.T) {
-		attrs := append(peerAttrs(&pc.Peer), slog.String("infohash", ih.HexString()))
-		l.With(attrs...).Debug("completed handshake")
-	}
-	torrentCfg.Callbacks.PeerConnAdded = append(torrentCfg.Callbacks.PeerConnAdded, func(pc *torrent.PeerConn) {
-		l.With(peerAttrs(&pc.Peer)...).Debug("peer conn added")
-	})
-	torrentCfg.Callbacks.PeerConnClosed = func(pc *torrent.PeerConn) {
-		l.With(peerAttrs(&pc.Peer)...).Debug("peer conn closed")
-	}
-	torrentCfg.Callbacks.CompletedHandshake = func(pc *torrent.PeerConn, ih infohash.T) {
-		attrs := append(peerAttrs(&pc.Peer), slog.String("infohash", ih.HexString()))
-		l.With(attrs...).Debug("completed handshake")
-	}
-	torrentCfg.Callbacks.ReceivedRequested = append(torrentCfg.Callbacks.ReceivedRequested, func(pme torrent.PeerMessageEvent) {
-		l.With(peerAttrs(pme.Peer)...).Debug("received requested")
-	})
-	torrentCfg.Callbacks.ReceivedUsefulData = append(torrentCfg.Callbacks.ReceivedUsefulData, func(pme torrent.PeerMessageEvent) {
-		l.With(peerAttrs(pme.Peer)...).Debug("received useful data")
-	})
-
-	return torrentCfg
-}
-
-var emptyBytes [20]byte
-
-func getOrCreatePeerID(p string) ([20]byte, error) {
-	idb, err := os.ReadFile(p)
-	if err == nil {
-		var out [20]byte
-		copy(out[:], idb)
-
-		return out, nil
-	}
-
-	if !os.IsNotExist(err) {
-		return emptyBytes, err
-	}
-
-	var out [20]byte
-	_, err = rand.Read(out[:])
-	if err != nil {
-		return emptyBytes, err
-	}
-
-	return out, os.WriteFile(p, out[:], 0755)
-}
-
-func peerAttrs(peer *torrent.Peer) []any {
-	out := []any{
-		slog.String("ip", peer.RemoteAddr.String()),
-		slog.String("discovery", string(peer.Discovery)),
-		slog.Int("max-requests", peer.PeerMaxRequests),
-		slog.Bool("prefers-encryption", peer.PeerPrefersEncryption),
-	}
-
-	if peer.Torrent() != nil {
-		out = append(out, slog.String("torrent", peer.Torrent().Name()))
-	}
-
-	return out
-}
diff --git a/daemons/atorrent/controller.go b/daemons/atorrent/controller.go
deleted file mode 100644
index 42a96f6..0000000
--- a/daemons/atorrent/controller.go
+++ /dev/null
@@ -1,265 +0,0 @@
-package atorrent
-
-import (
-	"context"
-	"log/slog"
-	"strings"
-
-	"git.kmsign.ru/royalcat/tstor/pkg/kvsingle"
-	"git.kmsign.ru/royalcat/tstor/pkg/rlog"
-	"github.com/anacrolix/torrent"
-	"github.com/anacrolix/torrent/types"
-	"github.com/royalcat/kv"
-)
-
-type TorrentFileDeleter interface {
-	DeleteFile(file *torrent.File) error
-}
-
-type FileProperties struct {
-	Excluded bool                `json:"excluded"`
-	Priority types.PiecePriority `json:"priority"`
-}
-
-type Controller struct {
-	torrentFilePath string
-	t               *torrent.Torrent
-	storage         TorrentFileDeleter
-	fileProperties  kv.Store[string, FileProperties]
-	log             *rlog.Logger
-}
-
-func newController(t *torrent.Torrent, torrentFileProperties kv.Store[string, FileProperties], storage TorrentFileDeleter, log *rlog.Logger) *Controller {
-	return &Controller{
-		t:              t,
-		storage:        storage,
-		fileProperties: torrentFileProperties,
-		log:            log.WithComponent("controller").With(slog.String("infohash", t.InfoHash().HexString())),
-	}
-}
-
-func (s *Controller) TorrentFilePath() string {
-	return s.torrentFilePath
-}
-
-func (s *Controller) Torrent() *torrent.Torrent {
-	return s.t
-}
-
-func (c *Controller) Name() string {
-	<-c.t.GotInfo()
-	if name := c.t.Name(); name != "" {
-		return name
-	}
-
-	return c.InfoHash()
-}
-
-func (s *Controller) InfoHash() string {
-	<-s.t.GotInfo()
-	return s.t.InfoHash().HexString()
-}
-
-func (s *Controller) BytesCompleted() int64 {
-	<-s.t.GotInfo()
-	return s.t.BytesCompleted()
-}
-
-func (s *Controller) BytesMissing() int64 {
-	<-s.t.GotInfo()
-	return s.t.BytesMissing()
-}
-
-func (s *Controller) Length() int64 {
-	<-s.t.GotInfo()
-	return s.t.Length()
-}
-
-func (s *Controller) Files(ctx context.Context) ([]*FileController, error) {
-	ctx, span := tracer.Start(ctx, "Files")
-	defer span.End()
-
-	fps := map[string]FileProperties{}
-	err := s.fileProperties.Range(ctx, func(k string, v FileProperties) error {
-		fps[k] = v
-		return nil
-	})
-	if err != nil {
-		return nil, err
-	}
-
-	select {
-	case <-ctx.Done():
-		return nil, ctx.Err()
-	case <-s.t.GotInfo():
-	}
-
-	files := make([]*FileController, 0)
-	for _, v := range s.t.Files() {
-		if strings.Contains(v.Path(), "/.pad/") {
-			continue
-		}
-
-		props := kvsingle.New(s.fileProperties, v.Path())
-		ctl := NewFileController(v, props, s.log)
-		files = append(files, ctl)
-	}
-
-	return files, nil
-}
-
-func (s *Controller) GetFile(ctx context.Context, file string) (*FileController, error) {
-	files, err := s.Files(ctx)
-	if err != nil {
-		return nil, err
-	}
-
-	for _, v := range files {
-		if v.Path() == file {
-			return v, nil
-		}
-	}
-
-	return nil, nil
-}
-
-func Map[T, U any](ts []T, f func(T) U) []U {
-	us := make([]U, len(ts))
-	for i := range ts {
-		us[i] = f(ts[i])
-	}
-	return us
-}
-
-func (s *Controller) ExcludeFile(ctx context.Context, f *torrent.File) error {
-	log := s.log.With(slog.String("file", f.Path()))
-	log.Info(ctx, "excluding file")
-
-	err := s.fileProperties.Edit(ctx, f.Path(), func(ctx context.Context, v FileProperties) (FileProperties, error) {
-		v.Excluded = true
-		return v, nil
-	})
-	if err == kv.ErrKeyNotFound {
-		err := s.fileProperties.Set(ctx, f.Path(), FileProperties{Excluded: true})
-		if err != nil {
-			return err
-		}
-	} else if err != nil {
-		return err
-	}
-
-	return s.storage.DeleteFile(f)
-}
-
-func (s *Controller) isFileComplete(startIndex int, endIndex int) bool {
-	for i := startIndex; i < endIndex; i++ {
-		if !s.t.Piece(i).State().Complete {
-			return false
-		}
-	}
-	return true
-}
-
-func (s *Controller) ValidateTorrent(ctx context.Context) error {
-	select {
-	case <-ctx.Done():
-		return ctx.Err()
-	case <-s.t.GotInfo():
-	}
-
-	for i := 0; i < s.t.NumPieces(); i++ {
-		if ctx.Err() != nil {
-			return ctx.Err()
-		}
-
-		s.t.Piece(i).VerifyData()
-	}
-
-	return nil
-}
-
-func (c *Controller) SetPriority(ctx context.Context, priority types.PiecePriority) error {
-	log := c.log.With(slog.Int("priority", int(priority)))
-	files, err := c.Files(ctx)
-	if err != nil {
-		return err
-	}
-	for _, f := range files {
-		excluded, err := f.Excluded(ctx)
-		if err != nil {
-			log.Error(ctx, "failed to get file exclusion status", rlog.Error(err))
-		}
-		if excluded {
-			continue
-		}
-
-		err = f.SetPriority(ctx, priority)
-		if err != nil {
-			log.Error(ctx, "failed to set file priority", rlog.Error(err))
-		}
-	}
-	return nil
-}
-
-const defaultPriority = types.PiecePriorityNone
-
-func (c *Controller) Priority(ctx context.Context) (types.PiecePriority, error) {
-	prio := defaultPriority
-	files, err := c.Files(ctx)
-	if err != nil {
-		return 0, err
-	}
-	for _, v := range files {
-		filePriority := v.Priority()
-		if filePriority > prio {
-			prio = filePriority
-		}
-	}
-
-	return prio, nil
-}
-
-// func (c *Controller) setFilePriority(ctx context.Context, file *torrent.File, priority types.PiecePriority) error {
-// 	err := c.fileProperties.Edit(ctx, file.Path(), func(ctx context.Context, v FileProperties) (FileProperties, error) {
-// 		v.Priority = priority
-// 		return v, nil
-// 	})
-
-// 	if err == kv.ErrKeyNotFound {
-// 		seterr := c.fileProperties.Set(ctx, file.Path(), FileProperties{Priority: priority})
-// 		if seterr != nil {
-// 			return seterr
-// 		}
-// 		err = nil
-// 	}
-
-// 	if err != nil {
-// 		return err
-// 	}
-// 	file.SetPriority(priority)
-// 	return nil
-// }
-
-func (c *Controller) initializeTorrentPriories(ctx context.Context) error {
-	ctx, span := tracer.Start(ctx, "initializeTorrentPriories")
-	defer span.End()
-	log := c.log
-
-	files, err := c.Files(ctx)
-	if err != nil {
-		return err
-	}
-
-	for _, file := range files {
-		props, err := file.Properties(ctx)
-		if err != nil {
-			log.Error(ctx, "failed to get file properties", rlog.Error(err))
-			continue
-		}
-		file.file.SetPriority(props.Priority)
-	}
-
-	log.Debug(ctx, "torrent initialization complete", slog.String("infohash", c.InfoHash()), slog.String("torrent_name", c.Name()))
-
-	return nil
-}
diff --git a/daemons/atorrent/daemon.go b/daemons/atorrent/daemon.go
deleted file mode 100644
index 97aa766..0000000
--- a/daemons/atorrent/daemon.go
+++ /dev/null
@@ -1,226 +0,0 @@
-package atorrent
-
-import (
-	"context"
-	"errors"
-	"fmt"
-	"os"
-	"path/filepath"
-	"sync"
-	"time"
-
-	"git.kmsign.ru/royalcat/tstor/pkg/rlog"
-	"git.kmsign.ru/royalcat/tstor/src/config"
-	"git.kmsign.ru/royalcat/tstor/src/tkv"
-	"git.kmsign.ru/royalcat/tstor/src/vfs"
-	"go.opentelemetry.io/otel"
-	"go.opentelemetry.io/otel/attribute"
-	"go.opentelemetry.io/otel/metric"
-	"go.opentelemetry.io/otel/trace"
-	"golang.org/x/exp/maps"
-
-	"github.com/anacrolix/torrent"
-	"github.com/anacrolix/torrent/bencode"
-	"github.com/anacrolix/torrent/metainfo"
-	"github.com/anacrolix/torrent/types/infohash"
-	"github.com/go-git/go-billy/v5"
-	"github.com/royalcat/kv"
-)
-
-const instrument = "git.kmsign.ru/royalcat/tstor/daemons/atorrent"
-
-var (
-	tracer = otel.Tracer(instrument, trace.WithInstrumentationAttributes(attribute.String("component", "torrent-daemon")))
-	meter  = otel.Meter(instrument, metric.WithInstrumentationAttributes(attribute.String("component", "torrent-daemon")))
-)
-
-type DirAquire struct {
-	Name   string
-	Hashes []infohash.T
-}
-
-type Daemon struct {
-	client         *torrent.Client
-	infoBytes      *infoBytesStore
-	Storage        *fileStorage
-	fis            *dhtFileItemStore
-	dirsAquire     kv.Store[string, DirAquire]
-	fileProperties kv.Store[string, FileProperties]
-	statsStore     *statsStore
-
-	loadMutex sync.Mutex
-
-	sourceFs billy.Filesystem
-
-	log *rlog.Logger
-}
-
-const dhtTTL = 180 * 24 * time.Hour
-
-func NewDaemon(sourceFs billy.Filesystem, conf config.TorrentClient) (*Daemon, error) {
-	s := &Daemon{
-		log:       rlog.Component("torrent-service"),
-		sourceFs:  sourceFs,
-		loadMutex: sync.Mutex{},
-	}
-
-	err := os.MkdirAll(conf.MetadataFolder, 0744)
-	if err != nil {
-		return nil, fmt.Errorf("error creating metadata folder: %w", err)
-	}
-
-	s.fis, err = newDHTStore(filepath.Join(conf.MetadataFolder, "dht-item-store"), dhtTTL)
-	if err != nil {
-		return nil, fmt.Errorf("error starting item store: %w", err)
-	}
-
-	s.Storage, _, err = setupStorage(conf)
-	if err != nil {
-		return nil, err
-	}
-
-	s.fileProperties, err = tkv.NewKV[string, FileProperties](conf.MetadataFolder, "file-properties")
-	if err != nil {
-		return nil, err
-	}
-
-	s.infoBytes, err = newInfoBytesStore(conf.MetadataFolder)
-	if err != nil {
-		return nil, err
-	}
-
-	id, err := getOrCreatePeerID(filepath.Join(conf.MetadataFolder, "ID"))
-	if err != nil {
-		return nil, fmt.Errorf("error creating node ID: %w", err)
-	}
-
-	s.statsStore, err = newStatsStore(conf.MetadataFolder, time.Hour*24*30)
-	if err != nil {
-		return nil, err
-	}
-
-	clientConfig := newClientConfig(s.Storage, s.fis, &conf, id)
-	s.client, err = torrent.NewClient(clientConfig)
-	if err != nil {
-		return nil, err
-	}
-
-	// TODO move to config
-	s.client.AddDhtNodes([]string{
-		"router.bittorrent.com:6881",
-		"router.utorrent.com:6881",
-		"dht.transmissionbt.com:6881",
-		"router.bitcomet.com:6881",
-		"dht.aelitis.com6881",
-	})
-
-	s.client.AddDhtNodes(conf.DHTNodes)
-
-	s.dirsAquire, err = tkv.NewKV[string, DirAquire](conf.MetadataFolder, "dir-acquire")
-	if err != nil {
-		return nil, err
-	}
-
-	// go func() {
-	// 	ctx := context.Background()
-	// 	err := s.backgroudFileLoad(ctx)
-	// 	if err != nil {
-	// 		s.log.Error(ctx, "initial torrent load failed", rlog.Error(err))
-	// 	}
-	// }()
-
-	go func() {
-		ctx := context.Background()
-		const period = time.Second * 10
-
-		err := registerTorrentMetrics(s.client)
-		if err != nil {
-			s.log.Error(ctx, "error registering torrent metrics", rlog.Error(err))
-		}
-		err = registerDhtMetrics(s.client)
-		if err != nil {
-			s.log.Error(ctx, "error registering dht metrics", rlog.Error(err))
-		}
-
-		timer := time.NewTicker(period)
-		for {
-			select {
-			case <-s.client.Closed():
-				return
-			case <-timer.C:
-				s.updateStats(ctx)
-			}
-		}
-	}()
-
-	return s, nil
-}
-
-var _ vfs.FsFactory = (*Daemon)(nil).NewTorrentFs
-
-func (s *Daemon) Close(ctx context.Context) error {
-	return errors.Join(append(
-		s.client.Close(),
-		s.Storage.Close(),
-		s.dirsAquire.Close(ctx),
-		// s.excludedFiles.Close(ctx),
-		s.infoBytes.Close(),
-		s.fis.Close(),
-	)...)
-}
-
-func isValidInfoHashBytes(d []byte) bool {
-	var info metainfo.Info
-	err := bencode.Unmarshal(d, &info)
-	return err == nil
-}
-
-func (s *Daemon) Stats() torrent.ConnStats {
-	return s.client.Stats().ConnStats
-}
-
-func storeByTorrent[K kv.Bytes, V any](s kv.Store[K, V], infohash infohash.T) kv.Store[K, V] {
-	return kv.PrefixBytes[K, V](s, K(infohash.HexString()+"/"))
-}
-
-func (s *Daemon) newController(t *torrent.Torrent) *Controller {
-	return newController(t,
-		storeByTorrent(s.fileProperties, t.InfoHash()),
-		s.Storage,
-		s.log,
-	)
-}
-
-func (s *Daemon) ListTorrents(ctx context.Context) ([]*Controller, error) {
-	out := []*Controller{}
-	for _, v := range s.client.Torrents() {
-		out = append(out, s.newController(v))
-	}
-	return out, nil
-}
-
-func (s *Daemon) GetTorrent(infohashHex string) (*Controller, error) {
-	t, ok := s.client.Torrent(infohash.FromHexString(infohashHex))
-	if !ok {
-		return nil, nil
-	}
-
-	return s.newController(t), nil
-}
-
-func slicesUnique[S ~[]E, E comparable](in S) S {
-	m := map[E]struct{}{}
-	for _, v := range in {
-		m[v] = struct{}{}
-	}
-
-	return maps.Keys(m)
-}
-
-func apply[I, O any](in []I, f func(e I) O) []O {
-	out := []O{}
-	for _, v := range in {
-		out = append(out, f(v))
-	}
-	return out
-}
diff --git a/daemons/atorrent/daemon_load.go b/daemons/atorrent/daemon_load.go
deleted file mode 100644
index 915ed64..0000000
--- a/daemons/atorrent/daemon_load.go
+++ /dev/null
@@ -1,246 +0,0 @@
-package atorrent
-
-import (
-	"bufio"
-	"context"
-	"fmt"
-	"io"
-	"log/slog"
-	"os"
-	"strings"
-	"sync"
-	"time"
-
-	"git.kmsign.ru/royalcat/tstor/pkg/ctxbilly"
-	"git.kmsign.ru/royalcat/tstor/pkg/rlog"
-	"git.kmsign.ru/royalcat/tstor/src/vfs"
-	"github.com/anacrolix/torrent"
-	"github.com/anacrolix/torrent/metainfo"
-	"github.com/go-git/go-billy/v5/util"
-	"github.com/royalcat/ctxio"
-	"go.opentelemetry.io/otel/attribute"
-	"go.opentelemetry.io/otel/trace"
-)
-
-const activityTimeout = time.Minute * 15
-
-func readInfoHash(ctx context.Context, f vfs.File) (metainfo.Hash, error) {
-	ctx, span := tracer.Start(ctx, "readInfoHash")
-	defer span.End()
-
-	mi, err := metainfo.Load(ctxio.IoReader(ctx, f))
-	if err != nil {
-		return metainfo.Hash{}, fmt.Errorf("loading metainfo: %w", err)
-	}
-
-	return mi.HashInfoBytes(), nil
-}
-
-func (s *Daemon) loadTorrent(ctx context.Context, f vfs.File) (*Controller, error) {
-	ctx, span := tracer.Start(ctx, "loadTorrent")
-	defer span.End()
-	log := s.log
-
-	stat, err := f.Info()
-	if err != nil {
-		return nil, fmt.Errorf("call stat failed: %w", err)
-	}
-
-	span.SetAttributes(attribute.String("filename", stat.Name()))
-
-	mi, err := metainfo.Load(bufio.NewReader(ctxio.IoReader(ctx, f)))
-	if err != nil {
-		return nil, fmt.Errorf("loading torrent metadata from file %s, error: %w", stat.Name(), err)
-	}
-	log = log.With(slog.String("info-hash", mi.HashInfoBytes().HexString()))
-
-	var ctl *Controller
-	t, ok := s.client.Torrent(mi.HashInfoBytes())
-	if ok {
-		log = log.With(slog.String("torrent-name", t.Name()))
-		ctl = s.newController(t)
-	} else {
-		span.AddEvent("torrent not found, loading from file")
-		log.Info(ctx, "torrent not found, loading from file")
-
-		spec, err := torrent.TorrentSpecFromMetaInfoErr(mi)
-		if err != nil {
-			return nil, fmt.Errorf("parse spec from metadata: %w", err)
-		}
-		infoBytes := spec.InfoBytes
-
-		if !isValidInfoHashBytes(infoBytes) {
-			log.Warn(ctx, "info loaded from spec not valid")
-			infoBytes = nil
-		}
-
-		if len(infoBytes) == 0 {
-			log.Info(ctx, "no info loaded from file, try to load from cache")
-			infoBytes, err = s.infoBytes.GetBytes(spec.InfoHash)
-			if err != nil && err != errNotFound {
-				return nil, fmt.Errorf("get info bytes from database: %w", err)
-			}
-		}
-
-		t, _ = s.client.AddTorrentOpt(torrent.AddTorrentOpts{
-			InfoHash:   spec.InfoHash,
-			InfoHashV2: spec.InfoHashV2,
-			Storage:    s.Storage,
-			InfoBytes:  infoBytes,
-			ChunkSize:  spec.ChunkSize,
-		})
-
-		log = log.With(slog.String("torrent-name", t.Name()))
-
-		t.AllowDataDownload()
-		t.AllowDataUpload()
-
-		span.AddEvent("torrent added to client")
-
-		select {
-		case <-ctx.Done():
-			return nil, ctx.Err()
-		case <-t.GotInfo():
-			err := s.infoBytes.Set(t.InfoHash(), t.Metainfo())
-			if err != nil {
-				log.Error(ctx, "error setting info bytes for torrent",
-					slog.String("torrent-name", t.Name()),
-					rlog.Error(err),
-				)
-			}
-		}
-		span.AddEvent("got info")
-
-		ctl = s.newController(t)
-
-		err = ctl.initializeTorrentPriories(ctx)
-		if err != nil {
-			return nil, fmt.Errorf("initialize torrent priorities: %w", err)
-		}
-
-		// go func() {
-		// 	subscr := ctl.t.SubscribePieceStateChanges()
-		// 	defer subscr.Close()
-		// 	dropTimer := time.NewTimer(activityTimeout)
-		// 	defer dropTimer.Stop()
-
-		// 	for {
-		// 		select {
-		// 		case <-subscr.Values:
-		// 			dropTimer.Reset(activityTimeout)
-		// 		case <-dropTimer.C:
-		// 			log.Info(ctx, "torrent dropped by activity timeout")
-		// 			select {
-		// 			case <-ctl.t.Closed():
-		// 				return
-		// 			case <-time.After(time.Second):
-		// 				ctl.t.Drop()
-		// 			}
-		// 		case <-ctl.t.Closed():
-		// 			return
-		// 		}
-		// 	}
-		// }()
-	}
-
-	return ctl, nil
-}
-
-const loadWorkers = 5
-
-func (s *Daemon) backgroudFileLoad(ctx context.Context) error {
-	ctx, span := tracer.Start(ctx, "loadTorrentFiles", trace.WithAttributes(
-		attribute.Int("workers", loadWorkers),
-	))
-	defer span.End()
-	log := s.log
-
-	loaderPaths := make(chan string, loadWorkers*5)
-	wg := sync.WaitGroup{}
-
-	defer func() {
-		close(loaderPaths)
-		wg.Wait()
-	}()
-
-	loaderWorker := func() {
-		for path := range loaderPaths {
-			info, err := s.sourceFs.Stat(path)
-			if err != nil {
-				log.Error(ctx, "error stat torrent file", slog.String("filename", path), rlog.Error(err))
-				continue
-			}
-
-			file, err := s.sourceFs.Open(path)
-			if err != nil {
-				log.Error(ctx, "error opening torrent file", slog.String("filename", path), rlog.Error(err))
-				continue
-			}
-			defer file.Close()
-
-			vfile := vfs.NewCtxBillyFile(info, ctxbilly.WrapFile(file))
-
-			ih, err := readInfoHash(ctx, vfile)
-			if err != nil {
-				log.Error(ctx, "error reading info hash", slog.String("filename", path), rlog.Error(err))
-				continue
-			}
-			props := storeByTorrent(s.fileProperties, ih)
-			_, err = vfile.Seek(0, io.SeekStart)
-			if err != nil {
-				log.Error(ctx, "error seeking file", slog.String("filename", path), rlog.Error(err))
-				continue
-			}
-
-			isPrioritized := false
-			err = props.Range(ctx, func(k string, v FileProperties) error {
-				if v.Priority > 0 {
-					isPrioritized = true
-					return io.EOF
-				}
-				return nil
-			})
-			if err != nil && err != io.EOF {
-				log.Error(ctx, "error checking file priority", slog.String("filename", path), rlog.Error(err))
-				continue
-			}
-
-			if !isPrioritized {
-				log.Debug(ctx, "file not prioritized, skipping", slog.String("filename", path))
-				continue
-			}
-
-			_, err = s.loadTorrent(ctx, vfile)
-			if err != nil {
-				log.Error(ctx, "failed adding torrent", rlog.Error(err))
-			}
-		}
-
-		wg.Done()
-	}
-
-	wg.Add(loadWorkers)
-	for range loadWorkers {
-		go loaderWorker()
-	}
-
-	return util.Walk(s.sourceFs, "", func(path string, info os.FileInfo, err error) error {
-		if err != nil {
-			return fmt.Errorf("fs walk error: %w", err)
-		}
-
-		if ctx.Err() != nil {
-			return ctx.Err()
-		}
-
-		if info.IsDir() {
-			return nil
-		}
-
-		if strings.HasSuffix(path, ".torrent") {
-			loaderPaths <- path
-		}
-
-		return nil
-	})
-}
diff --git a/daemons/atorrent/daemon_stats.go b/daemons/atorrent/daemon_stats.go
deleted file mode 100644
index 3693b02..0000000
--- a/daemons/atorrent/daemon_stats.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package atorrent
-
-import (
-	"context"
-	"time"
-
-	"git.kmsign.ru/royalcat/tstor/pkg/rlog"
-	"github.com/anacrolix/torrent/types/infohash"
-)
-
-func (s *Daemon) allStats(ctx context.Context) (map[infohash.T]TorrentStats, TorrentStats) {
-	totalPeers := 0
-	activePeers := 0
-	connectedSeeders := 0
-
-	perTorrentStats := map[infohash.T]TorrentStats{}
-
-	for _, v := range s.client.Torrents() {
-		stats := v.Stats()
-		perTorrentStats[v.InfoHash()] = TorrentStats{
-			Timestamp:        time.Now(),
-			DownloadedBytes:  uint64(stats.BytesRead.Int64()),
-			UploadedBytes:    uint64(stats.BytesWritten.Int64()),
-			TotalPeers:       uint16(stats.TotalPeers),
-			ActivePeers:      uint16(stats.ActivePeers),
-			ConnectedSeeders: uint16(stats.ConnectedSeeders),
-		}
-
-		totalPeers += stats.TotalPeers
-		activePeers += stats.ActivePeers
-		connectedSeeders += stats.ConnectedSeeders
-	}
-
-	totalStats := s.client.Stats()
-
-	return perTorrentStats, TorrentStats{
-		Timestamp:        time.Now(),
-		DownloadedBytes:  uint64(totalStats.BytesRead.Int64()),
-		UploadedBytes:    uint64(totalStats.BytesWritten.Int64()),
-		TotalPeers:       uint16(totalPeers),
-		ActivePeers:      uint16(activePeers),
-		ConnectedSeeders: uint16(connectedSeeders),
-	}
-}
-
-func (s *Daemon) updateStats(ctx context.Context) {
-	log := s.log
-
-	perTorrentStats, totalStats := s.allStats(ctx)
-	for ih, v := range perTorrentStats {
-		err := s.statsStore.AddTorrentStats(ih, v)
-		if err != nil {
-			log.Error(ctx, "error saving torrent stats", rlog.Error(err))
-		}
-	}
-
-	err := s.statsStore.AddTotalStats(totalStats)
-	if err != nil {
-		log.Error(ctx, "error saving total stats", rlog.Error(err))
-	}
-}
-
-func (s *Daemon) TotalStatsHistory(ctx context.Context, since time.Time) ([]TorrentStats, error) {
-	return s.statsStore.ReadTotalStatsHistory(ctx, since)
-}
-
-func (s *Daemon) TorrentStatsHistory(ctx context.Context, since time.Time, ih infohash.T) ([]TorrentStats, error) {
-	return s.statsStore.ReadTorrentStatsHistory(ctx, since, ih)
-}
-
-func (s *Daemon) StatsHistory(ctx context.Context, since time.Time) ([]TorrentStats, error) {
-	return s.statsStore.ReadStatsHistory(ctx, since)
-}
diff --git a/daemons/atorrent/delivery/graphql/fs.resolvers.go b/daemons/atorrent/delivery/graphql/fs.resolvers.go
deleted file mode 100644
index 99516d8..0000000
--- a/daemons/atorrent/delivery/graphql/fs.resolvers.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package graphql
-
-import (
-	"context"
-
-	"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
-)
-
-func (r *torrentFSResolver) Entries(ctx context.Context, obj *model.TorrentFs) ([]model.FsEntry, error) {
-	// entries, err := obj.FS.ReadDir(ctx, ".")
-	// if err != nil {
-	// 	return nil, err
-	// }
-	out := []model.FsEntry{}
-	// for _, e := range entries {
-	// 	entry, err := model.FillFsEntry(ctx, e, obj.FS, ".")
-	// 	if err != nil {
-	// 		return nil, err
-	// 	}
-	// 	out = append(out, entry)
-	// }
-	return out, nil
-}
-
-type torrentFSResolver struct{ *Resolver }
diff --git a/daemons/atorrent/delivery/graphql/mappers.go b/daemons/atorrent/delivery/graphql/mappers.go
deleted file mode 100644
index 00c2fcf..0000000
--- a/daemons/atorrent/delivery/graphql/mappers.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package graphql
-
-import (
-	"context"
-
-	"git.kmsign.ru/royalcat/tstor/daemons/atorrent"
-	"github.com/anacrolix/torrent"
-)
-
-func MapPeerSource(source torrent.PeerSource) string {
-	switch source {
-	case torrent.PeerSourceDirect:
-		return "Direct"
-	case torrent.PeerSourceUtHolepunch:
-		return "Ut Holepunch"
-	case torrent.PeerSourceDhtAnnouncePeer:
-		return "DHT Announce"
-	case torrent.PeerSourceDhtGetPeers:
-		return "DHT"
-	case torrent.PeerSourceIncoming:
-		return "Incoming"
-	case torrent.PeerSourceTracker:
-		return "Tracker"
-	case torrent.PeerSourcePex:
-		return "PEX"
-	default:
-		return "Unknown"
-	}
-}
-
-func MapTorrent(ctx context.Context, t *atorrent.Controller) (*Torrent, error) {
-	prio, err := t.Priority(ctx)
-	if err != nil {
-		return nil, err
-	}
-
-	return &Torrent{
-		Infohash:       t.InfoHash(),
-		Name:           t.Name(),
-		BytesCompleted: t.BytesCompleted(),
-		BytesMissing:   t.BytesMissing(),
-		Priority:       prio,
-		T:              t,
-	}, nil
-}
-
-func MapTorrentStats(s atorrent.TorrentStats) *TorrentStats {
-	return &TorrentStats{
-		Timestamp:        s.Timestamp,
-		DownloadedBytes:  uint(s.DownloadedBytes),
-		UploadedBytes:    uint(s.UploadedBytes),
-		TotalPeers:       uint(s.TotalPeers),
-		ActivePeers:      uint(s.ActivePeers),
-		ConnectedSeeders: uint(s.ConnectedSeeders),
-	}
-}
diff --git a/daemons/atorrent/delivery/graphql/models_gen.go b/daemons/atorrent/delivery/graphql/models_gen.go
deleted file mode 100644
index 856fa11..0000000
--- a/daemons/atorrent/delivery/graphql/models_gen.go
+++ /dev/null
@@ -1,140 +0,0 @@
-// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
-
-package graphql
-
-import (
-	"time"
-
-	"git.kmsign.ru/royalcat/tstor/daemons/atorrent"
-	"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
-	"github.com/anacrolix/torrent"
-	"github.com/anacrolix/torrent/types"
-)
-
-type CleanupResponse struct {
-	Count int64    `json:"count"`
-	List  []string `json:"list"`
-}
-
-type DownloadTorrentResponse struct {
-	TaskID string `json:"taskID"`
-}
-
-type Torrent struct {
-	Name            string               `json:"name"`
-	Infohash        string               `json:"infohash"`
-	BytesCompleted  int64                `json:"bytesCompleted"`
-	TorrentFilePath string               `json:"torrentFilePath"`
-	BytesMissing    int64                `json:"bytesMissing"`
-	Priority        types.PiecePriority  `json:"priority"`
-	Files           []*TorrentFile       `json:"files"`
-	ExcludedFiles   []*TorrentFile       `json:"excludedFiles"`
-	Peers           []*TorrentPeer       `json:"peers"`
-	T               *atorrent.Controller `json:"-"`
-}
-
-type TorrentClientStats struct {
-	BytesWritten                int64 `json:"bytesWritten"`
-	BytesWrittenData            int64 `json:"bytesWrittenData"`
-	BytesRead                   int64 `json:"bytesRead"`
-	BytesReadData               int64 `json:"bytesReadData"`
-	BytesReadUsefulData         int64 `json:"bytesReadUsefulData"`
-	BytesReadUsefulIntendedData int64 `json:"bytesReadUsefulIntendedData"`
-	ChunksWritten               int64 `json:"chunksWritten"`
-	ChunksRead                  int64 `json:"chunksRead"`
-	ChunksReadUseful            int64 `json:"chunksReadUseful"`
-	ChunksReadWasted            int64 `json:"chunksReadWasted"`
-	MetadataChunksRead          int64 `json:"metadataChunksRead"`
-	PiecesDirtiedGood           int64 `json:"piecesDirtiedGood"`
-	PiecesDirtiedBad            int64 `json:"piecesDirtiedBad"`
-}
-
-type TorrentDaemonMutation struct {
-	ValidateTorrent    bool             `json:"validateTorrent"`
-	SetTorrentPriority bool             `json:"setTorrentPriority"`
-	Cleanup            *CleanupResponse `json:"cleanup"`
-}
-
-type TorrentDaemonQuery struct {
-	Torrents     []*Torrent          `json:"torrents"`
-	ClientStats  *TorrentClientStats `json:"clientStats"`
-	StatsHistory []*TorrentStats     `json:"statsHistory"`
-}
-
-type TorrentFs struct {
-	Name    string              `json:"name"`
-	Torrent *Torrent            `json:"torrent"`
-	Entries []model.FsEntry     `json:"entries"`
-	FS      *atorrent.TorrentFS `json:"-"`
-}
-
-func (TorrentFs) IsDir() {}
-
-func (TorrentFs) IsFsEntry() {}
-
-type TorrentFile struct {
-	Filename       string                   `json:"filename"`
-	Size           int64                    `json:"size"`
-	BytesCompleted int64                    `json:"bytesCompleted"`
-	Priority       types.PiecePriority      `json:"priority"`
-	F              *atorrent.FileController `json:"-"`
-}
-
-type TorrentFileEntry struct {
-	Name    string   `json:"name"`
-	Torrent *Torrent `json:"torrent"`
-	Size    int64    `json:"size"`
-}
-
-func (TorrentFileEntry) IsFile() {}
-
-func (TorrentFileEntry) IsFsEntry() {}
-
-type TorrentFilter struct {
-	Everything *bool   `json:"everything,omitempty"`
-	Infohash   *string `json:"infohash,omitempty"`
-}
-
-type TorrentPeer struct {
-	IP           string            `json:"ip"`
-	DownloadRate float64           `json:"downloadRate"`
-	Discovery    string            `json:"discovery"`
-	Port         int64             `json:"port"`
-	ClientName   string            `json:"clientName"`
-	F            *torrent.PeerConn `json:"-"`
-}
-
-type TorrentPriorityFilter struct {
-	Eq  *types.PiecePriority  `json:"eq,omitempty"`
-	Gt  *types.PiecePriority  `json:"gt,omitempty"`
-	Lt  *types.PiecePriority  `json:"lt,omitempty"`
-	Gte *types.PiecePriority  `json:"gte,omitempty"`
-	Lte *types.PiecePriority  `json:"lte,omitempty"`
-	In  []types.PiecePriority `json:"in,omitempty"`
-}
-
-type TorrentProgress struct {
-	Torrent *Torrent `json:"torrent"`
-	Current int64    `json:"current"`
-	Total   int64    `json:"total"`
-}
-
-func (TorrentProgress) IsProgress() {}
-
-type TorrentStats struct {
-	Timestamp        time.Time `json:"timestamp"`
-	DownloadedBytes  uint      `json:"downloadedBytes"`
-	UploadedBytes    uint      `json:"uploadedBytes"`
-	TotalPeers       uint      `json:"totalPeers"`
-	ActivePeers      uint      `json:"activePeers"`
-	ConnectedSeeders uint      `json:"connectedSeeders"`
-}
-
-type TorrentsFilter struct {
-	Infohash       *model.StringFilter    `json:"infohash,omitempty"`
-	Name           *model.StringFilter    `json:"name,omitempty"`
-	BytesCompleted *model.IntFilter       `json:"bytesCompleted,omitempty"`
-	BytesMissing   *model.IntFilter       `json:"bytesMissing,omitempty"`
-	PeersCount     *model.IntFilter       `json:"peersCount,omitempty"`
-	Priority       *TorrentPriorityFilter `json:"priority,omitempty"`
-}
diff --git a/daemons/atorrent/delivery/graphql/resolver.go b/daemons/atorrent/delivery/graphql/resolver.go
deleted file mode 100644
index b6b4487..0000000
--- a/daemons/atorrent/delivery/graphql/resolver.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package graphql
-
-import (
-	"git.kmsign.ru/royalcat/tstor/daemons/atorrent"
-	"git.kmsign.ru/royalcat/tstor/src/vfs"
-	"github.com/go-git/go-billy/v5"
-)
-
-// This file will not be regenerated automatically.
-//
-// It serves as dependency injection for your app, add any dependencies you require here.
-
-type Resolver struct {
-	ATorrentDaemon *atorrent.Daemon
-	VFS            vfs.Filesystem
-	SourceFS       billy.Filesystem
-}
diff --git a/daemons/atorrent/delivery/graphql/subscription.resolvers.go b/daemons/atorrent/delivery/graphql/subscription.resolvers.go
deleted file mode 100644
index f1fc6b9..0000000
--- a/daemons/atorrent/delivery/graphql/subscription.resolvers.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package graphql
-
-// This file will be automatically regenerated based on the schema, any resolver implementations
-// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.55
-
-import (
-	"context"
-	"fmt"
-)
-
-type subscriptionResolver struct{ *Resolver }
-
-func (r *subscriptionResolver) TorrentDownloadUpdates(ctx context.Context) (<-chan *TorrentProgress, error) {
-	out := make(chan *TorrentProgress)
-	progress, err := r.ATorrentDaemon.DownloadProgress(ctx)
-	if err != nil {
-		return nil, err
-	}
-
-	go func() {
-		defer close(out)
-		for p := range progress {
-			if p.Torrent == nil {
-				fmt.Println("nil torrent")
-				continue
-			}
-			torrent, err := MapTorrent(ctx, p.Torrent)
-			if err != nil {
-				// TODO logs
-				continue
-			}
-			po := &TorrentProgress{
-				Torrent: torrent,
-				Current: p.Current,
-				Total:   p.Total,
-			}
-			select {
-			case <-ctx.Done():
-				return
-			case out <- po:
-			}
-		}
-	}()
-
-	return out, nil
-}
diff --git a/daemons/atorrent/delivery/graphql/torrent_mutation.resolvers.go b/daemons/atorrent/delivery/graphql/torrent_mutation.resolvers.go
deleted file mode 100644
index f45fc86..0000000
--- a/daemons/atorrent/delivery/graphql/torrent_mutation.resolvers.go
+++ /dev/null
@@ -1,102 +0,0 @@
-package graphql
-
-// This file will be automatically regenerated based on the schema, any resolver implementations
-// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.55
-
-import (
-	"context"
-
-	graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
-	"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
-	"github.com/anacrolix/torrent/types"
-)
-
-// ValidateTorrent is the resolver for the validateTorrent field.
-func (r *torrentDaemonMutationResolver) ValidateTorrent(ctx context.Context, obj *model.TorrentDaemonMutation, filter model.TorrentFilter) (bool, error) {
-	if filter.Infohash != nil {
-		t, err := r.Resolver.ATorrentDaemon.GetTorrent(*filter.Infohash)
-		if err != nil {
-			return false, err
-		}
-		if t == nil {
-			return false, nil
-		}
-
-		t.ValidateTorrent(ctx)
-		return true, nil
-	}
-
-	if filter.Everything != nil && *filter.Everything {
-		torrents, err := r.Resolver.ATorrentDaemon.ListTorrents(ctx)
-		if err != nil {
-			return false, err
-		}
-		for _, v := range torrents {
-			if err := v.ValidateTorrent(ctx); err != nil {
-				return false, err
-			}
-		}
-		return true, nil
-	}
-
-	return false, nil
-}
-
-// SetTorrentPriority is the resolver for the setTorrentPriority field.
-func (r *torrentDaemonMutationResolver) SetTorrentPriority(ctx context.Context, obj *model.TorrentDaemonMutation, infohash string, file *string, priority types.PiecePriority) (bool, error) {
-	t, err := r.Resolver.ATorrentDaemon.GetTorrent(infohash)
-	if err != nil {
-		return false, err
-	}
-	if t == nil {
-		return false, nil
-	}
-
-	if file == nil {
-		err = t.SetPriority(ctx, priority)
-		if err != nil {
-			return false, err
-		}
-		return true, nil
-	}
-
-	f, err := t.GetFile(ctx, *file)
-	if err != nil {
-		return false, err
-	}
-	err = f.SetPriority(ctx, priority)
-	if err != nil {
-		return false, err
-	}
-	return true, nil
-}
-
-// Cleanup is the resolver for the cleanup field.
-func (r *torrentDaemonMutationResolver) Cleanup(ctx context.Context, obj *model.TorrentDaemonMutation, files *bool, dryRun bool) (*model.CleanupResponse, error) {
-	torrents, err := r.ATorrentDaemon.ListTorrents(ctx)
-	if err != nil {
-		return nil, err
-	}
-
-	if files != nil && *files {
-		r, err := r.ATorrentDaemon.Storage.CleanupFiles(ctx, torrents, dryRun)
-		return &model.CleanupResponse{
-			Count: int64(len(r)),
-			List:  r,
-		}, err
-	} else {
-		r, err := r.ATorrentDaemon.Storage.CleanupDirs(ctx, torrents, dryRun)
-		return &model.CleanupResponse{
-			Count: int64(len(r)),
-			List:  r,
-		}, err
-	}
-}
-
-// TorrentDaemonMutation returns graph.TorrentDaemonMutationResolver implementation.
-func (r *Resolver) TorrentDaemonMutation() graph.TorrentDaemonMutationResolver {
-	return &torrentDaemonMutationResolver{r}
-}
-
-type torrentDaemonMutationResolver struct{ *Resolver }
diff --git a/daemons/atorrent/delivery/graphql/torrent_query.resolvers.go b/daemons/atorrent/delivery/graphql/torrent_query.resolvers.go
deleted file mode 100644
index da4c2b6..0000000
--- a/daemons/atorrent/delivery/graphql/torrent_query.resolvers.go
+++ /dev/null
@@ -1,142 +0,0 @@
-package graphql
-
-// This file will be automatically regenerated based on the schema, any resolver implementations
-// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.55
-
-import (
-	"context"
-	"time"
-
-	graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
-	"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
-)
-
-// Torrents is the resolver for the torrents field.
-func (r *torrentDaemonQueryResolver) Torrents(ctx context.Context, obj *model.TorrentDaemonQuery, filter *model.TorrentsFilter) ([]*model.Torrent, error) {
-	// torrents, err := r.ATorrentDaemon.ListTorrents(ctx)
-	// if err != nil {
-	// 	return nil, err
-	// }
-
-	// filterFuncs := []func(torrent *model.Torrent) bool{}
-
-	// if filter != nil {
-	// 	if filter.BytesCompleted != nil {
-	// 		filterFuncs = append(filterFuncs, func(torrent *model.Torrent) bool {
-	// 			return filter.BytesCompleted.Include(torrent.BytesCompleted)
-	// 		})
-	// 	}
-	// 	if filter.BytesMissing != nil {
-	// 		filterFuncs = append(filterFuncs, func(torrent *model.Torrent) bool {
-	// 			return filter.BytesMissing.Include(torrent.BytesMissing)
-	// 		})
-	// 	}
-	// 	if filter.PeersCount != nil {
-	// 		filterFuncs = append(filterFuncs, func(torrent *model.Torrent) bool {
-	// 			return filter.PeersCount.Include(
-	// 				int64(len(torrent.T.Torrent().PeerConns())),
-	// 			)
-	// 		})
-	// 	}
-	// 	if filter.Infohash != nil {
-	// 		filterFuncs = append(filterFuncs, func(torrent *model.Torrent) bool {
-	// 			return filter.Infohash.Include(
-	// 				torrent.Infohash,
-	// 			)
-	// 		})
-	// 	}
-	// 	if filter.Priority != nil {
-	// 		filterFuncs = append(filterFuncs, func(torrent *model.Torrent) bool {
-	// 			return filter.Priority.Include(
-	// 				torrent.Priority,
-	// 			)
-	// 		})
-	// 	}
-	// }
-
-	// filterFunc := func(torrent *model.Torrent) bool {
-	// 	for _, f := range filterFuncs {
-	// 		if !f(torrent) {
-	// 			return false
-	// 		}
-	// 	}
-	// 	return true
-	// }
-
-	// tr := []*model.Torrent{}
-	// for _, t := range torrents {
-	// 	d, err := model.MapTorrent(ctx, t)
-	// 	if err != nil {
-	// 		return nil, err
-	// 	}
-
-	// 	if !filterFunc(d) {
-	// 		continue
-	// 	}
-	// 	tr = append(tr, d)
-	// }
-
-	// slices.SortStableFunc(torrents, func(t1, t2 *torrent.Controller) int {
-	// 	return strings.Compare(t1.Name(), t2.Name())
-	// })
-
-	// return tr, nil
-	panic("not implemented")
-}
-
-// ClientStats is the resolver for the clientStats field.
-func (r *torrentDaemonQueryResolver) ClientStats(ctx context.Context, obj *model.TorrentDaemonQuery) (*model.TorrentClientStats, error) {
-	// stats := r.ATorrentDaemon.Stats()
-	// return &model.TorrentClientStats{
-	// 	BytesWritten:                stats.BytesWritten.Int64(),
-	// 	BytesRead:                   stats.BytesRead.Int64(),
-	// 	BytesWrittenData:            stats.BytesWrittenData.Int64(),
-	// 	BytesReadData:               stats.BytesReadData.Int64(),
-	// 	BytesReadUsefulData:         stats.BytesReadUsefulData.Int64(),
-	// 	BytesReadUsefulIntendedData: stats.BytesReadUsefulIntendedData.Int64(),
-	// 	ChunksWritten:               stats.ChunksWritten.Int64(),
-	// 	ChunksRead:                  stats.ChunksRead.Int64(),
-	// 	ChunksReadUseful:            stats.ChunksReadUseful.Int64(),
-	// 	ChunksReadWasted:            stats.ChunksReadWasted.Int64(),
-	// 	MetadataChunksRead:          stats.MetadataChunksRead.Int64(),
-	// 	PiecesDirtiedGood:           stats.PiecesDirtiedGood.Int64(),
-	// 	PiecesDirtiedBad:            stats.PiecesDirtiedBad.Int64(),
-	// }, nil
-	panic("not implemented")
-}
-
-// StatsHistory is the resolver for the statsHistory field.
-func (r *torrentDaemonQueryResolver) StatsHistory(ctx context.Context, obj *model.TorrentDaemonQuery, since time.Time, infohash *string) ([]*model.TorrentStats, error) {
-	// var stats []torrent.TorrentStats
-	// if infohash == nil {
-	// 	stats, err := r.ATorrentDaemon.StatsHistory(ctx, since)
-	// 	if err != nil {
-	// 		return nil, err
-	// 	}
-	// 	return model.Apply(stats, model.MapTorrentStats), nil
-	// } else if *infohash == "total" {
-	// 	var err error
-	// 	stats, err = r.ATorrentDaemon.TotalStatsHistory(ctx, since)
-	// 	if err != nil {
-	// 		return nil, err
-	// 	}
-	// } else {
-	// 	ih := tinfohash.FromHexString(*infohash)
-	// 	var err error
-	// 	stats, err = r.ATorrentDaemon.TorrentStatsHistory(ctx, since, ih)
-	// 	if err != nil {
-	// 		return nil, err
-	// 	}
-	// }
-
-	// return model.Apply(stats, model.MapTorrentStats), nil
-	panic("not implemented")
-}
-
-// TorrentDaemonQuery returns graph.TorrentDaemonQueryResolver implementation.
-func (r *Resolver) TorrentDaemonQuery() graph.TorrentDaemonQueryResolver {
-	return &torrentDaemonQueryResolver{r}
-}
-
-type torrentDaemonQueryResolver struct{ *Resolver }
diff --git a/daemons/atorrent/delivery/graphql/torrent_types.resolvers.go b/daemons/atorrent/delivery/graphql/torrent_types.resolvers.go
deleted file mode 100644
index bce3b03..0000000
--- a/daemons/atorrent/delivery/graphql/torrent_types.resolvers.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package graphql
-
-// This file will be automatically regenerated based on the schema, any resolver implementations
-// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.55
-
-import (
-	"context"
-
-	graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
-	"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
-	"github.com/anacrolix/torrent/types"
-)
-
-// Name is the resolver for the name field.
-func (r *torrentResolver) Name(ctx context.Context, obj *model.Torrent) (string, error) {
-	return obj.T.Name(), nil
-}
-
-// Files is the resolver for the files field.
-func (r *torrentResolver) Files(ctx context.Context, obj *model.Torrent) ([]*model.TorrentFile, error) {
-	out := []*model.TorrentFile{}
-	files, err := obj.T.Files(ctx)
-	if err != nil {
-		return nil, err
-	}
-	for _, f := range files {
-		out = append(out, &model.TorrentFile{
-			Filename:       f.Path(),
-			Size:           f.Size(),
-			BytesCompleted: f.BytesCompleted(),
-			F:              f,
-		})
-	}
-	return out, nil
-}
-
-// ExcludedFiles is the resolver for the excludedFiles field.
-func (r *torrentResolver) ExcludedFiles(ctx context.Context, obj *model.Torrent) ([]*model.TorrentFile, error) {
-	out := []*model.TorrentFile{}
-	// files, err := obj.T.ExcludedFiles()
-	// if err != nil {
-	// 	return nil, err
-	// }
-	// for _, f := range files {
-	// 	out = append(out, &model.TorrentFile{
-	// 		Filename: f.DisplayPath(),
-	// 		Size:     f.Length(),
-	// 		F:        f,
-	// 	})
-	// }
-	return out, nil
-}
-
-// Peers is the resolver for the peers field.
-func (r *torrentResolver) Peers(ctx context.Context, obj *model.Torrent) ([]*model.TorrentPeer, error) {
-	peers := []*model.TorrentPeer{}
-	for _, peer := range obj.T.Torrent().PeerConns() {
-		clientName, _ := peer.PeerClientName.Load().(string)
-
-		peers = append(peers, &model.TorrentPeer{
-			IP:           peer.RemoteAddr.String(),
-			DownloadRate: peer.DownloadRate(),
-
-			Discovery:  model.MapPeerSource(peer.Discovery),
-			Port:       int64(peer.PeerListenPort),
-			ClientName: clientName,
-			F:          peer,
-		})
-	}
-	return peers, nil
-}
-
-// Priority is the resolver for the priority field.
-func (r *torrentFileResolver) Priority(ctx context.Context, obj *model.TorrentFile) (types.PiecePriority, error) {
-	props, err := obj.F.Properties(ctx)
-	if err != nil {
-		return 0, err
-	}
-	return props.Priority, nil
-}
-
-// Torrent returns graph.TorrentResolver implementation.
-func (r *Resolver) Torrent() graph.TorrentResolver { return &torrentResolver{r} }
-
-// TorrentFile returns graph.TorrentFileResolver implementation.
-func (r *Resolver) TorrentFile() graph.TorrentFileResolver { return &torrentFileResolver{r} }
-
-type torrentResolver struct{ *Resolver }
-type torrentFileResolver struct{ *Resolver }
diff --git a/daemons/atorrent/dht_fileitem_store.go b/daemons/atorrent/dht_fileitem_store.go
deleted file mode 100644
index 9358e83..0000000
--- a/daemons/atorrent/dht_fileitem_store.go
+++ /dev/null
@@ -1,112 +0,0 @@
-package atorrent
-
-import (
-	"bytes"
-	"encoding/gob"
-	"time"
-
-	"git.kmsign.ru/royalcat/tstor/src/logwrap"
-	"github.com/anacrolix/dht/v2/bep44"
-	"github.com/dgraph-io/badger/v4"
-)
-
-var _ bep44.Store = &dhtFileItemStore{}
-
-type dhtFileItemStore struct {
-	ttl time.Duration
-	db  *badger.DB
-}
-
-func newDHTStore(path string, itemsTTL time.Duration) (*dhtFileItemStore, error) {
-	opts := badger.DefaultOptions(path).
-		WithLogger(logwrap.BadgerLogger("torrent-client", "dht-item-store")).
-		WithValueLogFileSize(1<<26 - 1)
-
-	db, err := badger.Open(opts)
-	if err != nil {
-		return nil, err
-	}
-
-	err = db.RunValueLogGC(0.5)
-	if err != nil && err != badger.ErrNoRewrite {
-		return nil, err
-	}
-
-	return &dhtFileItemStore{
-		db:  db,
-		ttl: itemsTTL,
-	}, nil
-}
-
-func (fis *dhtFileItemStore) Put(i *bep44.Item) error {
-	tx := fis.db.NewTransaction(true)
-	defer tx.Discard()
-
-	key := i.Target()
-	var value bytes.Buffer
-
-	enc := gob.NewEncoder(&value)
-	if err := enc.Encode(i); err != nil {
-		return err
-	}
-
-	e := badger.NewEntry(key[:], value.Bytes()).WithTTL(fis.ttl)
-	if err := tx.SetEntry(e); err != nil {
-		return err
-	}
-
-	return tx.Commit()
-}
-
-func (fis *dhtFileItemStore) Get(t bep44.Target) (*bep44.Item, error) {
-	tx := fis.db.NewTransaction(false)
-	defer tx.Discard()
-
-	dbi, err := tx.Get(t[:])
-	if err == badger.ErrKeyNotFound {
-		return nil, bep44.ErrItemNotFound
-	}
-	if err != nil {
-		return nil, err
-	}
-	valb, err := dbi.ValueCopy(nil)
-	if err != nil {
-		return nil, err
-	}
-
-	buf := bytes.NewBuffer(valb)
-	dec := gob.NewDecoder(buf)
-	var i *bep44.Item
-	if err := dec.Decode(&i); err != nil {
-		return nil, err
-	}
-
-	return i, nil
-}
-
-func (fis *dhtFileItemStore) Del(t bep44.Target) error {
-	tx := fis.db.NewTransaction(true)
-	defer tx.Discard()
-
-	err := tx.Delete(t[:])
-	if err == badger.ErrKeyNotFound {
-		return nil
-	}
-	if err != nil {
-		return err
-	}
-
-	err = tx.Commit()
-	if err == badger.ErrKeyNotFound {
-		return nil
-	}
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-func (fis *dhtFileItemStore) Close() error {
-	return fis.db.Close()
-}
diff --git a/daemons/atorrent/dup_cache.go b/daemons/atorrent/dup_cache.go
deleted file mode 100644
index fc400d2..0000000
--- a/daemons/atorrent/dup_cache.go
+++ /dev/null
@@ -1,92 +0,0 @@
-package atorrent
-
-import (
-	"path"
-	"slices"
-	"sync"
-
-	"git.kmsign.ru/royalcat/tstor/pkg/slicesutils"
-	"github.com/anacrolix/torrent/metainfo"
-	"github.com/anacrolix/torrent/types/infohash"
-)
-
-type dupInfo struct {
-	infohash infohash.T
-	fileinfo metainfo.FileInfo
-}
-
-type dupIndex struct {
-	mu         sync.RWMutex
-	torrents   map[infohash.T][]metainfo.FileInfo
-	sha1       map[string][]dupInfo   // bittorrent v1
-	piecesRoot map[[32]byte][]dupInfo // bittorrent v2
-}
-
-func newDupIndex() *dupIndex {
-	return &dupIndex{
-		torrents:   map[infohash.T][]metainfo.FileInfo{},
-		sha1:       map[string][]dupInfo{},
-		piecesRoot: map[[32]byte][]dupInfo{},
-	}
-}
-
-func (c *dupIndex) AddFile(fileinfo metainfo.FileInfo, ih infohash.T) {
-	c.mu.Lock()
-	defer c.mu.Unlock()
-
-	c.torrents[ih] = append(c.torrents[ih], fileinfo)
-
-	if fileinfo.Sha1 != "" {
-		c.sha1[fileinfo.Sha1] = append(c.sha1[fileinfo.Sha1], dupInfo{fileinfo: fileinfo, infohash: ih})
-	}
-
-	if fileinfo.PiecesRoot.Ok {
-		c.piecesRoot[fileinfo.PiecesRoot.Value] = append(c.piecesRoot[fileinfo.PiecesRoot.Value], dupInfo{fileinfo: fileinfo, infohash: ih})
-	}
-}
-
-func (c *dupIndex) DuplicateFiles(fileinfo metainfo.FileInfo, ih infohash.T) []dupInfo {
-	c.mu.RLock()
-	defer c.mu.RUnlock()
-
-	if fileinfo.Sha1 != "" {
-		if dups, ok := c.sha1[fileinfo.Sha1]; ok {
-			return slices.Clone(dups)
-		}
-	}
-
-	if fileinfo.PiecesRoot.Ok {
-		if dups, ok := c.piecesRoot[fileinfo.PiecesRoot.Value]; ok {
-			return slices.Clone(dups)
-		}
-	}
-
-	return []dupInfo{}
-}
-
-func (c *dupIndex) Includes(ih infohash.T, files []metainfo.FileInfo) []dupInfo {
-	c.mu.RLock()
-	defer c.mu.RUnlock()
-
-	out := []dupInfo{}
-
-	for ih, v := range c.torrents {
-		intersection := slicesutils.IntersectionFunc(files, v, func(a, b metainfo.FileInfo) bool {
-			mostly := path.Join(a.BestPath()...) == path.Join(b.BestPath()...) && a.Length == b.Length
-			if a.Sha1 != "" && b.Sha1 != "" {
-				return mostly && a.Sha1 == b.Sha1
-			}
-			if a.PiecesRoot.Ok && b.PiecesRoot.Ok {
-				return mostly && a.PiecesRoot.Value == b.PiecesRoot.Value
-			}
-
-			return mostly
-		})
-
-		for _, v := range intersection {
-			out = append(out, dupInfo{infohash: ih, fileinfo: v})
-		}
-	}
-
-	return []dupInfo{}
-}
diff --git a/daemons/atorrent/file_controller.go b/daemons/atorrent/file_controller.go
deleted file mode 100644
index 9169a18..0000000
--- a/daemons/atorrent/file_controller.go
+++ /dev/null
@@ -1,99 +0,0 @@
-package atorrent
-
-import (
-	"context"
-	"log/slog"
-
-	"git.kmsign.ru/royalcat/tstor/pkg/kvsingle"
-	"git.kmsign.ru/royalcat/tstor/pkg/rlog"
-	"github.com/anacrolix/torrent"
-	"github.com/anacrolix/torrent/metainfo"
-	"github.com/anacrolix/torrent/types"
-	"github.com/royalcat/kv"
-)
-
-type FileController struct {
-	file       *torrent.File
-	properties *kvsingle.Value[string, FileProperties]
-	log        *rlog.Logger
-}
-
-func NewFileController(f *torrent.File, properties *kvsingle.Value[string, FileProperties], log *rlog.Logger) *FileController {
-	return &FileController{
-		file:       f,
-		properties: properties,
-		log:        log.WithComponent("file-controller").With(slog.String("file", f.Path())),
-	}
-}
-
-func (s *FileController) Properties(ctx context.Context) (FileProperties, error) {
-	p, err := s.properties.Get(ctx)
-	if err == kv.ErrKeyNotFound {
-		return FileProperties{
-			Excluded: false,
-			Priority: defaultPriority,
-		}, nil
-	}
-
-	if err != nil {
-		return FileProperties{}, err
-	}
-	return p, nil
-}
-
-func (s *FileController) SetPriority(ctx context.Context, priority types.PiecePriority) error {
-	log := s.log.With(slog.Int("priority", int(priority)))
-
-	err := s.properties.Edit(ctx, func(ctx context.Context, v FileProperties) (FileProperties, error) {
-		v.Priority = priority
-		return v, nil
-	})
-	if err == kv.ErrKeyNotFound {
-		seterr := s.properties.Set(ctx, FileProperties{
-			Priority: priority,
-		})
-		if seterr != nil {
-			return err
-		}
-		err = nil
-	}
-	if err != nil {
-		return err
-	}
-
-	log.Debug(ctx, "file priority set")
-	s.file.SetPriority(priority)
-
-	return nil
-}
-
-func (s *FileController) FileInfo() metainfo.FileInfo {
-	return s.file.FileInfo()
-}
-
-func (s *FileController) Excluded(ctx context.Context) (bool, error) {
-	p, err := s.properties.Get(ctx)
-	if err == kv.ErrKeyNotFound {
-		return false, nil
-	}
-	if err != nil {
-		return false, err
-	}
-	return p.Excluded, nil
-}
-
-func (s *FileController) Path() string {
-	return s.file.Path()
-}
-
-func (s *FileController) Size() int64 {
-	return s.file.Length()
-}
-
-func (s *FileController) Priority() types.PiecePriority {
-	return s.file.Priority()
-}
-
-func (s *FileController) BytesCompleted() int64 {
-	return s.file.BytesCompleted()
-}
diff --git a/daemons/atorrent/fs.go b/daemons/atorrent/fs.go
deleted file mode 100644
index 4c33003..0000000
--- a/daemons/atorrent/fs.go
+++ /dev/null
@@ -1,567 +0,0 @@
-package atorrent
-
-import (
-	"context"
-	"fmt"
-	"io"
-	"io/fs"
-	"log/slog"
-	"path"
-	"slices"
-	"strings"
-	"sync"
-	"sync/atomic"
-	"time"
-
-	"git.kmsign.ru/royalcat/tstor/pkg/rlog"
-	"git.kmsign.ru/royalcat/tstor/src/vfs"
-	"github.com/anacrolix/torrent"
-	"go.opentelemetry.io/otel/attribute"
-	"go.opentelemetry.io/otel/trace"
-	"golang.org/x/exp/maps"
-)
-
-type TorrentFS struct {
-	name string
-
-	Torrent *Controller
-
-	filesCacheMu sync.Mutex
-	filesCache   map[string]vfs.File
-
-	lastTorrentReadTimeout atomic.Pointer[time.Time]
-
-	resolver *vfs.Resolver
-}
-
-var _ vfs.Filesystem = (*TorrentFS)(nil)
-
-const shortTimeout = time.Millisecond
-const lowTimeout = time.Second * 5
-
-func (s *Daemon) NewTorrentFs(ctx context.Context, _ string, f vfs.File) (vfs.Filesystem, error) {
-	c, err := s.loadTorrent(ctx, f)
-	if err != nil {
-		return nil, err
-	}
-
-	if err := f.Close(ctx); err != nil {
-		s.log.Error(ctx, "failed to close file", slog.String("name", f.Name()), rlog.Error(err))
-	}
-
-	return &TorrentFS{
-		name:     f.Name(),
-		Torrent:  c,
-		resolver: vfs.NewResolver(vfs.ArchiveFactories),
-	}, nil
-}
-
-var _ fs.DirEntry = (*TorrentFS)(nil)
-
-// Name implements fs.DirEntry.
-func (tfs *TorrentFS) Name() string {
-	return tfs.name
-}
-
-// Info implements fs.DirEntry.
-func (tfs *TorrentFS) Info() (fs.FileInfo, error) {
-	return tfs, nil
-}
-
-// IsDir implements fs.DirEntry.
-func (tfs *TorrentFS) IsDir() bool {
-	return true
-}
-
-// Type implements fs.DirEntry.
-func (tfs *TorrentFS) Type() fs.FileMode {
-	return fs.ModeDir
-}
-
-// ModTime implements fs.FileInfo.
-func (tfs *TorrentFS) ModTime() time.Time {
-	return time.Time{}
-}
-
-// Mode implements fs.FileInfo.
-func (tfs *TorrentFS) Mode() fs.FileMode {
-	return fs.ModeDir
-}
-
-// Size implements fs.FileInfo.
-func (tfs *TorrentFS) Size() int64 {
-	return 0
-}
-
-// Sys implements fs.FileInfo.
-func (tfs *TorrentFS) Sys() any {
-	return nil
-}
-
-// FsName implements Filesystem.
-func (tfs *TorrentFS) FsName() string {
-	return "torrentfs"
-}
-
-func (fs *TorrentFS) files(ctx context.Context) (map[string]vfs.File, error) {
-	fs.filesCacheMu.Lock()
-	defer fs.filesCacheMu.Unlock()
-
-	if fs.filesCache != nil {
-		return fs.filesCache, nil
-	}
-
-	ctx, span := tracer.Start(ctx, "files", fs.traceAttrs())
-	defer span.End()
-
-	files, err := fs.Torrent.Files(ctx)
-	if err != nil {
-		return nil, err
-	}
-
-	fs.filesCache = make(map[string]vfs.File)
-	for _, file := range files {
-		props, err := file.Properties(ctx)
-		if err != nil {
-			return nil, err
-		}
-		if props.Excluded {
-			continue
-		}
-
-		p := vfs.AbsPath(file.Path())
-		tf, err := openTorrentFile(ctx, path.Base(p), file.file, &fs.lastTorrentReadTimeout)
-		if err != nil {
-			return nil, err
-		}
-		fs.filesCache[p] = tf
-	}
-
-	// TODO optional
-	// if len(fs.filesCache) == 1 && fs.resolver.IsNestedFs(fs.Torrent.Name()) {
-	// 	filepath := "/" + fs.Torrent.Name()
-	// 	if file, ok := fs.filesCache[filepath]; ok {
-	// 		nestedFs, err := fs.resolver.NestedFs(ctx, filepath, file)
-	// 		if err != nil {
-	// 			return nil, err
-	// 		}
-	// 		if nestedFs == nil {
-	// 			goto DEFAULT_DIR // FIXME
-	// 		}
-	// 		fs.filesCache, err = listFilesRecursive(ctx, nestedFs, "/")
-	// 		if err != nil {
-	// 			return nil, err
-	// 		}
-
-	// 		return fs.filesCache, nil
-	// 	}
-	// }
-	// DEFAULT_DIR:
-
-	rootDir := "/" + fs.Torrent.Name() + "/"
-	singleDir := true
-	for k, _ := range fs.filesCache {
-		if !strings.HasPrefix(k, rootDir) {
-			singleDir = false
-		}
-	}
-	if singleDir {
-		for k, f := range fs.filesCache {
-			delete(fs.filesCache, k)
-			k, _ = strings.CutPrefix(k, rootDir)
-			k = vfs.AbsPath(k)
-			fs.filesCache[k] = f
-		}
-	}
-
-	return fs.filesCache, nil
-}
-
-func listFilesRecursive(ctx context.Context, fs vfs.Filesystem, start string) (map[string]vfs.File, error) {
-	out := make(map[string]vfs.File, 0)
-	entries, err := fs.ReadDir(ctx, start)
-	if err != nil {
-		return nil, err
-	}
-	for _, entry := range entries {
-		filename := path.Join(start, entry.Name())
-		if entry.IsDir() {
-			rec, err := listFilesRecursive(ctx, fs, filename)
-			if err != nil {
-				return nil, err
-			}
-			maps.Copy(out, rec)
-		} else {
-			file, err := fs.Open(ctx, filename)
-			if err != nil {
-				return nil, err
-			}
-			out[filename] = file
-		}
-	}
-
-	return out, nil
-}
-
-func (fs *TorrentFS) rawOpen(ctx context.Context, filename string) (file vfs.File, err error) {
-	ctx, span := tracer.Start(ctx, "rawOpen",
-		fs.traceAttrs(attribute.String("filename", filename)),
-	)
-	defer func() {
-		if err != nil {
-			span.RecordError(err)
-		}
-		span.End()
-	}()
-
-	files, err := fs.files(ctx)
-	if err != nil {
-		return nil, err
-	}
-	file, err = vfs.GetFile(files, filename)
-	return file, err
-}
-
-func (fs *TorrentFS) rawStat(ctx context.Context, filename string) (fs.FileInfo, error) {
-	ctx, span := tracer.Start(ctx, "rawStat",
-		fs.traceAttrs(attribute.String("filename", filename)),
-	)
-	defer span.End()
-
-	files, err := fs.files(ctx)
-	if err != nil {
-		return nil, err
-	}
-
-	file, err := vfs.GetFile(files, filename)
-	if err != nil {
-		return nil, err
-	}
-	return file.Info()
-}
-
-func (fs *TorrentFS) traceAttrs(add ...attribute.KeyValue) trace.SpanStartOption {
-	return trace.WithAttributes(append([]attribute.KeyValue{
-		attribute.String("fs", fs.FsName()),
-		attribute.String("torrent", fs.Torrent.Name()),
-		attribute.String("infohash", fs.Torrent.InfoHash()),
-	}, add...)...)
-}
-
-func (tfs *TorrentFS) readContext(ctx context.Context) (context.Context, context.CancelFunc) {
-	lastReadTimeout := tfs.lastTorrentReadTimeout.Load()
-	if lastReadTimeout != nil && time.Since(*lastReadTimeout) < secondaryTimeout { // make short timeout for already faliled files
-		trace.SpanFromContext(ctx).SetAttributes(attribute.Bool("short_timeout", true))
-
-		return context.WithTimeout(ctx, shortTimeout)
-	}
-
-	return ctx, func() {}
-}
-
-// Stat implements Filesystem.
-func (tfs *TorrentFS) Stat(ctx context.Context, filename string) (fs.FileInfo, error) {
-	ctx, span := tracer.Start(ctx, "Stat",
-		tfs.traceAttrs(attribute.String("filename", filename)),
-	)
-	defer span.End()
-
-	if vfs.IsRoot(filename) {
-		return tfs, nil
-	}
-
-	var err error
-	ctx, cancel := tfs.readContext(ctx)
-	defer func() {
-		cancel()
-		if err == context.DeadlineExceeded {
-			now := time.Now()
-			tfs.lastTorrentReadTimeout.Store(&now)
-		}
-	}()
-
-	fsPath, nestedFs, nestedFsPath, err := tfs.resolver.ResolvePath(ctx, filename, tfs.rawOpen)
-	if err != nil {
-		return nil, err
-	}
-	if nestedFs != nil {
-		return nestedFs.Stat(ctx, nestedFsPath)
-	}
-
-	return tfs.rawStat(ctx, fsPath)
-}
-
-func (tfs *TorrentFS) Open(ctx context.Context, filename string) (file vfs.File, err error) {
-	ctx, span := tracer.Start(ctx, "Open",
-		tfs.traceAttrs(attribute.String("filename", filename)),
-	)
-	defer span.End()
-
-	if vfs.IsRoot(filename) {
-		return vfs.NewDirFile(tfs.name), nil
-	}
-
-	ctx, cancel := tfs.readContext(ctx)
-	defer func() {
-		cancel()
-		if err == context.DeadlineExceeded {
-			now := time.Now()
-			tfs.lastTorrentReadTimeout.Store(&now)
-		}
-	}()
-
-	fsPath, nestedFs, nestedFsPath, err := tfs.resolver.ResolvePath(ctx, filename, tfs.rawOpen)
-	if err != nil {
-		return nil, err
-	}
-	if nestedFs != nil {
-		return nestedFs.Open(ctx, nestedFsPath)
-	}
-
-	return tfs.rawOpen(ctx, fsPath)
-}
-
-func (tfs *TorrentFS) ReadDir(ctx context.Context, name string) ([]fs.DirEntry, error) {
-	ctx, span := tracer.Start(ctx, "ReadDir",
-		tfs.traceAttrs(attribute.String("name", name)),
-	)
-	defer span.End()
-
-	var err error
-	ctx, cancel := tfs.readContext(ctx)
-	defer func() {
-		cancel()
-		if err == context.DeadlineExceeded {
-			now := time.Now()
-			tfs.lastTorrentReadTimeout.Store(&now)
-		}
-	}()
-
-	fsPath, nestedFs, nestedFsPath, err := tfs.resolver.ResolvePath(ctx, name, tfs.rawOpen)
-	if err != nil {
-		return nil, err
-	}
-	if nestedFs != nil {
-		return nestedFs.ReadDir(ctx, nestedFsPath)
-	}
-	files, err := tfs.files(ctx)
-	if err != nil {
-		return nil, err
-	}
-
-	return vfs.ListDirFromFiles(files, fsPath)
-}
-
-func (fs *TorrentFS) Unlink(ctx context.Context, name string) error {
-	ctx, span := tracer.Start(ctx, "Unlink",
-		fs.traceAttrs(attribute.String("name", name)),
-	)
-	defer span.End()
-
-	name = vfs.AbsPath(name)
-
-	files, err := fs.files(ctx)
-	if err != nil {
-		return err
-	}
-
-	if !slices.Contains(maps.Keys(files), name) {
-		return vfs.ErrNotExist
-	}
-
-	file := files[name]
-
-	fs.filesCacheMu.Lock()
-	delete(fs.filesCache, name)
-	fs.filesCacheMu.Unlock()
-
-	tfile, ok := file.(*torrentFile)
-	if !ok {
-		return vfs.ErrNotImplemented
-	}
-
-	return fs.Torrent.ExcludeFile(ctx, tfile.file)
-}
-
-// Rename implements vfs.Filesystem.
-func (s *TorrentFS) Rename(ctx context.Context, oldpath string, newpath string) error {
-	return vfs.ErrNotImplemented
-}
-
-var _ vfs.File = (*torrentFile)(nil)
-
-type torrentFile struct {
-	name string
-
-	mu sync.RWMutex
-
-	tr torrent.Reader
-
-	lastReadTimeout        atomic.Pointer[time.Time]
-	lastTorrentReadTimeout *atomic.Pointer[time.Time]
-
-	file *torrent.File
-}
-
-const secondaryTimeout = time.Hour * 24
-
-func openTorrentFile(ctx context.Context, name string, file *torrent.File, lastTorrentReadTimeout *atomic.Pointer[time.Time]) (*torrentFile, error) {
-	select {
-	case <-file.Torrent().GotInfo():
-		break
-	case <-ctx.Done():
-		return nil, ctx.Err()
-	}
-
-	r := file.NewReader()
-	_, err := r.ReadContext(ctx, make([]byte, 128))
-	if err != nil && err != io.EOF {
-		return nil, fmt.Errorf("failed initial file read: %w", err)
-	}
-	_, err = r.Seek(0, io.SeekStart)
-	if err != nil {
-		return nil, fmt.Errorf("failed seeking to start, after initial read: %w", err)
-	}
-
-	return &torrentFile{
-		name:                   name,
-		tr:                     r,
-		file:                   file,
-		lastTorrentReadTimeout: lastTorrentReadTimeout,
-	}, nil
-}
-
-// Name implements File.
-func (tf *torrentFile) Name() string {
-	return tf.name
-}
-
-// Seek implements vfs.File.
-func (tf *torrentFile) Seek(offset int64, whence int) (int64, error) {
-	tf.mu.Lock()
-	defer tf.mu.Unlock()
-
-	return tf.tr.Seek(offset, whence)
-}
-
-// Type implements File.
-func (tf *torrentFile) Type() fs.FileMode {
-	return vfs.ModeFileRO | fs.ModeDir
-}
-
-func (tf *torrentFile) Info() (fs.FileInfo, error) {
-	return vfs.NewFileInfo(tf.name, tf.file.Length(), time.Time{}), nil
-}
-
-func (tf *torrentFile) Size() int64 {
-	return tf.file.Length()
-}
-
-func (tf *torrentFile) IsDir() bool {
-	return false
-}
-
-func (rw *torrentFile) Close(ctx context.Context) error {
-	rw.mu.Lock()
-	defer rw.mu.Unlock()
-
-	return rw.tr.Close()
-}
-
-func (tf *torrentFile) readTimeout(ctx context.Context) (context.Context, context.CancelFunc) {
-	lastReadTimeout := tf.lastReadTimeout.Load()
-	if lastReadTimeout != nil && time.Since(*lastReadTimeout) < secondaryTimeout { // make short timeout for already faliled files
-		trace.SpanFromContext(ctx).SetAttributes(attribute.Bool("short_timeout", true))
-		return context.WithTimeout(ctx, shortTimeout)
-	}
-
-	lastTorrentReadTimeout := tf.lastTorrentReadTimeout.Load()
-	if lastTorrentReadTimeout != nil && time.Since(*lastTorrentReadTimeout) < secondaryTimeout { // make short timeout for already faliled files
-		trace.SpanFromContext(ctx).SetAttributes(attribute.Bool("low_timeout", true))
-		return context.WithTimeout(ctx, lowTimeout)
-	}
-
-	return ctx, func() {}
-}
-
-// Read implements ctxio.Reader.
-func (tf *torrentFile) Read(ctx context.Context, p []byte) (n int, err error) {
-	ctx, span := tracer.Start(ctx, "Read",
-		trace.WithAttributes(attribute.Int("length", len(p))),
-	)
-	defer func() {
-		span.SetAttributes(attribute.Int("read", n))
-		span.End()
-	}()
-
-	tf.mu.Lock()
-	defer tf.mu.Unlock()
-
-	ctx, cancel := tf.readTimeout(ctx)
-	defer cancel()
-	defer func() {
-		if err == context.DeadlineExceeded {
-			now := time.Now()
-			tf.lastReadTimeout.Store(&now)
-			tf.lastTorrentReadTimeout.Store(&now)
-		}
-	}()
-
-	return tf.tr.ReadContext(ctx, p)
-}
-
-func (tf *torrentFile) ReadAt(ctx context.Context, p []byte, off int64) (n int, err error) {
-	ctx, span := tracer.Start(ctx, "ReadAt",
-		trace.WithAttributes(attribute.Int("length", len(p)), attribute.Int64("offset", off)),
-	)
-	defer func() {
-		span.SetAttributes(attribute.Int("read", n))
-		span.End()
-	}()
-
-	tf.mu.RLock()
-	defer tf.mu.RUnlock()
-
-	ctx, cancel := tf.readTimeout(ctx)
-	defer cancel()
-	defer func() {
-		if err == context.DeadlineExceeded {
-			now := time.Now()
-			tf.lastReadTimeout.Store(&now)
-			tf.lastTorrentReadTimeout.Store(&now)
-		}
-	}()
-
-	_, err = tf.tr.Seek(off, io.SeekStart)
-	if err != nil {
-		return 0, err
-	}
-
-	// return tf.tr.ReadContext(ctx, p)
-	n, err = readAtLeast(ctx, tf.tr, p, len(p))
-
-	_, err = tf.tr.Seek(0, io.SeekStart)
-	if err != nil {
-		return 0, err
-	}
-
-	return n, err
-}
-
-func readAtLeast(ctx context.Context, r torrent.Reader, buf []byte, min int) (n int, err error) {
-	if len(buf) < min {
-		return 0, io.ErrShortBuffer
-	}
-	for n < min && err == nil {
-		var nn int
-
-		nn, err = r.ReadContext(ctx, buf[n:])
-		n += nn
-	}
-	if n >= min {
-		err = nil
-	} else if n > 0 && err == io.EOF {
-		err = io.ErrUnexpectedEOF
-	}
-	return
-}
diff --git a/daemons/atorrent/fs_test.go b/daemons/atorrent/fs_test.go
deleted file mode 100644
index b1c7765..0000000
--- a/daemons/atorrent/fs_test.go
+++ /dev/null
@@ -1,142 +0,0 @@
-package atorrent
-
-import (
-	"os"
-	"testing"
-
-	"github.com/anacrolix/torrent"
-)
-
-const testMagnet = "magnet:?xt=urn:btih:a88fda5954e89178c372716a6a78b8180ed4dad3&dn=The+WIRED+CD+-+Rip.+Sample.+Mash.+Share&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fwired-cd.torrent"
-
-var Cli *torrent.Client
-
-func TestMain(m *testing.M) {
-	cfg := torrent.NewDefaultClientConfig()
-	cfg.DataDir = os.TempDir()
-
-	// disable webseeds to avoid a panic when closing client on tests
-	cfg.DisableWebseeds = true
-
-	client, err := torrent.NewClient(cfg)
-	if err != nil {
-		panic(err)
-	}
-
-	Cli = client
-
-	exitVal := m.Run()
-
-	client.Close()
-
-	os.Exit(exitVal)
-}
-
-// func TestTorrentFilesystem(t *testing.T) {
-// 	require := require.New(t)
-
-// 	to, err := Cli.AddMagnet(testMagnet)
-// 	require.NoError(err)
-
-// 	tfs := NewTorrentFs(600)
-// 	tfs.AddTorrent(to)
-
-// 	files, err := tfs.ReadDir("/")
-// 	require.NoError(err)
-// 	require.Len(files, 1)
-// 	require.Contains(files, "The WIRED CD - Rip. Sample. Mash. Share")
-
-// 	files, err = tfs.ReadDir("/The WIRED CD - Rip. Sample. Mash. Share")
-// 	require.NoError(err)
-// 	require.Len(files, 18)
-
-// 	f, err := tfs.Open("/The WIRED CD - Rip. Sample. Mash. Share/not_existing_file.txt")
-// 	require.Equal(os.ErrNotExist, err)
-// 	require.Nil(f)
-
-// 	f, err = tfs.Open("/The WIRED CD - Rip. Sample. Mash. Share/01 - Beastie Boys - Now Get Busy.mp3")
-// 	require.NoError(err)
-// 	require.NotNil(f)
-// 	require.Equal(f.Size(), int64(1964275))
-
-// 	b := make([]byte, 10)
-
-// 	n, err := f.Read(b)
-// 	require.NoError(err)
-// 	require.Equal(10, n)
-// 	require.Equal([]byte{0x49, 0x44, 0x33, 0x3, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x76}, b)
-
-// 	n, err = f.ReadAt(b, 10)
-// 	require.NoError(err)
-// 	require.Equal(10, n)
-
-// 	n, err = f.ReadAt(b, 10000)
-// 	require.NoError(err)
-// 	require.Equal(10, n)
-
-// 	tfs.RemoveTorrent(to.InfoHash().String())
-// 	files, err = tfs.ReadDir("/")
-// 	require.NoError(err)
-// 	require.Len(files, 0)
-
-// 	require.NoError(f.Close())
-// }
-
-// func TestReadAtTorrent(t *testing.T) {
-// 	t.Parallel()
-
-// 	ctx := context.Background()
-
-// 	require := require.New(t)
-
-// 	to, err := Cli.AddMagnet(testMagnet)
-// 	require.NoError(err)
-
-// 	<-to.GotInfo()
-// 	torrFile := to.Files()[0]
-
-// 	tf, err := openTorrentFile(ctx, "torr", torrFile)
-// 	require.NoError(err)
-
-// 	defer tf.Close(ctx)
-
-// 	toRead := make([]byte, 5)
-// 	n, err := tf.ReadAt(ctx, toRead, 6)
-// 	require.NoError(err)
-// 	require.Equal(5, n)
-// 	require.Equal([]byte{0x0, 0x0, 0x1f, 0x76, 0x54}, toRead)
-
-// 	n, err = tf.ReadAt(ctx, toRead, 0)
-// 	require.NoError(err)
-// 	require.Equal(5, n)
-// 	require.Equal([]byte{0x49, 0x44, 0x33, 0x3, 0x0}, toRead)
-// }
-
-// func TestReadAtWrapper(t *testing.T) {
-// 	t.Parallel()
-
-// 	ctx := context.Background()
-
-// 	require := require.New(t)
-
-// 	to, err := Cli.AddMagnet(testMagnet)
-// 	require.NoError(err)
-
-// 	<-to.GotInfo()
-// 	torrFile := to.Files()[0]
-
-// 	r, err := openTorrentFile(ctx, "file", torrFile)
-// 	require.NoError(err)
-// 	defer r.Close(ctx)
-
-// 	toRead := make([]byte, 5)
-// 	n, err := r.ReadAt(ctx, toRead, 6)
-// 	require.NoError(err)
-// 	require.Equal(5, n)
-// 	require.Equal([]byte{0x0, 0x0, 0x1f, 0x76, 0x54}, toRead)
-
-// 	n, err = r.ReadAt(ctx, toRead, 0)
-// 	require.NoError(err)
-// 	require.Equal(5, n)
-// 	require.Equal([]byte{0x49, 0x44, 0x33, 0x3, 0x0}, toRead)
-// }
diff --git a/daemons/atorrent/go.mod b/daemons/atorrent/go.mod
deleted file mode 100644
index bf13c0a..0000000
--- a/daemons/atorrent/go.mod
+++ /dev/null
@@ -1,136 +0,0 @@
-module git.kmsign.ru/royalcat/tstor/daemons/atorrent
-
-go 1.23.5
-
-require (
-	git.kmsign.ru/royalcat/tstor v0.0.0-20250120032914-a43371d1e3b9
-	github.com/anacrolix/dht/v2 v2.22.0
-	github.com/anacrolix/log v0.16.0
-	github.com/anacrolix/torrent v1.58.1-0.20241228235504-75e6b6565845
-	github.com/dgraph-io/badger/v4 v4.5.0
-	github.com/dustin/go-humanize v1.0.1
-	github.com/go-git/go-billy/v5 v5.6.1
-	github.com/royalcat/ctxio v0.0.0-20240602084623-009bd79b3176
-	github.com/royalcat/kv v0.0.0-20240723215915-954e36a2491d
-	github.com/royalcat/kv/kvbadger v0.0.0-20240723215915-954e36a2491d
-	github.com/stretchr/testify v1.10.0
-	go.opentelemetry.io/otel v1.34.0
-	go.opentelemetry.io/otel/metric v1.34.0
-	go.opentelemetry.io/otel/trace v1.34.0
-	golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8
-	golang.org/x/sys v0.29.0
-)
-
-require (
-	github.com/99designs/gqlgen v0.17.55 // indirect
-	github.com/RoaringBitmap/roaring v1.2.3 // indirect
-	github.com/agnivade/levenshtein v1.1.1 // indirect
-	github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 // indirect
-	github.com/alecthomas/assert/v2 v2.3.0 // indirect
-	github.com/alecthomas/atomic v0.1.0-alpha2 // indirect
-	github.com/anacrolix/chansync v0.4.1-0.20240627045151-1aa1ac392fe8 // indirect
-	github.com/anacrolix/envpprof v1.3.0 // indirect
-	github.com/anacrolix/generics v0.0.3-0.20240902042256-7fb2702ef0ca // indirect
-	github.com/anacrolix/go-libutp v1.3.1 // indirect
-	github.com/anacrolix/missinggo v1.3.0 // indirect
-	github.com/anacrolix/missinggo/perf v1.0.0 // indirect
-	github.com/anacrolix/missinggo/v2 v2.7.4 // indirect
-	github.com/anacrolix/mmsg v1.0.0 // indirect
-	github.com/anacrolix/multiless v0.4.0 // indirect
-	github.com/anacrolix/stm v0.4.1-0.20221221005312-96d17df0e496 // indirect
-	github.com/anacrolix/sync v0.5.1 // indirect
-	github.com/anacrolix/upnp v0.1.4 // indirect
-	github.com/anacrolix/utp v0.1.0 // indirect
-	github.com/bahlo/generic-list-go v0.2.0 // indirect
-	github.com/benbjohnson/immutable v0.4.1-0.20221220213129-8932b999621d // indirect
-	github.com/bits-and-blooms/bitset v1.2.2 // indirect
-	github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
-	github.com/cespare/xxhash v1.1.0 // indirect
-	github.com/cespare/xxhash/v2 v2.3.0 // indirect
-	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
-	github.com/dgraph-io/ristretto/v2 v2.0.0 // indirect
-	github.com/edsrzf/mmap-go v1.1.0 // indirect
-	github.com/fatih/structs v1.1.0 // indirect
-	github.com/fsnotify/fsnotify v1.7.0 // indirect
-	github.com/go-llsqlite/adapter v0.0.0-20230927005056-7f5ce7f0c916 // indirect
-	github.com/go-llsqlite/crawshaw v0.5.2-0.20240425034140-f30eb7704568 // indirect
-	github.com/go-logr/logr v1.4.2 // indirect
-	github.com/go-logr/stdr v1.2.2 // indirect
-	github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
-	github.com/gofrs/uuid/v5 v5.1.0 // indirect
-	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
-	github.com/google/btree v1.1.2 // indirect
-	github.com/google/flatbuffers v24.3.25+incompatible // indirect
-	github.com/google/uuid v1.6.0 // indirect
-	github.com/gorilla/websocket v1.5.1 // indirect
-	github.com/goware/singleflight v0.2.0 // indirect
-	github.com/huandu/xstrings v1.4.0 // indirect
-	github.com/klauspost/compress v1.17.11 // indirect
-	github.com/klauspost/cpuid/v2 v2.2.8 // indirect
-	github.com/knadh/koanf/maps v0.1.1 // indirect
-	github.com/knadh/koanf/parsers/yaml v0.1.0 // indirect
-	github.com/knadh/koanf/providers/env v0.1.0 // indirect
-	github.com/knadh/koanf/providers/file v0.1.0 // indirect
-	github.com/knadh/koanf/providers/structs v0.1.0 // indirect
-	github.com/knadh/koanf/v2 v2.1.2 // indirect
-	github.com/mattn/go-colorable v0.1.13 // indirect
-	github.com/mattn/go-isatty v0.0.20 // indirect
-	github.com/minio/sha256-simd v1.0.0 // indirect
-	github.com/mitchellh/copystructure v1.2.0 // indirect
-	github.com/mitchellh/reflectwalk v1.0.2 // indirect
-	github.com/mr-tron/base58 v1.2.0 // indirect
-	github.com/mschoch/smat v0.2.0 // indirect
-	github.com/multiformats/go-multihash v0.2.3 // indirect
-	github.com/multiformats/go-varint v0.0.6 // indirect
-	github.com/pion/datachannel v1.5.9 // indirect
-	github.com/pion/dtls/v3 v3.0.3 // indirect
-	github.com/pion/ice/v4 v4.0.2 // indirect
-	github.com/pion/interceptor v0.1.37 // indirect
-	github.com/pion/logging v0.2.2 // indirect
-	github.com/pion/mdns/v2 v2.0.7 // indirect
-	github.com/pion/randutil v0.1.0 // indirect
-	github.com/pion/rtcp v1.2.14 // indirect
-	github.com/pion/rtp v1.8.9 // indirect
-	github.com/pion/sctp v1.8.33 // indirect
-	github.com/pion/sdp/v3 v3.0.9 // indirect
-	github.com/pion/srtp/v3 v3.0.4 // indirect
-	github.com/pion/stun/v3 v3.0.0 // indirect
-	github.com/pion/transport/v3 v3.0.7 // indirect
-	github.com/pion/turn/v4 v4.0.0 // indirect
-	github.com/pion/webrtc/v4 v4.0.0 // indirect
-	github.com/pkg/errors v0.9.1 // indirect
-	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
-	github.com/protolambda/ctxlock v0.1.0 // indirect
-	github.com/rasky/go-xdr v0.0.0-20170124162913-1a41d1a06c93 // indirect
-	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
-	github.com/royalcat/btrgo v0.0.0-20240318160410-19bd27154450 // indirect
-	github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 // indirect
-	github.com/rs/zerolog v1.32.0 // indirect
-	github.com/samber/lo v1.47.0 // indirect
-	github.com/samber/slog-multi v1.0.2 // indirect
-	github.com/samber/slog-zerolog v1.0.0 // indirect
-	github.com/sosodev/duration v1.3.1 // indirect
-	github.com/sourcegraph/conc v0.3.0 // indirect
-	github.com/spaolacci/murmur3 v1.1.0 // indirect
-	github.com/tidwall/btree v1.6.0 // indirect
-	github.com/vektah/gqlparser/v2 v2.5.17 // indirect
-	github.com/willscott/go-nfs-client v0.0.0-20240104095149-b44639837b00 // indirect
-	github.com/wlynxg/anet v0.0.3 // indirect
-	go.etcd.io/bbolt v1.3.10 // indirect
-	go.opencensus.io v0.24.0 // indirect
-	go.opentelemetry.io/auto/sdk v1.1.0 // indirect
-	go.uber.org/multierr v1.10.0 // indirect
-	golang.org/x/crypto v0.32.0 // indirect
-	golang.org/x/net v0.34.0 // indirect
-	golang.org/x/sync v0.10.0 // indirect
-	golang.org/x/text v0.21.0 // indirect
-	golang.org/x/time v0.6.0 // indirect
-	google.golang.org/protobuf v1.35.1 // indirect
-	gopkg.in/yaml.v3 v3.0.1 // indirect
-	lukechampine.com/blake3 v1.1.6 // indirect
-	modernc.org/libc v1.22.4 // indirect
-	modernc.org/mathutil v1.5.0 // indirect
-	modernc.org/memory v1.5.0 // indirect
-	modernc.org/sqlite v1.21.2 // indirect
-	zombiezen.com/go/sqlite v0.13.1 // indirect
-)
diff --git a/daemons/atorrent/go.sum b/daemons/atorrent/go.sum
deleted file mode 100644
index 2fcf4f1..0000000
--- a/daemons/atorrent/go.sum
+++ /dev/null
@@ -1,629 +0,0 @@
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797/go.mod h1:sXBiorCo8c46JlQV3oXPKINnZ8mcqnye1EkVkqsectk=
-crawshaw.io/sqlite v0.3.2/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4=
-filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
-filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
-git.kmsign.ru/royalcat/tstor v0.0.0-20250120032914-a43371d1e3b9 h1:DHcbILTa1w3TWerW1Wkty/2TIsjK7Hr0yeoTBCYrf4U=
-git.kmsign.ru/royalcat/tstor v0.0.0-20250120032914-a43371d1e3b9/go.mod h1:vhoCnS6pDoj3OS9jnFjdRPldAkcvxirfKh0aXxa88EI=
-github.com/99designs/gqlgen v0.17.55 h1:3vzrNWYyzSZjGDFo68e5j9sSauLxfKvLp+6ioRokVtM=
-github.com/99designs/gqlgen v0.17.55/go.mod h1:3Bq768f8hgVPGZxL8aY9MaYmbxa6llPM/qu1IGH1EJo=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
-github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
-github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI=
-github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
-github.com/RoaringBitmap/roaring v1.2.3 h1:yqreLINqIrX22ErkKI0vY47/ivtJr6n+kMhVOVmhWBY=
-github.com/RoaringBitmap/roaring v1.2.3/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE=
-github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
-github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
-github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
-github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
-github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 h1:byYvvbfSo3+9efR4IeReh77gVs4PnNDR3AMOE9NJ7a0=
-github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0/go.mod h1:q37NoqncT41qKc048STsifIt69LfUJ8SrWWcz/yam5k=
-github.com/alecthomas/assert/v2 v2.3.0 h1:mAsH2wmvjsuvyBvAmCtm7zFsBlb8mIHx5ySLVdDZXL0=
-github.com/alecthomas/assert/v2 v2.3.0/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
-github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8=
-github.com/alecthomas/atomic v0.1.0-alpha2/go.mod h1:zD6QGEyw49HIq19caJDc2NMXAy8rNi9ROrxtMXATfyI=
-github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
-github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
-github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/anacrolix/chansync v0.4.1-0.20240627045151-1aa1ac392fe8 h1:eyb0bBaQKMOh5Se/Qg54shijc8K4zpQiOjEhKFADkQM=
-github.com/anacrolix/chansync v0.4.1-0.20240627045151-1aa1ac392fe8/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
-github.com/anacrolix/dht/v2 v2.22.0 h1:wat5FLdT25vltHsjX377GBrpK9o6L2QVn541bIguCYo=
-github.com/anacrolix/dht/v2 v2.22.0/go.mod h1:shbBjhgvezqsJoE+hMo/ezHYQFF18V9jUllNIP5xV9k=
-github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
-github.com/anacrolix/envpprof v1.0.0/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
-github.com/anacrolix/envpprof v1.1.0/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAKu/0SM/rkf4=
-github.com/anacrolix/envpprof v1.3.0 h1:WJt9bpuT7A/CDCxPOv/eeZqHWlle/Y0keJUvc6tcJDk=
-github.com/anacrolix/envpprof v1.3.0/go.mod h1:7QIG4CaX1uexQ3tqd5+BRa/9e2D02Wcertl6Yh0jCB0=
-github.com/anacrolix/generics v0.0.0-20230113004304-d6428d516633/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8=
-github.com/anacrolix/generics v0.0.3-0.20240902042256-7fb2702ef0ca h1:aiiGqSQWjtVNdi8zUMfA//IrM8fPkv2bWwZVPbDe0wg=
-github.com/anacrolix/generics v0.0.3-0.20240902042256-7fb2702ef0ca/go.mod h1:MN3ve08Z3zSV/rTuX/ouI4lNdlfTxgdafQJiLzyNRB8=
-github.com/anacrolix/go-libutp v1.3.1 h1:idJzreNLl+hNjGC3ZnUOjujEaryeOGgkwHLqSGoige0=
-github.com/anacrolix/go-libutp v1.3.1/go.mod h1:heF41EC8kN0qCLMokLBVkB8NXiLwx3t8R8810MTNI5o=
-github.com/anacrolix/log v0.3.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
-github.com/anacrolix/log v0.6.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
-github.com/anacrolix/log v0.13.1/go.mod h1:D4+CvN8SnruK6zIFS/xPoRJmtvtnxs+CSfDQ+BFxZ68=
-github.com/anacrolix/log v0.14.2/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY=
-github.com/anacrolix/log v0.16.0 h1:DSuyb5kAJwl3Y0X1TRcStVrTS9ST9b0BHW+7neE4Xho=
-github.com/anacrolix/log v0.16.0/go.mod h1:m0poRtlr41mriZlXBQ9SOVZ8yZBkLjOkDhd5Li5pITA=
-github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62 h1:P04VG6Td13FHMgS5ZBcJX23NPC/fiC4cp9bXwYujdYM=
-github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62/go.mod h1:66cFKPCO7Sl4vbFnAaSq7e4OXtdMhRSBagJGWgmpJbM=
-github.com/anacrolix/missinggo v0.0.0-20180725070939-60ef2fbf63df/go.mod h1:kwGiTUTZ0+p4vAz3VbAI5a30t2YbvemcmspjKwrAz5s=
-github.com/anacrolix/missinggo v1.1.0/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo=
-github.com/anacrolix/missinggo v1.1.2-0.20190815015349-b888af804467/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo=
-github.com/anacrolix/missinggo v1.2.1/go.mod h1:J5cMhif8jPmFoC3+Uvob3OXXNIhOUikzMt+uUjeM21Y=
-github.com/anacrolix/missinggo v1.3.0 h1:06HlMsudotL7BAELRZs0yDZ4yVXsHXGi323QBjAVASw=
-github.com/anacrolix/missinggo v1.3.0/go.mod h1:bqHm8cE8xr+15uVfMG3BFui/TxyB6//H5fwlq/TeqMc=
-github.com/anacrolix/missinggo/perf v1.0.0 h1:7ZOGYziGEBytW49+KmYGTaNfnwUqP1HBsy6BqESAJVw=
-github.com/anacrolix/missinggo/perf v1.0.0/go.mod h1:ljAFWkBuzkO12MQclXzZrosP5urunoLS0Cbvb4V0uMQ=
-github.com/anacrolix/missinggo/v2 v2.2.0/go.mod h1:o0jgJoYOyaoYQ4E2ZMISVa9c88BbUBVQQW4QeRkNCGY=
-github.com/anacrolix/missinggo/v2 v2.5.1/go.mod h1:WEjqh2rmKECd0t1VhQkLGTdIWXO6f6NLjp5GlMZ+6FA=
-github.com/anacrolix/missinggo/v2 v2.7.4 h1:47h5OXoPV8JbA/ACA+FLwKdYbAinuDO8osc2Cu9xkxg=
-github.com/anacrolix/missinggo/v2 v2.7.4/go.mod h1:vVO5FEziQm+NFmJesc7StpkquZk+WJFCaL0Wp//2sa0=
-github.com/anacrolix/mmsg v0.0.0-20180515031531-a4a3ba1fc8bb/go.mod h1:x2/ErsYUmT77kezS63+wzZp8E3byYB0gzirM/WMBLfw=
-github.com/anacrolix/mmsg v1.0.0 h1:btC7YLjOn29aTUAExJiVUhQOuf/8rhm+/nWCMAnL3Hg=
-github.com/anacrolix/mmsg v1.0.0/go.mod h1:x8kRaJY/dCrY9Al0PEcj1mb/uFHwP6GCJ9fLl4thEPc=
-github.com/anacrolix/multiless v0.4.0 h1:lqSszHkliMsZd2hsyrDvHOw4AbYWa+ijQ66LzbjqWjM=
-github.com/anacrolix/multiless v0.4.0/go.mod h1:zJv1JF9AqdZiHwxqPgjuOZDGWER6nyE48WBCi/OOrMM=
-github.com/anacrolix/stm v0.2.0/go.mod h1:zoVQRvSiGjGoTmbM0vSLIiaKjWtNPeTvXUSdJQA4hsg=
-github.com/anacrolix/stm v0.4.1-0.20221221005312-96d17df0e496 h1:aMiRi2kOOd+nG64suAmFMVnNK2E6GsnLif7ia9tI3cA=
-github.com/anacrolix/stm v0.4.1-0.20221221005312-96d17df0e496/go.mod h1:DBm8/1OXm4A4RZ6Xa9u/eOsjeAXCaoRYvd2JzlskXeM=
-github.com/anacrolix/sync v0.0.0-20180808010631-44578de4e778/go.mod h1:s735Etp3joe/voe2sdaXLcqDdJSay1O0OPnM0ystjqk=
-github.com/anacrolix/sync v0.3.0/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g=
-github.com/anacrolix/sync v0.5.1 h1:FbGju6GqSjzVoTgcXTUKkF041lnZkG5P0C3T5RL3SGc=
-github.com/anacrolix/sync v0.5.1/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g=
-github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
-github.com/anacrolix/tagflag v1.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
-github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8=
-github.com/anacrolix/torrent v1.58.1-0.20241228235504-75e6b6565845 h1:ZuYsqgbLCVJHHmYQKG6ImMtz+3hUOI1qvRJTuxTVEZY=
-github.com/anacrolix/torrent v1.58.1-0.20241228235504-75e6b6565845/go.mod h1:n3SjHIE8oHXeH0Px0d5FXQ7cU4IgbEfTroen6B9KWJk=
-github.com/anacrolix/upnp v0.1.4 h1:+2t2KA6QOhm/49zeNyeVwDu1ZYS9dB9wfxyVvh/wk7U=
-github.com/anacrolix/upnp v0.1.4/go.mod h1:Qyhbqo69gwNWvEk1xNTXsS5j7hMHef9hdr984+9fIic=
-github.com/anacrolix/utp v0.1.0 h1:FOpQOmIwYsnENnz7tAGohA+r6iXpRjrq8ssKSre2Cp4=
-github.com/anacrolix/utp v0.1.0/go.mod h1:MDwc+vsGEq7RMw6lr2GKOEqjWny5hO5OZXRVNaBJ2Dk=
-github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
-github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
-github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
-github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
-github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
-github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
-github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
-github.com/benbjohnson/immutable v0.2.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI=
-github.com/benbjohnson/immutable v0.4.1-0.20221220213129-8932b999621d h1:2qVb9bsAMtmAfnxXltm+6eBzrrS7SZ52c3SedsulaMI=
-github.com/benbjohnson/immutable v0.4.1-0.20221220213129-8932b999621d/go.mod h1:iAr8OjJGLnLmVUr9MZ/rz4PWUy6Ouc2JLYuMArmvAJM=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
-github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
-github.com/bits-and-blooms/bitset v1.2.2 h1:J5gbX05GpMdBjCvQ9MteIg2KKDExr7DrgK+Yc15FvIk=
-github.com/bits-and-blooms/bitset v1.2.2/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
-github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
-github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
-github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
-github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
-github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
-github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
-github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dgraph-io/badger/v4 v4.5.0 h1:TeJE3I1pIWLBjYhIYCA1+uxrjWEoJXImFBMEBVSm16g=
-github.com/dgraph-io/badger/v4 v4.5.0/go.mod h1:ysgYmIeG8dS/E8kwxT7xHyc7MkmwNYLRoYnFbr7387A=
-github.com/dgraph-io/ristretto/v2 v2.0.0 h1:l0yiSOtlJvc0otkqyMaDNysg8E9/F/TYZwMbxscNOAQ=
-github.com/dgraph-io/ristretto/v2 v2.0.0/go.mod h1:FVFokF2dRqXyPyeMnK1YDy8Fc6aTe0IKgbcd03CYeEk=
-github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
-github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
-github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=
-github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
-github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
-github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
-github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
-github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
-github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
-github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
-github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
-github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
-github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
-github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
-github.com/frankban/quicktest v1.9.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
-github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
-github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
-github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
-github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
-github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
-github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
-github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
-github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
-github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
-github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
-github.com/go-git/go-billy/v5 v5.6.1 h1:u+dcrgaguSSkbjzHwelEjc0Yj300NUevrrPphk/SoRA=
-github.com/go-git/go-billy/v5 v5.6.1/go.mod h1:0AsLr1z2+Uksi4NlElmMblP5rPcDZNRCD8ujZCRR2BE=
-github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-llsqlite/adapter v0.0.0-20230927005056-7f5ce7f0c916 h1:OyQmpAN302wAopDgwVjgs2HkFawP9ahIEqkUYz7V7CA=
-github.com/go-llsqlite/adapter v0.0.0-20230927005056-7f5ce7f0c916/go.mod h1:DADrR88ONKPPeSGjFp5iEN55Arx3fi2qXZeKCYDpbmU=
-github.com/go-llsqlite/crawshaw v0.5.2-0.20240425034140-f30eb7704568 h1:3EpZo8LxIzF4q3BT+vttQQlRfA6uTtTb/cxVisWa5HM=
-github.com/go-llsqlite/crawshaw v0.5.2-0.20240425034140-f30eb7704568/go.mod h1:/YJdV7uBQaYDE0fwe4z3wwJIZBJxdYzd38ICggWqtaE=
-github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
-github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
-github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
-github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
-github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
-github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
-github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
-github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
-github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
-github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
-github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/gofrs/uuid/v5 v5.1.0 h1:S5rqVKIigghZTCBKPCw0Y+bXkn26K3TB5mvQq2Ix8dk=
-github.com/gofrs/uuid/v5 v5.1.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
-github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
-github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
-github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI=
-github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
-github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
-github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gopherjs/gopherjs v0.0.0-20190309154008-847fc94819f9/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
-github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
-github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
-github.com/goware/singleflight v0.2.0 h1:e/hZsvNmbLoiZLx3XbihH01oXYA2MwLFo4e+N017U4c=
-github.com/goware/singleflight v0.2.0/go.mod h1:SsAslCMS7HizXdbYcBQRBLC7HcNmFrHutRt3Hz6wovY=
-github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
-github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
-github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
-github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
-github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
-github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
-github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
-github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
-github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
-github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
-github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
-github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
-github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
-github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
-github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
-github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
-github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs=
-github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
-github.com/knadh/koanf/parsers/yaml v0.1.0 h1:ZZ8/iGfRLvKSaMEECEBPM1HQslrZADk8fP1XFUxVI5w=
-github.com/knadh/koanf/parsers/yaml v0.1.0/go.mod h1:cvbUDC7AL23pImuQP0oRw/hPuccrNBS2bps8asS0CwY=
-github.com/knadh/koanf/providers/env v0.1.0 h1:LqKteXqfOWyx5Ab9VfGHmjY9BvRXi+clwyZozgVRiKg=
-github.com/knadh/koanf/providers/env v0.1.0/go.mod h1:RE8K9GbACJkeEnkl8L/Qcj8p4ZyPXZIQ191HJi44ZaQ=
-github.com/knadh/koanf/providers/file v0.1.0 h1:fs6U7nrV58d3CFAFh8VTde8TM262ObYf3ODrc//Lp+c=
-github.com/knadh/koanf/providers/file v0.1.0/go.mod h1:rjJ/nHQl64iYCtAW2QQnF0eSmDEX/YZ/eNFj5yR6BvA=
-github.com/knadh/koanf/providers/structs v0.1.0 h1:wJRteCNn1qvLtE5h8KQBvLJovidSdntfdyIbbCzEyE0=
-github.com/knadh/koanf/providers/structs v0.1.0/go.mod h1:sw2YZ3txUcqA3Z27gPlmmBzWn1h8Nt9O6EP/91MkcWE=
-github.com/knadh/koanf/v2 v2.1.2 h1:I2rtLRqXRy1p01m/utEtpZSSA6dcJbgGVuE27kW2PzQ=
-github.com/knadh/koanf/v2 v2.1.2/go.mod h1:Gphfaen0q1Fc1HTgJgSTC4oRX9R2R5ErYMZJy8fLJBo=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
-github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
-github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
-github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
-github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
-github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
-github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
-github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
-github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
-github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
-github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
-github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
-github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
-github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
-github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
-github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U=
-github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM=
-github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=
-github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
-github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
-github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
-github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
-github.com/pion/datachannel v1.5.9 h1:LpIWAOYPyDrXtU+BW7X0Yt/vGtYxtXQ8ql7dFfYUVZA=
-github.com/pion/datachannel v1.5.9/go.mod h1:kDUuk4CU4Uxp82NH4LQZbISULkX/HtzKa4P7ldf9izE=
-github.com/pion/dtls/v3 v3.0.3 h1:j5ajZbQwff7Z8k3pE3S+rQ4STvKvXUdKsi/07ka+OWM=
-github.com/pion/dtls/v3 v3.0.3/go.mod h1:weOTUyIV4z0bQaVzKe8kpaP17+us3yAuiQsEAG1STMU=
-github.com/pion/ice/v4 v4.0.2 h1:1JhBRX8iQLi0+TfcavTjPjI6GO41MFn4CeTBX+Y9h5s=
-github.com/pion/ice/v4 v4.0.2/go.mod h1:DCdqyzgtsDNYN6/3U8044j3U7qsJ9KFJC92VnOWHvXg=
-github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI=
-github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y=
-github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
-github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
-github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM=
-github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA=
-github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
-github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
-github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE=
-github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4=
-github.com/pion/rtp v1.8.9 h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk=
-github.com/pion/rtp v1.8.9/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
-github.com/pion/sctp v1.8.33 h1:dSE4wX6uTJBcNm8+YlMg7lw1wqyKHggsP5uKbdj+NZw=
-github.com/pion/sctp v1.8.33/go.mod h1:beTnqSzewI53KWoG3nqB282oDMGrhNxBdb+JZnkCwRM=
-github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY=
-github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M=
-github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M=
-github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ=
-github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw=
-github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU=
-github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0=
-github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo=
-github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM=
-github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA=
-github.com/pion/webrtc/v4 v4.0.0 h1:x8ec7uJQPP3D1iI8ojPAiTOylPI7Fa7QgqZrhpLyqZ8=
-github.com/pion/webrtc/v4 v4.0.0/go.mod h1:SfNn8CcFxR6OUVjLXVslAQ3a3994JhyE3Hw1jAuqEto=
-github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
-github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
-github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
-github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
-github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
-github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
-github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
-github.com/protolambda/ctxlock v0.1.0 h1:rCUY3+vRdcdZXqT07iXgyr744J2DU2LCBIXowYAjBCE=
-github.com/protolambda/ctxlock v0.1.0/go.mod h1:vefhX6rIZH8rsg5ZpOJfEDYQOppZi19SfPiGOFrNnwM=
-github.com/rasky/go-xdr v0.0.0-20170124162913-1a41d1a06c93 h1:UVArwN/wkKjMVhh2EQGC0tEc1+FqiLlvYXY5mQ2f8Wg=
-github.com/rasky/go-xdr v0.0.0-20170124162913-1a41d1a06c93/go.mod h1:Nfe4efndBz4TibWycNE+lqyJZiMX4ycx+QKV8Ta0f/o=
-github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
-github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
-github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
-github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
-github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
-github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
-github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
-github.com/royalcat/btrgo v0.0.0-20240318160410-19bd27154450 h1:AZyZxXZLniAR0DaZhTS4RVcHtOvYMW8IunplqC9A0mk=
-github.com/royalcat/btrgo v0.0.0-20240318160410-19bd27154450/go.mod h1:m3TPa9l/wMKpm/7WHrMs3dSFUxo7kLHaI8ap+SFGYhQ=
-github.com/royalcat/ctxio v0.0.0-20240602084623-009bd79b3176 h1:2jCQJow6jRvhpdMJCo1Okd7tq5Rg4YXlUxqT0q0NWAg=
-github.com/royalcat/ctxio v0.0.0-20240602084623-009bd79b3176/go.mod h1:81eB8eOH/UU7pzI7J1Rsg3KLpshF7BXg4+UHbex+27I=
-github.com/royalcat/kv v0.0.0-20240723215915-954e36a2491d h1:MmqWGKR/MQdRBRieWVQXkn6X5dVyvwC/1H1WZEVLj3A=
-github.com/royalcat/kv v0.0.0-20240723215915-954e36a2491d/go.mod h1:UMD8Uk5ph+34lFjD7WrEUdiivC3pyd1tTAGYv3+iukg=
-github.com/royalcat/kv/kvbadger v0.0.0-20240723215915-954e36a2491d h1:87jn2CTjcxuLmQ2+8128bQD9m4qUM2F8oLNX+HvPGfc=
-github.com/royalcat/kv/kvbadger v0.0.0-20240723215915-954e36a2491d/go.mod h1:ZvAOAmLJhB9YaaDZ8e0RDdbjOA4bHD7MilyMjongmS8=
-github.com/royalcat/kv/testsuite v0.0.0-20240723124828-253d2ecf5312 h1:HJa7itFbdRh1S1MzLGLT56C7glaCOFC/zFnIIJleWVc=
-github.com/royalcat/kv/testsuite v0.0.0-20240723124828-253d2ecf5312/go.mod h1:mnIN/3t3O7piZJW5N0Em79rO27EbupBcHZncbMeBwjE=
-github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 h1:Lt9DzQALzHoDwMBGJ6v8ObDPR0dzr2a6sXTB1Fq7IHs=
-github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA=
-github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
-github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
-github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
-github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8=
-github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
-github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc=
-github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
-github.com/samber/slog-multi v1.0.2 h1:6BVH9uHGAsiGkbbtQgAOQJMpKgV8unMrHhhJaw+X1EQ=
-github.com/samber/slog-multi v1.0.2/go.mod h1:uLAvHpGqbYgX4FSL0p1ZwoLuveIAJvBECtE07XmYvFo=
-github.com/samber/slog-zerolog v1.0.0 h1:YpRy0xux1uJr0Ng3wrEjv9nyvb4RAoNqkS611UjzeG8=
-github.com/samber/slog-zerolog v1.0.0/go.mod h1:N2/g/mNGRY1zqsydIYE0uKipSSFsPDjytoVkRnZ0Jp0=
-github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
-github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
-github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/assertions v0.0.0-20190215210624-980c5ac6f3ac/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
-github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs=
-github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4=
-github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
-github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
-github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
-github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
-github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
-github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
-github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg=
-github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
-github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
-github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
-github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
-github.com/vektah/gqlparser/v2 v2.5.17 h1:9At7WblLV7/36nulgekUgIaqHZWn5hxqluxrxGUhOmI=
-github.com/vektah/gqlparser/v2 v2.5.17/go.mod h1:1lz1OeCqgQbQepsGxPVywrjdBHW2T08PUS3pJqepRww=
-github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
-github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
-github.com/willscott/go-nfs-client v0.0.0-20240104095149-b44639837b00 h1:U0DnHRZFzoIV1oFEZczg5XyPut9yxk9jjtax/9Bxr/o=
-github.com/willscott/go-nfs-client v0.0.0-20240104095149-b44639837b00/go.mod h1:Tq++Lr/FgiS3X48q5FETemXiSLGuYMQT2sPjYNPJSwA=
-github.com/wlynxg/anet v0.0.3 h1:PvR53psxFXstc12jelG6f1Lv4MWqE0tI76/hHGjh9rg=
-github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
-github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=
-go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=
-go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
-go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
-go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
-go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
-go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
-go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
-go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
-go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
-go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
-go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
-go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
-go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
-golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
-golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
-golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
-golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
-golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
-golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
-golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
-golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
-golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
-golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
-golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
-google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
-gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-lukechampine.com/blake3 v1.1.6 h1:H3cROdztr7RCfoaTpGZFQsrqvweFLrqS73j7L7cmR5c=
-lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
-modernc.org/libc v1.22.4 h1:wymSbZb0AlrjdAVX3cjreCHTPCpPARbQXNz6BHPzdwQ=
-modernc.org/libc v1.22.4/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
-modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
-modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
-modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
-modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
-modernc.org/sqlite v1.21.2 h1:ixuUG0QS413Vfzyx6FWx6PYTmHaOegTY+hjzhn7L+a0=
-modernc.org/sqlite v1.21.2/go.mod h1:cxbLkB5WS32DnQqeH4h4o1B0eMr8W/y8/RGuxQ3JsC0=
-zombiezen.com/go/sqlite v0.13.1 h1:qDzxyWWmMtSSEH5qxamqBFmqA2BLSSbtODi3ojaE02o=
-zombiezen.com/go/sqlite v0.13.1/go.mod h1:Ht/5Rg3Ae2hoyh1I7gbWtWAl89CNocfqeb/aAMTkJr4=
diff --git a/daemons/atorrent/graphql/mutation.graphql b/daemons/atorrent/graphql/mutation.graphql
deleted file mode 100644
index 13ada15..0000000
--- a/daemons/atorrent/graphql/mutation.graphql
+++ /dev/null
@@ -1,18 +0,0 @@
-type TorrentDaemonMutation {
-  validateTorrent(filter: TorrentFilter!): Boolean! @resolver
-  setTorrentPriority(
-    infohash: String!
-    file: String
-    priority: TorrentPriority!
-  ): Boolean! @resolver
-  cleanup(files: Boolean, dryRun: Boolean!): CleanupResponse! @resolver
-}
-
-type CleanupResponse {
-  count: Int!
-  list: [String!]!
-}
-
-type DownloadTorrentResponse {
-  taskID: String!
-}
diff --git a/daemons/atorrent/graphql/query.graphql b/daemons/atorrent/graphql/query.graphql
deleted file mode 100644
index 6ecd144..0000000
--- a/daemons/atorrent/graphql/query.graphql
+++ /dev/null
@@ -1,29 +0,0 @@
-type TorrentDaemonQuery {
-  torrents(filter: TorrentsFilter): [Torrent!]! @resolver
-  clientStats: TorrentClientStats! @resolver
-  statsHistory(since: DateTime!, infohash: String): [TorrentStats!]! @resolver
-}
-
-input TorrentsFilter {
-  infohash: StringFilter
-  name: StringFilter
-  bytesCompleted: IntFilter
-  bytesMissing: IntFilter
-  peersCount: IntFilter
-  priority: TorrentPriorityFilter
-}
-
-input TorrentPriorityFilter @oneOf {
-  eq: TorrentPriority
-  gt: TorrentPriority
-  lt: TorrentPriority
-  gte: TorrentPriority
-  lte: TorrentPriority
-  in: [TorrentPriority!]
-}
-
-input TorrentFilter @oneOf {
-  everything: Boolean
-  infohash: String
-  # pathGlob: String!
-}
diff --git a/daemons/atorrent/graphql/schema.graphql b/daemons/atorrent/graphql/schema.graphql
deleted file mode 100644
index 2284bb9..0000000
--- a/daemons/atorrent/graphql/schema.graphql
+++ /dev/null
@@ -1,21 +0,0 @@
-directive @oneOf on INPUT_OBJECT | FIELD_DEFINITION
-directive @resolver on INPUT_FIELD_DEFINITION | FIELD_DEFINITION
-
-directive @stream on FIELD_DEFINITION
-
-scalar DateTime
-scalar Upload
-scalar UInt
-
-type Schema {
-  query: Query
-  mutation: Mutation
-}
-
-type Query {
-  torrentDaemon: TorrentDaemonQuery @resolver
-}
-
-type Mutation {
-  torrentDaemon: TorrentDaemonMutation @resolver
-}
diff --git a/daemons/atorrent/graphql/types.graphql b/daemons/atorrent/graphql/types.graphql
deleted file mode 100644
index ed47cb7..0000000
--- a/daemons/atorrent/graphql/types.graphql
+++ /dev/null
@@ -1,80 +0,0 @@
-type TorrentFS implements Dir & FsEntry {
-  name: String!
-  torrent: Torrent!
-  entries: [FsEntry!]! @resolver
-}
-
-type TorrentFileEntry implements File & FsEntry {
-  name: String!
-  torrent: Torrent!
-  size: Int!
-}
-
-type TorrentProgress implements Progress {
-  torrent: Torrent!
-  current: Int!
-  total: Int!
-}
-
-type Torrent {
-  name: String! @resolver
-  infohash: String!
-  bytesCompleted: Int!
-  torrentFilePath: String!
-  bytesMissing: Int!
-  priority: TorrentPriority!
-  files: [TorrentFile!]! @resolver
-  excludedFiles: [TorrentFile!]! @resolver
-  peers: [TorrentPeer!]! @resolver
-}
-
-type TorrentFile {
-  filename: String!
-  size: Int!
-  bytesCompleted: Int!
-  priority: TorrentPriority! @resolver
-}
-
-type TorrentPeer {
-  ip: String!
-  downloadRate: Float!
-  discovery: String!
-  port: Int!
-  clientName: String!
-}
-
-enum TorrentPriority {
-  NONE
-  NORMAL
-  HIGH
-  READAHEAD
-  NOW
-}
-
-type TorrentClientStats {
-  bytesWritten: Int!
-  bytesWrittenData: Int!
-  bytesRead: Int!
-  bytesReadData: Int!
-  bytesReadUsefulData: Int!
-  bytesReadUsefulIntendedData: Int!
-
-  chunksWritten: Int!
-  chunksRead: Int!
-  chunksReadUseful: Int!
-  chunksReadWasted: Int!
-
-  metadataChunksRead: Int!
-
-  piecesDirtiedGood: Int!
-  piecesDirtiedBad: Int!
-}
-
-type TorrentStats {
-  timestamp: DateTime!
-  downloadedBytes: UInt!
-  uploadedBytes: UInt!
-  totalPeers: UInt!
-  activePeers: UInt!
-  connectedSeeders: UInt!
-}
diff --git a/daemons/atorrent/infobytes.go b/daemons/atorrent/infobytes.go
deleted file mode 100644
index fbcc8fe..0000000
--- a/daemons/atorrent/infobytes.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package atorrent
-
-import (
-	"bytes"
-	"errors"
-	"fmt"
-	"path/filepath"
-
-	"git.kmsign.ru/royalcat/tstor/src/logwrap"
-	"github.com/anacrolix/torrent/metainfo"
-	"github.com/anacrolix/torrent/types/infohash"
-	"github.com/dgraph-io/badger/v4"
-)
-
-var errNotFound = errors.New("not found")
-
-type infoBytesStore struct {
-	db *badger.DB
-}
-
-func newInfoBytesStore(metaDir string) (*infoBytesStore, error) {
-	opts := badger.
-		DefaultOptions(filepath.Join(metaDir, "infobytes")).
-		WithLogger(logwrap.BadgerLogger("torrent-client", "infobytes"))
-	db, err := badger.Open(opts)
-	if err != nil {
-		return nil, err
-	}
-	return &infoBytesStore{db}, nil
-}
-
-func (k *infoBytesStore) GetBytes(ih infohash.T) ([]byte, error) {
-	var data []byte
-	err := k.db.View(func(tx *badger.Txn) error {
-		item, err := tx.Get(ih.Bytes())
-		if err != nil {
-			if err == badger.ErrKeyNotFound {
-				return errNotFound
-			}
-
-			return fmt.Errorf("error getting value: %w", err)
-		}
-
-		data, err = item.ValueCopy(data)
-		return err
-	})
-	return data, err
-}
-
-func (k *infoBytesStore) Get(ih infohash.T) (*metainfo.MetaInfo, error) {
-	data, err := k.GetBytes(ih)
-	if err != nil {
-		return nil, err
-	}
-
-	return metainfo.Load(bytes.NewReader(data))
-}
-
-func (me *infoBytesStore) SetBytes(ih infohash.T, data []byte) error {
-	return me.db.Update(func(txn *badger.Txn) error {
-		item, err := txn.Get(ih.Bytes())
-		if err != nil {
-			if err == badger.ErrKeyNotFound {
-				return txn.Set(ih.Bytes(), data)
-			}
-			return err
-		}
-
-		return item.Value(func(val []byte) error {
-			if !bytes.Equal(val, data) {
-				return txn.Set(ih.Bytes(), data)
-			}
-			return nil
-		})
-	})
-}
-
-func (me *infoBytesStore) Set(ih infohash.T, info metainfo.MetaInfo) error {
-	return me.SetBytes(ih, info.InfoBytes)
-}
-
-func (k *infoBytesStore) Delete(ih infohash.T) error {
-	return k.db.Update(func(txn *badger.Txn) error {
-		return txn.Delete(ih.Bytes())
-	})
-}
-
-func (me *infoBytesStore) Close() error {
-	return me.db.Close()
-}
diff --git a/daemons/atorrent/metrics.go b/daemons/atorrent/metrics.go
deleted file mode 100644
index 4e1754e..0000000
--- a/daemons/atorrent/metrics.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package atorrent
-
-import (
-	"context"
-	"encoding/base64"
-
-	"github.com/anacrolix/dht/v2"
-	"github.com/anacrolix/torrent"
-	"go.opentelemetry.io/otel/attribute"
-	"go.opentelemetry.io/otel/metric"
-)
-
-func registerTorrentMetrics(client *torrent.Client) error {
-	meterTotalPeers, _ := meter.Int64ObservableGauge("torrent.peers.total")
-	meterActivePeers, _ := meter.Int64ObservableGauge("torrent.peers.active")
-	meterSeeders, _ := meter.Int64ObservableGauge("torrent.seeders")
-	meterDownloaded, _ := meter.Int64ObservableGauge("torrent.downloaded", metric.WithUnit("By"))
-	meterIO, _ := meter.Int64ObservableGauge("torrent.io", metric.WithUnit("By"))
-	meterLoaded, _ := meter.Int64ObservableGauge("torrent.loaded")
-
-	_, err := meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error {
-		o.ObserveInt64(meterLoaded, int64(len(client.Torrents())))
-
-		for _, v := range client.Torrents() {
-			as := attribute.NewSet(
-				attribute.String("infohash", v.InfoHash().HexString()),
-				attribute.String("name", v.Name()),
-				attribute.Int64("size", v.Length()),
-			)
-			stats := v.Stats()
-			o.ObserveInt64(meterTotalPeers, int64(stats.TotalPeers), metric.WithAttributeSet(as))
-			o.ObserveInt64(meterActivePeers, int64(stats.ActivePeers), metric.WithAttributeSet(as))
-			o.ObserveInt64(meterSeeders, int64(stats.ConnectedSeeders), metric.WithAttributeSet(as))
-			o.ObserveInt64(meterIO, stats.BytesRead.Int64(), metric.WithAttributeSet(as), metric.WithAttributes(attribute.String("direction", "download")))
-			o.ObserveInt64(meterIO, stats.BytesWritten.Int64(), metric.WithAttributeSet(as), metric.WithAttributes(attribute.String("direction", "upload")))
-			o.ObserveInt64(meterDownloaded, v.BytesCompleted(), metric.WithAttributeSet(as))
-		}
-
-		return nil
-	}, meterTotalPeers, meterActivePeers, meterSeeders, meterIO, meterDownloaded, meterLoaded)
-	if err != nil {
-		return err
-	}
-	return nil
-}
-
-func registerDhtMetrics(client *torrent.Client) error {
-	meterDhtNodes, _ := meter.Int64ObservableGauge("torrent.dht.nodes")
-
-	_, err := meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error {
-		servers := client.DhtServers()
-		for _, dhtSrv := range servers {
-			stats, ok := dhtSrv.Stats().(dht.ServerStats)
-			if !ok {
-				continue
-			}
-			id := dhtSrv.ID()
-			as := attribute.NewSet(
-				attribute.String("id", base64.StdEncoding.EncodeToString(id[:])),
-				attribute.String("address", dhtSrv.Addr().String()),
-			)
-			o.ObserveInt64(meterDhtNodes, int64(stats.Nodes), metric.WithAttributeSet(as))
-		}
-
-		return nil
-	}, meterDhtNodes)
-
-	return err
-}
diff --git a/daemons/atorrent/peer_store.go b/daemons/atorrent/peer_store.go
deleted file mode 100644
index 6f030e3..0000000
--- a/daemons/atorrent/peer_store.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package atorrent
-
-import (
-	"github.com/anacrolix/dht/v2/krpc"
-	peer_store "github.com/anacrolix/dht/v2/peer-store"
-	"github.com/anacrolix/torrent/types/infohash"
-	"github.com/royalcat/kv"
-)
-
-type peerStore struct {
-	store kv.Store[infohash.T, []krpc.NodeAddr]
-}
-
-var _ peer_store.Interface = (*peerStore)(nil)
-
-// AddPeer implements peer_store.Interface.
-func (p *peerStore) AddPeer(ih infohash.T, node krpc.NodeAddr) {
-	panic("unimplemented")
-}
-
-// GetPeers implements peer_store.Interface.
-func (p *peerStore) GetPeers(ih infohash.T) []krpc.NodeAddr {
-	panic("unimplemented")
-}
diff --git a/daemons/atorrent/piece_completion.go b/daemons/atorrent/piece_completion.go
deleted file mode 100644
index 013a0bb..0000000
--- a/daemons/atorrent/piece_completion.go
+++ /dev/null
@@ -1,137 +0,0 @@
-package atorrent
-
-import (
-	"context"
-	"encoding/binary"
-	"fmt"
-
-	"git.kmsign.ru/royalcat/tstor/src/logwrap"
-	"github.com/anacrolix/torrent/metainfo"
-	"github.com/anacrolix/torrent/storage"
-	"github.com/royalcat/kv"
-	"github.com/royalcat/kv/kvbadger"
-)
-
-type PieceCompletionState byte
-
-const (
-	PieceNotComplete PieceCompletionState = 0
-	PieceComplete    PieceCompletionState = 1<<8 - 1
-)
-
-var _ kv.Binary = (*PieceCompletionState)(nil)
-
-// MarshalBinary implements kv.Binary.
-func (p PieceCompletionState) MarshalBinary() (data []byte, err error) {
-	return []byte{byte(p)}, nil
-}
-
-// UnmarshalBinary implements kv.Binary.
-func (p *PieceCompletionState) UnmarshalBinary(data []byte) error {
-	if len(data) != 1 {
-		return fmt.Errorf("bad length")
-	}
-
-	switch PieceCompletionState(data[0]) {
-	case PieceComplete:
-		*p = PieceComplete
-	case PieceNotComplete:
-		*p = PieceNotComplete
-	default:
-		*p = PieceNotComplete
-	}
-
-	return nil
-}
-
-func pieceCompletionState(i bool) PieceCompletionState {
-	if i {
-		return PieceComplete
-	}
-	return PieceNotComplete
-}
-
-type pieceKey metainfo.PieceKey
-
-const pieceKeySize = metainfo.HashSize + 4
-
-var _ kv.Binary = (*pieceKey)(nil)
-
-// const delimeter rune = 0x1F
-
-// MarshalBinary implements kv.Binary.
-func (pk pieceKey) MarshalBinary() (data []byte, err error) {
-	key := make([]byte, 0, pieceKeySize)
-	key = append(key, pk.InfoHash.Bytes()...)
-	key = binary.BigEndian.AppendUint32(key, uint32(pk.Index))
-	return key, nil
-}
-
-// UnmarshalBinary implements kv.Binary.
-func (p *pieceKey) UnmarshalBinary(data []byte) error {
-	if len(data) < pieceKeySize {
-		return fmt.Errorf("data too short")
-	}
-	p.InfoHash = metainfo.Hash(data[:metainfo.HashSize])
-	p.Index = int(binary.BigEndian.Uint32(data[metainfo.HashSize:]))
-	return nil
-}
-
-type badgerPieceCompletion struct {
-	db kv.Store[pieceKey, PieceCompletionState]
-}
-
-var _ storage.PieceCompletion = (*badgerPieceCompletion)(nil)
-
-func newPieceCompletion(dir string) (storage.PieceCompletion, error) {
-	opts := kvbadger.DefaultOptions[PieceCompletionState](dir)
-	opts.Codec = kv.CodecBinary[PieceCompletionState, *PieceCompletionState]{}
-	opts.BadgerOptions = opts.BadgerOptions.WithLogger(logwrap.BadgerLogger("torrent-client", "piece-completion"))
-
-	db, err := kvbadger.NewBinaryKey[pieceKey, PieceCompletionState](opts)
-	if err != nil {
-		return nil, err
-	}
-
-	return &badgerPieceCompletion{
-		db: db,
-	}, nil
-}
-
-func (c *badgerPieceCompletion) Get(pk metainfo.PieceKey) (completion storage.Completion, err error) {
-	ctx := context.Background()
-
-	state, err := c.db.Get(ctx, pieceKey(pk))
-	if err != nil {
-		if err == kv.ErrKeyNotFound {
-			return completion, nil
-		}
-		return completion, err
-	}
-
-	if state == PieceComplete {
-		return storage.Completion{
-			Complete: true,
-			Ok:       true,
-		}, nil
-	}
-
-	return storage.Completion{
-		Complete: false,
-		Ok:       true,
-	}, nil
-}
-
-func (me badgerPieceCompletion) Set(pk metainfo.PieceKey, b bool) error {
-	ctx := context.Background()
-
-	if c, err := me.Get(pk); err == nil && c.Ok && c.Complete == b {
-		return nil
-	}
-
-	return me.db.Set(ctx, pieceKey(pk), pieceCompletionState(b))
-}
-
-func (me *badgerPieceCompletion) Close() error {
-	return me.db.Close(context.Background())
-}
diff --git a/daemons/atorrent/piece_completion_test.go b/daemons/atorrent/piece_completion_test.go
deleted file mode 100644
index c6acf0e..0000000
--- a/daemons/atorrent/piece_completion_test.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package atorrent
-
-import (
-	"testing"
-
-	"github.com/anacrolix/torrent/metainfo"
-	"github.com/anacrolix/torrent/storage"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-func TestBoltPieceCompletion(t *testing.T) {
-	td := t.TempDir()
-
-	pc, err := newPieceCompletion(td)
-	require.NoError(t, err)
-	defer pc.Close()
-
-	pk := metainfo.PieceKey{}
-
-	b, err := pc.Get(pk)
-	require.NoError(t, err)
-	assert.False(t, b.Ok)
-
-	require.NoError(t, pc.Set(pk, false))
-
-	b, err = pc.Get(pk)
-	require.NoError(t, err)
-	assert.Equal(t, storage.Completion{Complete: false, Ok: true}, b)
-
-	require.NoError(t, pc.Set(pk, true))
-
-	b, err = pc.Get(pk)
-	require.NoError(t, err)
-	assert.Equal(t, storage.Completion{Complete: true, Ok: true}, b)
-}
diff --git a/daemons/atorrent/queue.go b/daemons/atorrent/queue.go
deleted file mode 100644
index 2fcd004..0000000
--- a/daemons/atorrent/queue.go
+++ /dev/null
@@ -1,135 +0,0 @@
-package atorrent
-
-import (
-	"context"
-	"fmt"
-
-	"git.kmsign.ru/royalcat/tstor/pkg/uuid"
-	"github.com/anacrolix/torrent"
-	"github.com/anacrolix/torrent/types/infohash"
-)
-
-type DownloadTask struct {
-	ID       uuid.UUID
-	InfoHash infohash.T
-	File     string
-}
-
-func (s *Daemon) Download(ctx context.Context, task *DownloadTask) error {
-	t, ok := s.client.Torrent(task.InfoHash)
-	if !ok {
-		return fmt.Errorf("torrent with IH %s not found", task.InfoHash.HexString())
-	}
-
-	if task.File != "" {
-		var file *torrent.File
-		for _, tf := range t.Files() {
-			if tf.Path() == task.File {
-				file = tf
-				break
-			}
-		}
-
-		if file == nil {
-			return fmt.Errorf("file %s not found in torrent torrent with IH %s", task.File, task.InfoHash.HexString())
-		}
-
-		file.Download()
-	} else {
-		for _, file := range t.Files() {
-			file.Download()
-		}
-	}
-
-	return nil
-}
-
-// func (s *Service) DownloadAndWait(ctx context.Context, task *TorrentDownloadTask) error {
-// 	t, ok := s.c.Torrent(task.InfoHash)
-// 	if !ok {
-// 		return fmt.Errorf("torrent with IH %s not found", task.InfoHash.HexString())
-// 	}
-
-// 	if task.File != "" {
-// 		var file *torrent.File
-// 		for _, tf := range t.Files() {
-// 			if tf.Path() == task.File {
-// 				file = tf
-// 				break
-// 			}
-// 		}
-
-// 		if file == nil {
-// 			return fmt.Errorf("file %s not found in torrent torrent with IH %s", task.File, task.InfoHash.HexString())
-// 		}
-
-// 		file.Download()
-// 		return waitPieceRange(ctx, t, file.BeginPieceIndex(), file.EndPieceIndex())
-
-// 	}
-
-// 	t.DownloadAll()
-// 	select {
-// 	case <-ctx.Done():
-// 		return ctx.Err()
-// 	case <-t.Complete.On():
-// 		return nil
-// 	}
-// }
-
-// func waitPieceRange(ctx context.Context, t *torrent.Torrent, start, end int) error {
-// 	for i := start; i < end; i++ {
-// 		timer := time.NewTimer(time.Millisecond)
-// 		for {
-// 			select {
-// 			case <-ctx.Done():
-// 				return ctx.Err()
-// 			case <-timer.C:
-// 				if t.PieceState(i).Complete {
-// 					continue
-// 				}
-// 			}
-
-// 		}
-// 	}
-// 	return nil
-// }
-
-type TorrentProgress struct {
-	Torrent *Controller
-	Current int64
-	Total   int64
-}
-
-func (s *Daemon) DownloadProgress(ctx context.Context) (<-chan TorrentProgress, error) {
-	torrents, err := s.ListTorrents(ctx)
-	if err != nil {
-		return nil, err
-	}
-
-	out := make(chan TorrentProgress, 1)
-	go func() {
-		defer close(out)
-		for _, t := range torrents {
-			sub := t.Torrent().SubscribePieceStateChanges()
-			go func(t *Controller) {
-				for stateChange := range sub.Values {
-					if !stateChange.Complete && !stateChange.Partial {
-						continue
-					}
-
-					out <- TorrentProgress{
-						Torrent: t,
-						Current: t.BytesCompleted(),
-						Total:   t.Length(),
-					}
-				}
-			}(t)
-			defer sub.Close()
-		}
-
-		<-ctx.Done()
-	}()
-
-	return out, nil
-}
diff --git a/daemons/atorrent/setup.go b/daemons/atorrent/setup.go
deleted file mode 100644
index 04ff54d..0000000
--- a/daemons/atorrent/setup.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package atorrent
-
-import (
-	"fmt"
-	"os"
-	"path/filepath"
-
-	"git.kmsign.ru/royalcat/tstor/src/config"
-	"github.com/anacrolix/torrent/storage"
-)
-
-func setupStorage(cfg config.TorrentClient) (*fileStorage, storage.PieceCompletion, error) {
-	pcp := filepath.Join(cfg.MetadataFolder, "piece-completion")
-	if err := os.MkdirAll(pcp, 0744); err != nil {
-		return nil, nil, fmt.Errorf("error creating piece completion folder: %w", err)
-	}
-
-	// pc, err := storage.NewBoltPieceCompletion(pcp)
-	// if err != nil {
-	// 	return nil, nil, err
-	// }
-
-	pc, err := newPieceCompletion(pcp)
-	if err != nil {
-		return nil, nil, fmt.Errorf("error creating servers piece completion: %w", err)
-	}
-
-	// TODO implement cache/storage switching
-	// cacheDir := filepath.Join(tcfg.DataFolder, "cache")
-	// if err := os.MkdirAll(cacheDir, 0744); err != nil {
-	// 	return nil, nil, fmt.Errorf("error creating piece completion folder: %w", err)
-	// }
-	// fc, err := filecache.NewCache(cacheDir)
-	// if err != nil {
-	// 	return nil, nil, fmt.Errorf("error creating cache: %w", err)
-	// }
-	// log.Info().Msg(fmt.Sprintf("setting cache size to %d MB", 1024))
-	// fc.SetCapacity(1024 * 1024 * 1024)
-
-	// rp := storage.NewResourcePieces(fc.AsResourceProvider())
-	// st := &stc{rp}
-
-	filesDir := cfg.DataFolder
-	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(piecesDir, pc)
-
-	return st, pc, nil
-}
diff --git a/daemons/atorrent/stats.go b/daemons/atorrent/stats.go
deleted file mode 100644
index 2451d82..0000000
--- a/daemons/atorrent/stats.go
+++ /dev/null
@@ -1,207 +0,0 @@
-package atorrent
-
-import (
-	"context"
-	"encoding/json"
-	"path"
-	"slices"
-	"time"
-
-	"git.kmsign.ru/royalcat/tstor/src/logwrap"
-	"github.com/anacrolix/torrent/types/infohash"
-	"github.com/dgraph-io/badger/v4"
-)
-
-func newStatsStore(metaDir string, lifetime time.Duration) (*statsStore, error) {
-	db, err := badger.OpenManaged(
-		badger.
-			DefaultOptions(path.Join(metaDir, "stats")).
-			WithNumVersionsToKeep(int(^uint(0) >> 1)).
-			WithLogger(logwrap.BadgerLogger("stats")), // Infinity
-	)
-	if err != nil {
-		return nil, err
-	}
-
-	go func() {
-		for n := range time.NewTimer(lifetime / 2).C {
-			db.SetDiscardTs(uint64(n.Add(-lifetime).Unix()))
-		}
-	}()
-	return &statsStore{
-		db: db,
-	}, nil
-}
-
-type statsStore struct {
-	db *badger.DB
-}
-
-type TorrentStats struct {
-	Timestamp        time.Time
-	DownloadedBytes  uint64
-	UploadedBytes    uint64
-	TotalPeers       uint16
-	ActivePeers      uint16
-	ConnectedSeeders uint16
-}
-
-func (s TorrentStats) Same(o TorrentStats) bool {
-	return s.DownloadedBytes == o.DownloadedBytes &&
-		s.UploadedBytes == o.UploadedBytes &&
-		s.TotalPeers == o.TotalPeers &&
-		s.ActivePeers == o.ActivePeers &&
-		s.ConnectedSeeders == o.ConnectedSeeders
-}
-
-func (r *statsStore) addStats(key []byte, stat TorrentStats) error {
-	ts := uint64(stat.Timestamp.Unix())
-
-	txn := r.db.NewTransactionAt(ts, true)
-	defer txn.Discard()
-
-	item, err := txn.Get(key)
-	if err != nil && err != badger.ErrKeyNotFound {
-		return err
-	}
-
-	if err != badger.ErrKeyNotFound {
-		var prevStats TorrentStats
-		err = item.Value(func(val []byte) error {
-			return json.Unmarshal(val, &prevStats)
-		})
-		if err != nil {
-			return err
-		}
-
-		if prevStats.Same(stat) {
-			return nil
-		}
-	}
-
-	data, err := json.Marshal(stat)
-	if err != nil {
-		return err
-	}
-	err = txn.Set(key, data)
-	if err != nil {
-		return err
-	}
-
-	return txn.CommitAt(ts, nil)
-}
-
-func (r *statsStore) AddTorrentStats(ih infohash.T, stat TorrentStats) error {
-	return r.addStats(ih.Bytes(), stat)
-}
-
-const totalKey = "total"
-
-func (r *statsStore) AddTotalStats(stat TorrentStats) error {
-	return r.addStats([]byte(totalKey), stat)
-}
-
-func (r *statsStore) ReadTotalStatsHistory(ctx context.Context, since time.Time) ([]TorrentStats, error) {
-	stats := []TorrentStats{}
-
-	err := r.db.View(func(txn *badger.Txn) error {
-		opts := badger.DefaultIteratorOptions
-		opts.AllVersions = true
-		opts.SinceTs = uint64(since.Unix())
-
-		it := txn.NewKeyIterator([]byte(totalKey), opts)
-		defer it.Close()
-		for it.Rewind(); it.Valid(); it.Next() {
-			item := it.Item()
-			var stat TorrentStats
-			err := item.Value(func(v []byte) error {
-				return json.Unmarshal(v, &stat)
-			})
-			if err != nil {
-				return err
-			}
-
-			stats = append(stats, stat)
-		}
-		return nil
-	})
-	if err != nil {
-		return nil, err
-	}
-
-	slices.SortFunc(stats, func(a, b TorrentStats) int {
-		return a.Timestamp.Compare(b.Timestamp)
-	})
-	stats = slices.Compact(stats)
-	return stats, nil
-}
-
-func (r *statsStore) ReadTorrentStatsHistory(ctx context.Context, since time.Time, ih infohash.T) ([]TorrentStats, error) {
-	stats := []TorrentStats{}
-
-	err := r.db.View(func(txn *badger.Txn) error {
-		opts := badger.DefaultIteratorOptions
-		opts.AllVersions = true
-		opts.SinceTs = uint64(since.Unix())
-
-		it := txn.NewKeyIterator(ih.Bytes(), opts)
-		defer it.Close()
-		for it.Rewind(); it.Valid(); it.Next() {
-			item := it.Item()
-			var stat TorrentStats
-			err := item.Value(func(v []byte) error {
-				return json.Unmarshal(v, &stat)
-			})
-			if err != nil {
-				return err
-			}
-
-			stats = append(stats, stat)
-		}
-		return nil
-	})
-	if err != nil {
-		return nil, err
-	}
-
-	slices.SortFunc(stats, func(a, b TorrentStats) int {
-		return a.Timestamp.Compare(b.Timestamp)
-	})
-	stats = slices.Compact(stats)
-	return stats, nil
-}
-
-func (r *statsStore) ReadStatsHistory(ctx context.Context, since time.Time) ([]TorrentStats, error) {
-	stats := []TorrentStats{}
-
-	err := r.db.View(func(txn *badger.Txn) error {
-		opts := badger.DefaultIteratorOptions
-		opts.AllVersions = true
-		opts.SinceTs = uint64(since.Unix())
-
-		it := txn.NewIterator(opts)
-		defer it.Close()
-		for it.Rewind(); it.Valid(); it.Next() {
-			item := it.Item()
-			var stat TorrentStats
-			err := item.Value(func(v []byte) error {
-				return json.Unmarshal(v, &stat)
-			})
-			if err != nil {
-				return err
-			}
-
-			stats = append(stats, stat)
-		}
-		return nil
-	})
-	if err != nil {
-		return nil, err
-	}
-
-	slices.SortFunc(stats, func(a, b TorrentStats) int {
-		return a.Timestamp.Compare(b.Timestamp)
-	})
-	stats = slices.Compact(stats)
-	return stats, nil
-}
diff --git a/daemons/atorrent/storage.go b/daemons/atorrent/storage.go
deleted file mode 100644
index c805c20..0000000
--- a/daemons/atorrent/storage.go
+++ /dev/null
@@ -1,196 +0,0 @@
-package atorrent
-
-import (
-	"context"
-	"errors"
-	"io/fs"
-	"log/slog"
-	"os"
-	"path"
-	"path/filepath"
-	"slices"
-
-	"git.kmsign.ru/royalcat/tstor/pkg/rlog"
-	"github.com/anacrolix/torrent"
-	"github.com/anacrolix/torrent/metainfo"
-	"github.com/anacrolix/torrent/storage"
-)
-
-// NewFileStorage creates a new ClientImplCloser that stores files using the OS native filesystem.
-func NewFileStorage(baseDir string, pc storage.PieceCompletion) *fileStorage {
-	return &fileStorage{
-		client: storage.NewFileOpts(storage.NewFileClientOpts{
-			ClientBaseDir:   baseDir,
-			PieceCompletion: pc,
-			TorrentDirMaker: func(baseDir string, info *metainfo.Info, infoHash metainfo.Hash) string {
-				return torrentDir(baseDir, infoHash)
-			},
-			FilePathMaker: func(opts storage.FilePathMakerOpts) string {
-				return filePath(*opts.File)
-			},
-		}),
-		baseDir:         baseDir,
-		pieceCompletion: pc,
-		dupIndex:        newDupIndex(),
-		log:             rlog.Component("daemon", "torrent"),
-	}
-}
-
-// File-based storage for torrents, that isn't yet bound to a particular torrent.
-type fileStorage struct {
-	baseDir         string
-	client          storage.ClientImplCloser
-	pieceCompletion storage.PieceCompletion
-	dupIndex        *dupIndex
-	log             *rlog.Logger
-}
-
-var _ storage.ClientImplCloser = (*fileStorage)(nil)
-
-func (me *fileStorage) Close() error {
-	return errors.Join(
-		me.client.Close(),
-		me.pieceCompletion.Close(),
-	)
-}
-
-func (fs *fileStorage) fullFilePath(infoHash metainfo.Hash, fileInfo metainfo.FileInfo) string {
-	return filepath.Join(
-		torrentDir(fs.baseDir, infoHash),
-		filePath(fileInfo),
-	)
-}
-
-func (fs *fileStorage) DeleteFile(file *torrent.File) error {
-	infoHash := file.Torrent().InfoHash()
-	torrentDir := torrentDir(fs.baseDir, infoHash)
-	fileInfo := file.FileInfo()
-	relFilePath := filePath(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)
-}
-
-func (fs *fileStorage) CleanupDirs(ctx context.Context, expected []*Controller, dryRun bool) ([]string, error) {
-	log := fs.log.With(slog.Int("expectedTorrents", len(expected)), slog.Bool("dryRun", dryRun))
-
-	expectedEntries := []string{}
-	for _, e := range expected {
-		expectedEntries = append(expectedEntries, e.Torrent().InfoHash().HexString())
-	}
-
-	entries, err := os.ReadDir(fs.baseDir)
-	if err != nil {
-		return nil, err
-	}
-
-	toDelete := []string{}
-	for _, v := range entries {
-		if !slices.Contains(expectedEntries, v.Name()) {
-			toDelete = append(toDelete, v.Name())
-		}
-	}
-
-	if ctx.Err() != nil {
-		return nil, ctx.Err()
-	}
-
-	log.Info(ctx, "deleting trash data", slog.Int("dirsCount", len(toDelete)))
-	if !dryRun {
-		for i, name := range toDelete {
-			p := path.Join(fs.baseDir, name)
-			log.Warn(ctx, "deleting trash data", slog.String("path", p))
-			err := os.RemoveAll(p)
-			if err != nil {
-				return toDelete[:i], err
-			}
-		}
-	}
-
-	return toDelete, nil
-}
-
-func (s *fileStorage) CleanupFiles(ctx context.Context, expected []*Controller, dryRun bool) ([]string, error) {
-	log := s.log.With(slog.Int("expectedTorrents", len(expected)), slog.Bool("dryRun", dryRun))
-
-	expectedEntries := []string{}
-	{
-		for _, e := range expected {
-			files, err := e.Files(ctx)
-			if err != nil {
-				return nil, err
-			}
-
-			for _, f := range files {
-				expectedEntries = append(expectedEntries, s.fullFilePath(e.Torrent().InfoHash(), f.FileInfo()))
-			}
-		}
-	}
-
-	entries := []string{}
-	err := filepath.WalkDir(s.baseDir,
-		func(path string, info fs.DirEntry, err error) error {
-			if err != nil {
-				return err
-			}
-			if ctx.Err() != nil {
-				return ctx.Err()
-			}
-
-			if info.IsDir() {
-				return nil
-			}
-			entries = append(entries, path)
-			return nil
-		})
-	if err != nil {
-		return nil, err
-	}
-
-	toDelete := []string{}
-	for _, v := range entries {
-		if !slices.Contains(expectedEntries, v) {
-			toDelete = append(toDelete, v)
-		}
-	}
-
-	if ctx.Err() != nil {
-		return toDelete, ctx.Err()
-	}
-
-	log.Info(ctx, "deleting trash data", slog.Int("filesCount", len(toDelete)))
-	if !dryRun {
-		for i, p := range toDelete {
-			s.log.Warn(ctx, "deleting trash data", slog.String("path", p))
-			err := os.Remove(p)
-			if err != nil {
-				return toDelete[i:], err
-			}
-		}
-	}
-	return toDelete, nil
-}
-
-func (s *fileStorage) iterFiles(ctx context.Context, iter func(ctx context.Context, path string, entry fs.FileInfo) error) error {
-	return filepath.Walk(s.baseDir,
-		func(path string, info fs.FileInfo, err error) error {
-			if err != nil {
-				return err
-			}
-			if ctx.Err() != nil {
-				return ctx.Err()
-			}
-
-			if info.IsDir() {
-				return nil
-			}
-
-			return iter(ctx, path, info)
-		})
-}
diff --git a/daemons/atorrent/storage_dedupe.go b/daemons/atorrent/storage_dedupe.go
deleted file mode 100644
index e8f91a1..0000000
--- a/daemons/atorrent/storage_dedupe.go
+++ /dev/null
@@ -1,225 +0,0 @@
-package atorrent
-
-import (
-	"context"
-	"crypto/sha1"
-	"fmt"
-	"io"
-	"io/fs"
-	"log/slog"
-	"os"
-	"path/filepath"
-	"slices"
-
-	"git.kmsign.ru/royalcat/tstor/pkg/rlog"
-	"github.com/dustin/go-humanize"
-	"go.opentelemetry.io/otel/attribute"
-	"go.opentelemetry.io/otel/trace"
-	"golang.org/x/exp/maps"
-	"golang.org/x/sys/unix"
-)
-
-func (s *fileStorage) Dedupe(ctx context.Context) (uint64, error) {
-	ctx, span := tracer.Start(ctx, fmt.Sprintf("Dedupe"))
-	defer span.End()
-
-	log := s.log
-
-	sizeMap := map[int64][]string{}
-	err := s.iterFiles(ctx, func(ctx context.Context, path string, info fs.FileInfo) error {
-		size := info.Size()
-		sizeMap[size] = append(sizeMap[size], path)
-		return nil
-	})
-	if err != nil {
-		return 0, err
-	}
-
-	maps.DeleteFunc(sizeMap, func(k int64, v []string) bool {
-		return len(v) <= 1
-	})
-
-	span.AddEvent("collected files with same size", trace.WithAttributes(
-		attribute.Int("count", len(sizeMap)),
-	))
-
-	var deduped uint64 = 0
-
-	i := 0
-	for _, paths := range sizeMap {
-		if i%100 == 0 {
-			log.Info(ctx, "deduping in progress", slog.Int("current", i), slog.Int("total", len(sizeMap)))
-		}
-		i++
-
-		if ctx.Err() != nil {
-			return deduped, ctx.Err()
-		}
-
-		slices.Sort(paths)
-		paths = slices.Compact(paths)
-		if len(paths) <= 1 {
-			continue
-		}
-
-		paths, err = applyErr(paths, filepath.Abs)
-		if err != nil {
-			return deduped, err
-		}
-
-		dedupedGroup, err := s.dedupeFiles(ctx, paths)
-		if err != nil {
-			log.Error(ctx, "Error applying dedupe", slog.Any("files", paths), rlog.Error(err))
-			continue
-		}
-
-		if dedupedGroup > 0 {
-			deduped += dedupedGroup
-			log.Info(ctx, "deduped file group",
-				slog.String("files", fmt.Sprint(paths)),
-				slog.String("deduped", humanize.Bytes(dedupedGroup)),
-				slog.String("deduped_total", humanize.Bytes(deduped)),
-			)
-		}
-
-	}
-
-	return deduped, nil
-}
-
-func applyErr[E, O any](in []E, apply func(E) (O, error)) ([]O, error) {
-	out := make([]O, 0, len(in))
-	for _, p := range in {
-		o, err := apply(p)
-		if err != nil {
-			return out, err
-		}
-		out = append(out, o)
-
-	}
-	return out, nil
-}
-
-// const blockSize uint64 = 4096
-
-func (s *fileStorage) dedupeFiles(ctx context.Context, paths []string) (deduped uint64, err error) {
-	ctx, span := tracer.Start(ctx, fmt.Sprintf("dedupeFiles"), trace.WithAttributes(
-		attribute.StringSlice("files", paths),
-	))
-	defer func() {
-		span.SetAttributes(attribute.Int64("deduped", int64(deduped)))
-		if err != nil {
-			span.RecordError(err)
-		}
-		span.End()
-	}()
-
-	log := s.log
-
-	srcF, err := os.Open(paths[0])
-	if err != nil {
-		return deduped, fmt.Errorf("error opening file %s: %w", paths[0], err)
-	}
-	defer srcF.Close()
-	srcStat, err := srcF.Stat()
-	if err != nil {
-		return deduped, fmt.Errorf("error stat file %s: %w", paths[0], err)
-	}
-
-	srcFd := int(srcF.Fd())
-	srcSize := srcStat.Size()
-
-	fsStat := unix.Statfs_t{}
-	err = unix.Fstatfs(srcFd, &fsStat)
-	if err != nil {
-		span.RecordError(err)
-		return deduped, fmt.Errorf("error statfs file %s: %w", paths[0], err)
-	}
-
-	srcHash, err := filehash(srcF)
-	if err != nil {
-		return deduped, fmt.Errorf("error hashing file %s: %w", paths[0], err)
-	}
-
-	if int64(fsStat.Bsize) > srcSize { // for btrfs it means file in residing in not deduplicatable metadata
-		return deduped, nil
-	}
-
-	blockSize := uint64((srcSize % int64(fsStat.Bsize)) * int64(fsStat.Bsize))
-
-	span.SetAttributes(attribute.Int64("blocksize", int64(blockSize)))
-
-	rng := unix.FileDedupeRange{
-		Src_offset: 0,
-		Src_length: blockSize,
-		Info:       []unix.FileDedupeRangeInfo{},
-	}
-
-	for _, dst := range paths[1:] {
-		if ctx.Err() != nil {
-			return deduped, ctx.Err()
-		}
-
-		destF, err := os.OpenFile(dst, os.O_RDWR, os.ModePerm)
-		if err != nil {
-			return deduped, fmt.Errorf("error opening file %s: %w", dst, err)
-		}
-		defer destF.Close()
-
-		dstHash, err := filehash(destF)
-		if err != nil {
-			return deduped, fmt.Errorf("error hashing file %s: %w", dst, err)
-		}
-
-		if srcHash != dstHash {
-			destF.Close()
-			continue
-		}
-
-		rng.Info = append(rng.Info, unix.FileDedupeRangeInfo{
-			Dest_fd:     int64(destF.Fd()),
-			Dest_offset: 0,
-		})
-	}
-
-	if len(rng.Info) == 0 {
-		return deduped, nil
-	}
-
-	log.Info(ctx, "found same files, deduping", slog.Any("files", paths), slog.String("size", humanize.Bytes(uint64(srcStat.Size()))))
-
-	if ctx.Err() != nil {
-		return deduped, ctx.Err()
-	}
-
-	rng.Src_offset = 0
-	for i := range rng.Info {
-		rng.Info[i].Dest_offset = 0
-	}
-
-	err = unix.IoctlFileDedupeRange(srcFd, &rng)
-	if err != nil {
-		return deduped, fmt.Errorf("error calling FIDEDUPERANGE: %w", err)
-	}
-
-	for i := range rng.Info {
-		deduped += rng.Info[i].Bytes_deduped
-
-		rng.Info[i].Status = 0
-		rng.Info[i].Bytes_deduped = 0
-	}
-
-	return deduped, nil
-}
-
-const compareBlockSize = 1024 * 128
-
-func filehash(r io.Reader) ([20]byte, error) {
-	buf := make([]byte, compareBlockSize)
-	_, err := r.Read(buf)
-	if err != nil && err != io.EOF {
-		return [20]byte{}, err
-	}
-
-	return sha1.Sum(buf), nil
-}
diff --git a/daemons/atorrent/storage_open.go b/daemons/atorrent/storage_open.go
deleted file mode 100644
index 4c8eb66..0000000
--- a/daemons/atorrent/storage_open.go
+++ /dev/null
@@ -1,179 +0,0 @@
-package atorrent
-
-import (
-	"context"
-	"errors"
-	"fmt"
-	"log/slog"
-	"os"
-	"path/filepath"
-	"slices"
-	"strings"
-
-	"git.kmsign.ru/royalcat/tstor/pkg/cowutils"
-	"git.kmsign.ru/royalcat/tstor/pkg/rlog"
-	"github.com/anacrolix/torrent/metainfo"
-	"github.com/anacrolix/torrent/storage"
-	"github.com/anacrolix/torrent/types/infohash"
-	"github.com/royalcat/kv"
-)
-
-// OpenTorrent implements storage.ClientImplCloser.
-func (me *fileStorage) OpenTorrent(ctx context.Context, info *metainfo.Info, infoHash infohash.T) (storage.TorrentImpl, error) {
-	ctx, span := tracer.Start(ctx, "OpenTorrent")
-	defer span.End()
-	log := me.log.With(slog.String("infohash", infoHash.HexString()), slog.String("name", info.BestName()))
-
-	log.Debug(ctx, "opening torrent")
-
-	impl, err := me.client.OpenTorrent(ctx, info, infoHash)
-	if err != nil {
-		log.Error(ctx, "error opening torrent", rlog.Error(err))
-	}
-	return impl, err
-}
-
-func (me *fileStorage) copyDup(ctx context.Context, infoHash infohash.T, dup dupInfo) error {
-	log := me.log.With(slog.String("infohash", infoHash.HexString()), slog.String("dup_infohash", dup.infohash.HexString()))
-
-	srcPath := me.fullFilePath(dup.infohash, dup.fileinfo)
-	src, err := os.Open(me.fullFilePath(dup.infohash, dup.fileinfo))
-	if err != nil {
-		return err
-	}
-
-	dstPath := me.fullFilePath(infoHash, dup.fileinfo)
-	dst, err := os.OpenFile(dstPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
-	if err != nil {
-		return err
-	}
-
-	log.Info(ctx, "copying duplicate file", slog.String("src", srcPath), slog.String("dst", dstPath))
-
-	err = cowutils.Reflink(ctx, dst, src, true)
-	if err != nil {
-		return fmt.Errorf("error copying file: %w", err)
-	}
-
-	return nil
-}
-
-func torrentDir(baseDir string, infoHash metainfo.Hash) string {
-	return filepath.Join(baseDir, infoHash.HexString())
-}
-
-func filePath(file metainfo.FileInfo) string {
-	return filepath.Join(file.BestPath()...)
-}
-
-func (s *Daemon) checkTorrentCompatable(ctx context.Context, ih infohash.T, info metainfo.Info) (compatable bool, tryLater bool, err error) {
-	log := s.log.With(
-		slog.String("new-name", info.BestName()),
-		slog.String("new-infohash", ih.String()),
-	)
-
-	name := info.BestName()
-
-	aq, err := s.dirsAquire.Get(ctx, info.BestName())
-	if errors.Is(err, kv.ErrKeyNotFound) {
-		err = s.dirsAquire.Set(ctx, name, DirAquire{
-			Name:   name,
-			Hashes: slices.Compact([]infohash.T{ih}),
-		})
-		if err != nil {
-			return false, false, err
-		}
-
-		log.Debug(ctx, "acquiring was not found, so created")
-		return true, false, nil
-	} else if err != nil {
-		return false, false, err
-	}
-
-	if slices.Contains(aq.Hashes, ih) {
-		log.Debug(ctx, "hash already know to be compatable")
-		return true, false, nil
-	}
-
-	for _, existingTorrent := range s.client.Torrents() {
-		if existingTorrent.Name() != name || existingTorrent.InfoHash() == ih {
-			continue
-		}
-
-		existingInfo := existingTorrent.Info()
-
-		existingFiles := slices.Clone(existingInfo.Files)
-		newFiles := slices.Clone(info.Files)
-
-		if !s.checkTorrentFilesCompatable(ctx, aq, existingFiles, newFiles) {
-			return false, false, nil
-		}
-
-		aq.Hashes = slicesUnique(append(aq.Hashes, ih))
-		err = s.dirsAquire.Set(ctx, aq.Name, aq)
-		if err != nil {
-			log.Warn(ctx, "torrent not compatible")
-			return false, false, err
-		}
-
-	}
-	if slices.Contains(aq.Hashes, ih) {
-		log.Debug(ctx, "hash is compatable")
-		return true, false, nil
-	}
-
-	log.Debug(ctx, "torrent with same name not found, try later")
-	return false, true, nil
-}
-
-func (s *Daemon) checkTorrentFilesCompatable(ctx context.Context, aq DirAquire, existingFiles, newFiles []metainfo.FileInfo) bool {
-	log := s.log.With(slog.String("name", aq.Name))
-
-	pathCmp := func(a, b metainfo.FileInfo) int {
-		return slices.Compare(a.BestPath(), b.BestPath())
-	}
-	slices.SortStableFunc(existingFiles, pathCmp)
-	slices.SortStableFunc(newFiles, pathCmp)
-
-	// torrents basically equals
-	if slices.EqualFunc(existingFiles, newFiles, func(fi1, fi2 metainfo.FileInfo) bool {
-		return fi1.Length == fi2.Length && slices.Equal(fi1.BestPath(), fi1.BestPath())
-	}) {
-		return true
-	}
-
-	if len(newFiles) > len(existingFiles) {
-		type fileInfo struct {
-			Path   string
-			Length int64
-		}
-		mapInfo := func(fi metainfo.FileInfo) fileInfo {
-			return fileInfo{
-				Path:   strings.Join(fi.BestPath(), "/"),
-				Length: fi.Length,
-			}
-		}
-
-		existingFiles := apply(existingFiles, mapInfo)
-		newFiles := apply(newFiles, mapInfo)
-
-		for _, n := range newFiles {
-			if slices.Contains(existingFiles, n) {
-				continue
-			}
-
-			for _, e := range existingFiles {
-				if e.Path == n.Path && e.Length != n.Length {
-					log.Warn(ctx, "torrents not compatible, has files with different length",
-						slog.String("path", n.Path),
-						slog.Int64("existing-length", e.Length),
-						slog.Int64("new-length", e.Length),
-					)
-					return false
-				}
-			}
-		}
-	}
-
-	return true
-}