2024-05-19 21:36:22 +00:00
|
|
|
package torrent
|
2023-12-21 23:15:39 +00:00
|
|
|
|
|
|
|
import (
|
2024-07-08 21:19:04 +00:00
|
|
|
"context"
|
2023-12-21 23:15:39 +00:00
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
|
|
|
|
2024-01-07 17:09:56 +00:00
|
|
|
dlog "git.kmsign.ru/royalcat/tstor/src/log"
|
2023-12-21 23:15:39 +00:00
|
|
|
"github.com/anacrolix/torrent/metainfo"
|
|
|
|
"github.com/anacrolix/torrent/storage"
|
2024-07-08 21:19:04 +00:00
|
|
|
"github.com/royalcat/kv"
|
|
|
|
"github.com/royalcat/kv/kvbadger"
|
2023-12-21 23:15:39 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type PieceCompletionState byte
|
|
|
|
|
|
|
|
const (
|
|
|
|
PieceNotComplete PieceCompletionState = 0
|
|
|
|
PieceComplete PieceCompletionState = 1<<8 - 1
|
|
|
|
)
|
|
|
|
|
2024-07-08 21:19:04 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2023-12-21 23:15:39 +00:00
|
|
|
func pieceCompletionState(i bool) PieceCompletionState {
|
|
|
|
if i {
|
|
|
|
return PieceComplete
|
|
|
|
}
|
2024-07-08 21:19:04 +00:00
|
|
|
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
|
2023-12-21 23:15:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type badgerPieceCompletion struct {
|
2024-07-08 21:19:04 +00:00
|
|
|
db kv.Store[pieceKey, PieceCompletionState]
|
2023-12-21 23:15:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ storage.PieceCompletion = (*badgerPieceCompletion)(nil)
|
|
|
|
|
2024-05-19 21:36:22 +00:00
|
|
|
func newPieceCompletion(dir string) (storage.PieceCompletion, error) {
|
2024-07-08 21:19:04 +00:00
|
|
|
opts := kvbadger.DefaultOptions[PieceCompletionState](dir)
|
|
|
|
opts.Codec = kv.CodecBinary[PieceCompletionState, *PieceCompletionState]{}
|
|
|
|
opts.BadgerOptions = opts.BadgerOptions.WithLogger(dlog.BadgerLogger("torrent-client", "piece-completion"))
|
|
|
|
|
|
|
|
db, err := kvbadger.NewBagerKVBinaryKey[pieceKey, PieceCompletionState](opts)
|
2023-12-21 23:15:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-07-08 21:19:04 +00:00
|
|
|
return &badgerPieceCompletion{
|
|
|
|
db: db,
|
|
|
|
}, nil
|
2023-12-21 23:15:39 +00:00
|
|
|
}
|
|
|
|
|
2024-07-08 21:19:04 +00:00
|
|
|
func (c *badgerPieceCompletion) Get(pk metainfo.PieceKey) (completion storage.Completion, err error) {
|
|
|
|
ctx := context.Background()
|
2023-12-21 23:15:39 +00:00
|
|
|
|
2024-07-08 21:19:04 +00:00
|
|
|
state, err := c.db.Get(ctx, pieceKey(pk))
|
|
|
|
if err != nil {
|
|
|
|
if err == kv.ErrKeyNotFound {
|
|
|
|
return completion, nil
|
2023-12-21 23:15:39 +00:00
|
|
|
}
|
2024-07-08 21:19:04 +00:00
|
|
|
return completion, err
|
|
|
|
}
|
2023-12-21 23:15:39 +00:00
|
|
|
|
2024-07-08 21:19:04 +00:00
|
|
|
if state == PieceComplete {
|
|
|
|
return storage.Completion{
|
|
|
|
Complete: true,
|
|
|
|
Ok: true,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return storage.Completion{
|
|
|
|
Complete: false,
|
|
|
|
Ok: true,
|
|
|
|
}, nil
|
2023-12-21 23:15:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (me badgerPieceCompletion) Set(pk metainfo.PieceKey, b bool) error {
|
2024-07-08 21:19:04 +00:00
|
|
|
ctx := context.Background()
|
|
|
|
|
2023-12-21 23:15:39 +00:00
|
|
|
if c, err := me.Get(pk); err == nil && c.Ok && c.Complete == b {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-07-08 21:19:04 +00:00
|
|
|
return me.db.Set(ctx, pieceKey(pk), pieceCompletionState(b))
|
2023-12-21 23:15:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (me *badgerPieceCompletion) Close() error {
|
2024-07-08 21:19:04 +00:00
|
|
|
return me.db.Close(context.Background())
|
2023-12-21 23:15:39 +00:00
|
|
|
}
|