mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-08 09:30:27 +00:00
110 lines
2.3 KiB
Go
110 lines
2.3 KiB
Go
package torrent
|
|
|
|
import (
|
|
"github.com/monkeyWie/gopeed/protocol/bt/metainfo"
|
|
"math"
|
|
"sync"
|
|
|
|
"github.com/RoaringBitmap/roaring"
|
|
)
|
|
|
|
type state int
|
|
|
|
const (
|
|
stateReady = iota
|
|
stateDownloading
|
|
stateFinish
|
|
)
|
|
|
|
// 所有piece的下载状态
|
|
type pieceStates struct {
|
|
lock *sync.RWMutex
|
|
// 所有piece的block下载进度
|
|
states map[int]*pieceState
|
|
}
|
|
|
|
type pieceState struct {
|
|
state state
|
|
// piece中block的个数
|
|
blockCount int
|
|
// piece中block的下载记录
|
|
blockRecord *roaring.Bitmap
|
|
}
|
|
|
|
func newPiecesState(meta *metainfo.MetaInfo) *pieceStates {
|
|
pieceCount := len(meta.Info.Pieces)
|
|
ps := &pieceStates{
|
|
lock: &sync.RWMutex{},
|
|
states: make(map[int]*pieceState, pieceCount),
|
|
}
|
|
for i := 0; i < pieceCount; i++ {
|
|
ps.states[i] = &pieceState{
|
|
state: stateReady,
|
|
blockCount: int(math.Ceil(float64(meta.GetPieceLength(i)) / blockSize)),
|
|
blockRecord: roaring.New(),
|
|
}
|
|
}
|
|
return ps
|
|
}
|
|
|
|
func (ps *pieceStates) getState(index int) state {
|
|
ps.lock.RLock()
|
|
defer ps.lock.RUnlock()
|
|
return ps.states[index].state
|
|
}
|
|
|
|
func (ps *pieceStates) setState(index int, state state) {
|
|
ps.lock.Lock()
|
|
defer ps.lock.Unlock()
|
|
ps.states[index].state = state
|
|
}
|
|
|
|
func (ps *pieceStates) size() int {
|
|
return len(ps.states)
|
|
}
|
|
|
|
func (ps *pieceStates) getLeft() int {
|
|
ps.lock.RLock()
|
|
defer ps.lock.RUnlock()
|
|
count := 0
|
|
for _, v := range ps.states {
|
|
if v.state == stateReady || v.state == stateDownloading {
|
|
count++
|
|
}
|
|
}
|
|
return count
|
|
}
|
|
|
|
func (ps *pieceStates) isDone() bool {
|
|
ps.lock.RLock()
|
|
defer ps.lock.RUnlock()
|
|
for _, v := range ps.states {
|
|
if v.state == stateReady || v.state == stateDownloading {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (ps *pieceStates) isPieceDone(index int) bool {
|
|
ps.lock.RLock()
|
|
defer ps.lock.RUnlock()
|
|
state := ps.states[index]
|
|
return uint64(state.blockCount) == state.blockRecord.GetCardinality()
|
|
}
|
|
|
|
// 指定piece下的某个block是否下载完成
|
|
func (ps *pieceStates) isBlockDone(pieceIndex int, blockIndex int) bool {
|
|
return ps.states[pieceIndex].blockRecord.ContainsInt(blockIndex)
|
|
}
|
|
|
|
// 指定piece下的某个block下载完成
|
|
func (ps *pieceStates) setBlockDone(pieceIndex int, blockIndex int) {
|
|
ps.states[pieceIndex].blockRecord.AddInt(blockIndex)
|
|
}
|
|
|
|
// 清空指定piece下所有的block下载记录
|
|
func (ps *pieceStates) clearBlocks(index int) {
|
|
ps.states[index].blockRecord.Clear()
|
|
}
|