tstor/src/sources/torrent/piece_completion.go

138 lines
3.1 KiB
Go
Raw Normal View History

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
}