diff --git a/connection.go b/connection.go index 947adc5f..20a4f901 100644 --- a/connection.go +++ b/connection.go @@ -59,7 +59,10 @@ type connection struct { lastChunkSent time.Time // Stuff controlled by the local peer. - Interested bool + Interested bool + lastBecameInterested time.Time + priorInterest time.Duration + Choked bool requests map[request]struct{} requestsLowWater int @@ -99,6 +102,14 @@ type connection struct { writerCond sync.Cond } +func (cn *connection) cumInterest() time.Duration { + ret := cn.priorInterest + if cn.Interested { + ret += time.Since(cn.lastBecameInterested) + } + return ret +} + func (cn *connection) peerHasAllPieces() (all bool, known bool) { if cn.peerSentHaveAll { return true, true @@ -197,30 +208,38 @@ func (cn *connection) statusFlags() (ret string) { return } -func (cn *connection) String() string { - var buf bytes.Buffer - cn.WriteStatus(&buf, nil) - return buf.String() +// func (cn *connection) String() string { +// var buf bytes.Buffer +// cn.WriteStatus(&buf, nil) +// return buf.String() +// } + +func (cn *connection) downloadRate() float64 { + return float64(cn.stats.BytesReadUsefulData) / cn.cumInterest().Seconds() } func (cn *connection) WriteStatus(w io.Writer, t *Torrent) { // \t isn't preserved in
blocks? - fmt.Fprintf(w, "%-40s: %s-%s\n", cn.PeerID, cn.localAddr(), cn.remoteAddr()) - fmt.Fprintf(w, " last msg: %s, connected: %s, last helpful: %s\n", + fmt.Fprintf(w, "%+-55q %s %s-%s\n", cn.PeerID, cn.PeerExtensionBytes, cn.localAddr(), cn.remoteAddr()) + fmt.Fprintf(w, " last msg: %s, connected: %s, last helpful: %s, itime: %s\n", eventAgeString(cn.lastMessageReceived), eventAgeString(cn.completedHandshake), - eventAgeString(cn.lastHelpful())) + eventAgeString(cn.lastHelpful()), + cn.cumInterest(), + ) fmt.Fprintf(w, - " %s completed, %d pieces touched, good chunks: %d/%d-%d reqq: %d-%d, flags: %s\n", + " %s completed, %d pieces touched, good chunks: %d/%d-%d reqq: (%d,%d,%d]-%d, flags: %s, dr: %.1f KiB/s\n", cn.completedString(), len(cn.peerTouchedPieces), cn.stats.ChunksReadUseful, - // TODO: Use ChunksRead? Verify that value is the same as this sum? - cn.stats.ChunksReadUnwanted+cn.stats.ChunksReadUseful, + cn.stats.ChunksRead, cn.stats.ChunksWritten, + cn.requestsLowWater, cn.numLocalRequests(), + cn.nominalMaxRequests(), len(cn.PeerRequests), cn.statusFlags(), + cn.downloadRate()/(1<<10), ) roi := cn.pieceRequestOrderIter() fmt.Fprintf(w, " next pieces: %v%s\n", @@ -350,6 +369,11 @@ func (cn *connection) SetInterested(interested bool, msg func(pp.Message) bool) return true } cn.Interested = interested + if interested { + cn.lastBecameInterested = time.Now() + } else if !cn.lastBecameInterested.IsZero() { + cn.priorInterest += time.Since(cn.lastBecameInterested) + } // log.Printf("%p: setting interest: %v", cn, interested) return msg(pp.Message{ Type: func() pp.MessageType { diff --git a/handshake.go b/handshake.go index f15f5bbf..6627b608 100644 --- a/handshake.go +++ b/handshake.go @@ -38,6 +38,10 @@ type ( peerExtensionBytes [8]byte ) +func (me peerExtensionBytes) String() string { + return hex.EncodeToString(me[:]) +} + func newPeerExtensionBytes(bits ...ExtensionBit) (ret peerExtensionBytes) { for _, b := range bits { ret.SetBit(b) @@ -124,7 +128,7 @@ func handshake(sock io.ReadWriter, ih *metainfo.Hash, peerID [20]byte, extension missinggo.CopyExact(&res.peerExtensionBytes, b[20:28]) missinggo.CopyExact(&res.Hash, b[28:48]) missinggo.CopyExact(&res.PeerID, b[48:68]) - peerExtensions.Add(hex.EncodeToString(res.peerExtensionBytes[:]), 1) + peerExtensions.Add(res.peerExtensionBytes.String(), 1) // TODO: Maybe we can just drop peers here if we're not interested. This // could prevent them trying to reconnect, falsely believing there was diff --git a/peerid.go b/peerid.go index 1514b79c..9bc94754 100644 --- a/peerid.go +++ b/peerid.go @@ -1,17 +1,14 @@ package torrent -import ( - "encoding/hex" -) - // Peer client ID. type PeerID [20]byte -// Pretty prints the ID as hex, except parts that adher to the Peer ID -// Conventions of BEP 20. -func (me PeerID) String() string { - if me[0] == '-' && me[7] == '-' { - return string(me[:8]) + hex.EncodeToString(me[8:]) - } - return hex.EncodeToString(me[:]) -} +// // Pretty prints the ID as hex, except parts that adher to the Peer ID +// // Conventions of BEP 20. +// func (me PeerID) String() string { +// // if me[0] == '-' && me[7] == '-' { +// // return string(me[:8]) + hex.EncodeToString(me[8:]) +// // } +// // return hex.EncodeToString(me[:]) +// return fmt.Sprintf("%+q", me[:]) +// } diff --git a/peerid_test.go b/peerid_test.go index 965a28ab..bcf09998 100644 --- a/peerid_test.go +++ b/peerid_test.go @@ -1,24 +1,16 @@ package torrent -import ( - "fmt" - "testing" - - "github.com/anacrolix/missinggo" - "github.com/stretchr/testify/assert" -) - -func TestPeerIdString(t *testing.T) { - for _, _case := range []struct { - id string - s string - }{ - {"\x1cNJ}\x9c\xc7\xc4o\x94<\x9b\x8c\xc2!I\x1c\a\xec\x98n", "1c4e4a7d9cc7c46f943c9b8cc221491c07ec986e"}, - {"-FD51W\xe4-LaZMk0N8ZLA7", "-FD51W\xe4-4c615a4d6b304e385a4c4137"}, - } { - var pi PeerID - missinggo.CopyExact(&pi, _case.id) - assert.EqualValues(t, _case.s, pi.String()) - assert.EqualValues(t, fmt.Sprintf("%q", _case.s), fmt.Sprintf("%q", pi)) - } -} +// func TestPeerIdString(t *testing.T) { +// for _, _case := range []struct { +// id string +// s string +// }{ +// {"\x1cNJ}\x9c\xc7\xc4o\x94<\x9b\x8c\xc2!I\x1c\a\xec\x98n", "\"\x1cNJ}\x9c\xc7\xc4o\x94<\x9b\x8c\xc2!I\x1c\a\xec\x98n\""}, +// {"-FD51W\xe4-LaZMk0N8ZLA7", "-FD51W\xe4-LaZMk0N8ZLA7"}, +// } { +// var pi PeerID +// missinggo.CopyExact(&pi, _case.id) +// assert.EqualValues(t, _case.s, pi.String()) +// assert.EqualValues(t, fmt.Sprintf("%q", _case.s), fmt.Sprintf("%q", pi)) +// } +// }