package qbittorrent import ( "context" "fmt" "slices" "time" "git.kmsign.ru/royalcat/tstor/pkg/qbittorrent" ) type cacheClient struct { qb qbittorrent.Client } func wrapClient(qb qbittorrent.Client) *cacheClient { return &cacheClient{qb: qb} } var errNotFound = fmt.Errorf("not found") func (f *cacheClient) getProperties(ctx context.Context, hash string) (*qbittorrent.TorrentProperties, error) { info, err := f.qb.Torrent().GetProperties(ctx, hash) if err != nil { return nil, err } return info, nil } func (f *cacheClient) listContent(ctx context.Context, hash string) ([]*qbittorrent.TorrentContent, error) { contents, err := f.qb.Torrent().GetContents(ctx, hash) if err != nil { return nil, err } return contents, nil } func (f *cacheClient) getContent(ctx context.Context, hash string, contentIndex int) (*qbittorrent.TorrentContent, error) { contents, err := f.qb.Torrent().GetContents(ctx, hash, contentIndex) if err != nil { return nil, err } contentI := slices.IndexFunc(contents, func(c *qbittorrent.TorrentContent) bool { return c.Index == contentIndex }) if contentI == -1 { return nil, fmt.Errorf("content not found") } return contents[contentI], nil } func (f *cacheClient) isPieceComplete(ctx context.Context, hash string, pieceIndex int) (bool, error) { completion, err := f.qb.Torrent().GetPiecesStates(ctx, hash) if err != nil { return false, err } if completion[pieceIndex] == 2 { return true, nil } return false, nil } func (f *cacheClient) waitPieceToComplete(ctx context.Context, hash string, pieceIndex int) error { const checkingInterval = 1 * time.Second ok, err := f.isPieceComplete(ctx, hash, pieceIndex) if err != nil { return err } if ok { return nil } if deadline, ok := ctx.Deadline(); ok && time.Until(deadline) < checkingInterval { return context.DeadlineExceeded } ticker := time.NewTicker(checkingInterval) defer ticker.Stop() for { select { case <-ctx.Done(): return ctx.Err() case <-ticker.C: ok, err := f.isPieceComplete(ctx, hash, pieceIndex) if err != nil { return err } if ok { return nil } if deadline, ok := ctx.Deadline(); ok && time.Until(deadline) < checkingInterval { return context.DeadlineExceeded } } } }