connection.go | 24 +++++++++++++++++------- torrent.go | 6 ++++++ torrent_stats.go | 10 ++++++---- diff --git a/connection.go b/connection.go index 753bc64fddbf9bf64db25a368621269830c13029..40d02abab34d7ca8f57417bc66a23a664c0690f8 100644 --- a/connection.go +++ b/connection.go @@ -82,7 +82,7 @@ // The pieces the peer has claimed to have. peerPieces bitmap.Bitmap // The peer has everything. This can occur due to a special message, when // we may not even know the number of pieces in the torrent yet. - peerHasAll bool + peerSentHaveAll bool // The highest possible number of pieces the torrent could have based on // communication with the peer. Generally only useful until we have the // torrent info. @@ -100,6 +100,16 @@ postedBuffer bytes.Buffer uploadTimer *time.Timer writerCond sync.Cond +} + +func (cn *connection) peerHasAllPieces() (all bool, known bool) { + if cn.peerSentHaveAll { + return true, true + } + if !cn.t.haveInfo() { + return false, false + } + return bitmap.Flip(cn.peerPieces, 0, cn.t.numPieces()).IsEmpty(), true } func (cn *connection) mu() sync.Locker { @@ -234,7 +244,7 @@ } } func (cn *connection) PeerHasPiece(piece int) bool { - return cn.peerHasAll || cn.peerPieces.Contains(piece) + return cn.peerSentHaveAll || cn.peerPieces.Contains(piece) } func (cn *connection) Post(msg pp.Message) { @@ -695,7 +705,7 @@ return nil } func (cn *connection) peerSentBitfield(bf []bool) error { - cn.peerHasAll = false + cn.peerSentHaveAll = false if len(bf)%8 != 0 { panic("expected bitfield length divisible by 8") } @@ -716,8 +726,8 @@ cn.peerPiecesChanged() return nil } -func (cn *connection) peerSentHaveAll() error { - cn.peerHasAll = true +func (cn *connection) onPeerSentHaveAll() error { + cn.peerSentHaveAll = true cn.peerPieces.Clear() cn.peerPiecesChanged() return nil @@ -725,7 +735,7 @@ } func (cn *connection) peerSentHaveNone() error { cn.peerPieces.Clear() - cn.peerHasAll = false + cn.peerSentHaveAll = false cn.peerPiecesChanged() return nil } @@ -883,7 +893,7 @@ } case pp.Bitfield: err = c.peerSentBitfield(msg.Bitfield) case pp.HaveAll: - err = c.peerSentHaveAll() + err = c.onPeerSentHaveAll() case pp.HaveNone: err = c.peerSentHaveNone() case pp.Piece: diff --git a/torrent.go b/torrent.go index a215859d568c7cc61277007bc28d17115ec8d013..f5d3b2a646cebe2934762a3de1518293564d6300 100644 --- a/torrent.go +++ b/torrent.go @@ -1354,6 +1354,12 @@ t.stats.ActivePeers = len(t.conns) t.stats.HalfOpenPeers = len(t.halfOpen) t.stats.PendingPeers = len(t.peers) t.stats.TotalPeers = t.numTotalPeers() + t.stats.ConnectedSeeders = 0 + for c := range t.conns { + if all, ok := c.peerHasAllPieces(); all && ok { + t.stats.ConnectedSeeders++ + } + } return t.stats } diff --git a/torrent_stats.go b/torrent_stats.go index 3dd2716a916db24aa5be75eac817922c68d89290..f155a0d83ea369e2fa6539b9fe157ace55b18039 100644 --- a/torrent_stats.go +++ b/torrent_stats.go @@ -3,8 +3,10 @@ type TorrentStats struct { ConnStats // Aggregates stats over all connections past and present. - ActivePeers int - HalfOpenPeers int - PendingPeers int - TotalPeers int + // Ordered by expected descending quantities (if all is well). + TotalPeers int + PendingPeers int + ActivePeers int + ConnectedSeeders int + HalfOpenPeers int }