peer-impl.go | 2 +- peerconn.go | 14 +++++++------- torrent.go | 8 ++++++-- webseed-peer.go | 34 ++++++++++++++++++++++++---------- diff --git a/peer-impl.go b/peer-impl.go index b854ffd0ff5f096ab486b81a3353269eb0042794..f9f9096b198ea5d247d157fb940fbc9172ace1ac 100644 --- a/peer-impl.go +++ b/peer-impl.go @@ -26,7 +26,7 @@ drop() // Rebuke the peer ban() String() string - connStatusString() string + peerImplStatusLines() []string // All if the peer should have everything, known if we know that for a fact. For example, we can // guess at how many pieces are in a torrent, and assume they have all pieces based on them diff --git a/peerconn.go b/peerconn.go index 5ed5bde69eff88dcf9fe9e16b682bba7bc80c1b4..3c515aaf989d130e88670a89215abb14b1364e53 100644 --- a/peerconn.go +++ b/peerconn.go @@ -171,8 +171,8 @@ // we may not even know the number of pieces in the torrent yet. peerSentHaveAll bool } -func (cn *PeerConn) connStatusString() string { - return fmt.Sprintf("%+-55q %s %s", cn.PeerID, cn.PeerExtensionBytes, cn.connString) +func (cn *PeerConn) peerImplStatusLines() []string { + return []string{fmt.Sprintf("%+-55q %s %s", cn.PeerID, cn.PeerExtensionBytes, cn.connString)} } func (cn *Peer) updateExpectingChunks() { @@ -389,14 +389,14 @@ // \t isn't preserved in
blocks?
if cn.closed.IsSet() {
fmt.Fprint(w, "CLOSED: ")
}
- fmt.Fprintln(w, cn.connStatusString())
+ fmt.Fprintln(w, strings.Join(cn.peerImplStatusLines(), "\n"))
prio, err := cn.peerPriority()
prioStr := fmt.Sprintf("%08x", prio)
if err != nil {
prioStr += ": " + err.Error()
}
- fmt.Fprintf(w, " bep40-prio: %v\n", prioStr)
- fmt.Fprintf(w, " last msg: %s, connected: %s, last helpful: %s, itime: %s, etime: %s\n",
+ fmt.Fprintf(w, "bep40-prio: %v\n", prioStr)
+ fmt.Fprintf(w, "last msg: %s, connected: %s, last helpful: %s, itime: %s, etime: %s\n",
eventAgeString(cn.lastMessageReceived),
eventAgeString(cn.completedHandshake),
eventAgeString(cn.lastHelpful()),
@@ -404,7 +404,7 @@ cn.cumInterest(),
cn.totalExpectingTime(),
)
fmt.Fprintf(w,
- " %s completed, %d pieces touched, good chunks: %v/%v:%v reqq: %d+%v/(%d/%d):%d/%d, flags: %s, dr: %.1f KiB/s\n",
+ "%s completed, %d pieces touched, good chunks: %v/%v:%v reqq: %d+%v/(%d/%d):%d/%d, flags: %s, dr: %.1f KiB/s\n",
cn.completedString(),
len(cn.peerTouchedPieces),
&cn._stats.ChunksReadUseful,
@@ -419,7 +419,7 @@ localClientReqq,
cn.statusFlags(),
cn.downloadRate()/(1<<10),
)
- fmt.Fprintf(w, " requested pieces:")
+ fmt.Fprintf(w, "requested pieces:")
cn.iterContiguousPieceRequests(func(piece pieceIndex, count int) {
fmt.Fprintf(w, " %v(%v)", piece, count)
})
diff --git a/torrent.go b/torrent.go
index e0bc7246320ca7880dbee91bb06c685e03f5d519..f19deb7587aa07b26c18d779025779e16c2e88b7 100644
--- a/torrent.go
+++ b/torrent.go
@@ -770,9 +770,14 @@ return less
}
return worseConn(i, j)
})
+ var buf bytes.Buffer
for i, c := range peers {
fmt.Fprintf(w, "%2d. ", i+1)
- c.writeStatus(w, t)
+ buf.Reset()
+ c.writeStatus(&buf, t)
+ w.Write(bytes.TrimRight(
+ bytes.ReplaceAll(buf.Bytes(), []byte("\n"), []byte("\n ")),
+ " "))
}
}
@@ -2425,7 +2430,6 @@ }
},
},
activeRequests: make(map[Request]webseed.Request, maxRequests),
- maxRequests: maxRequests,
}
ws.peer.initRequestState()
for _, opt := range opts {
diff --git a/webseed-peer.go b/webseed-peer.go
index 52e33c721217b51096a5d6e99c6f179233c5e23c..678c805bd9b3b4590aae11f5d92e0be86661d0ab 100644
--- a/webseed-peer.go
+++ b/webseed-peer.go
@@ -16,20 +16,27 @@ pp "github.com/anacrolix/torrent/peer_protocol"
"github.com/anacrolix/torrent/webseed"
)
+const (
+ webseedPeerUnhandledErrorSleep = 5 * time.Second
+ webseedPeerCloseOnUnhandledError = false
+)
+
type webseedPeer struct {
// First field for stats alignment.
- peer Peer
- client webseed.Client
- activeRequests map[Request]webseed.Request
- requesterCond sync.Cond
- // Number of requester routines.
- maxRequests int
+ peer Peer
+ client webseed.Client
+ activeRequests map[Request]webseed.Request
+ requesterCond sync.Cond
+ lastUnhandledErr time.Time
}
var _ peerImpl = (*webseedPeer)(nil)
-func (me *webseedPeer) connStatusString() string {
- return me.client.Url
+func (me *webseedPeer) peerImplStatusLines() []string {
+ return []string{
+ me.client.Url,
+ fmt.Sprintf("last unhandled error: %v", eventAgeString(me.lastUnhandledErr)),
+ }
}
func (ws *webseedPeer) String() string {
@@ -86,6 +93,7 @@ ws.requesterCond.L.Lock()
defer ws.requesterCond.L.Unlock()
start:
for !ws.peer.closed.IsSet() {
+ // Restart is set if we don't need to wait for the requestCond before trying again.
restart := false
ws.peer.requestState.Requests.Iterate(func(x RequestIndex) bool {
r := ws.peer.t.requestIndexToRequest(x)
@@ -101,6 +109,7 @@ restart = true
if errors.Is(err, webseed.ErrTooFast) {
time.Sleep(time.Duration(rand.Int63n(int64(10 * time.Second))))
}
+ time.Sleep(time.Until(ws.lastUnhandledErr.Add(webseedPeerUnhandledErrorSleep)))
ws.requesterCond.L.Lock()
return false
})
@@ -172,8 +181,13 @@ // // Here lies my attempt to extract something concrete from Go's error system. RIP.
// cfg := spew.NewDefaultConfig()
// cfg.DisableMethods = true
// cfg.Dump(result.Err)
- log.Printf("closing %v", ws)
- ws.peer.close()
+
+ if webseedPeerCloseOnUnhandledError {
+ log.Printf("closing %v", ws)
+ ws.peer.close()
+ } else {
+ ws.lastUnhandledErr = time.Now()
+ }
}
if !ws.peer.remoteRejectedRequest(ws.peer.t.requestIndexFromRequest(r)) {
panic("invalid reject")