tstor/src/sources/qbittorrent/client.go

105 lines
2.2 KiB
Go
Raw Normal View History

package qbittorrent
import (
"context"
"fmt"
"slices"
"time"
2024-08-31 23:00:13 +00:00
"git.kmsign.ru/royalcat/tstor/pkg/qbittorrent"
)
2024-08-31 23:00:13 +00:00
type cacheClient struct {
qb qbittorrent.Client
}
2024-08-31 23:00:13 +00:00
func wrapClient(qb qbittorrent.Client) *cacheClient {
return &cacheClient{qb: qb}
}
2024-08-31 23:00:13 +00:00
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
}
2024-08-31 23:00:13 +00:00
contentI := slices.IndexFunc(contents, func(c *qbittorrent.TorrentContent) bool {
return c.Index == contentIndex
})
2024-08-31 23:00:13 +00:00
if contentI == -1 {
return nil, fmt.Errorf("content not found")
}
2024-08-31 23:00:13 +00:00
return contents[contentI], nil
}
2024-08-31 23:00:13 +00:00
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
}
2024-08-31 23:00:13 +00:00
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
}
}
}
}