"github.com/anacrolix/log"
"github.com/anacrolix/missinggo/v2"
"github.com/anacrolix/missinggo/v2/bitmap"
+ "github.com/anacrolix/missinggo/v2/panicif"
"github.com/anacrolix/missinggo/v2/pproffd"
"github.com/anacrolix/sync"
"github.com/cespare/xxhash"
numHalfOpen int
websocketTrackers websocketTrackers
- numWebSeedRequests int
+ numWebSeedRequests map[webseedHostKeyHandle]int
activeAnnounceLimiter limiter.Instance
httpClient *http.Client
return cl.statsLocked()
}
-func (cl *Client) underWebSeedHttpRequestLimit() bool {
- return cl.numWebSeedRequests < 10
+func (cl *Client) underWebSeedHttpRequestLimit(key webseedHostKeyHandle) bool {
+ panicif.Zero(key)
+ return cl.numWebSeedRequests[key] < 5
}
func (cl *Client) countWebSeedHttpRequests() (num int) {
"strings"
"text/tabwriter"
"time"
+ "unique"
"unsafe"
"github.com/RoaringBitmap/roaring"
}
},
},
+ hostKey: t.deriveWebSeedHostKey(url),
}
ws.peer.initRequestState()
for _, opt := range opts {
return true
}
+func (t *Torrent) deriveWebSeedHostKey(urlStr string) (ret webseedHostKeyHandle) {
+ u, err := url.Parse(urlStr)
+ if err != nil {
+ t.slogger().Warn("error parsing webseed URL", "url", urlStr, "err", err)
+ return unique.Make(webseedHostKey(urlStr))
+ }
+ return unique.Make(webseedHostKey(u.Hostname()))
+}
+
func (t *Torrent) peerIsActive(p *Peer) (active bool) {
t.iterPeers(func(p1 *Peer) {
if p1 == p {
import (
"context"
- "errors"
"fmt"
"io"
"iter"
"github.com/RoaringBitmap/roaring"
g "github.com/anacrolix/generics"
-
+ "github.com/anacrolix/missinggo/v2/panicif"
"github.com/anacrolix/torrent/metainfo"
pp "github.com/anacrolix/torrent/peer_protocol"
"github.com/anacrolix/torrent/webseed"
activeRequests map[*webseedRequest]struct{}
locker sync.Locker
lastUnhandledErr time.Time
+ hostKey webseedHostKeyHandle
}
func (me *webseedPeer) nominalMaxRequests() maxRequests {
}
func (me *webseedPeer) shouldUpdateRequests() bool {
- return me.numRequests() < me.client.MaxRequests && me.peer.t.cl.underWebSeedHttpRequestLimit()
+ return me.moreRequestsAllowed()
+}
+
+func (me *webseedPeer) moreRequestsAllowed() bool {
+ return me.numRequests() < me.client.MaxRequests && me.peer.t.cl.underWebSeedHttpRequestLimit(me.hostKey)
}
func (me *webseedPeer) updateRequests() {
end: end,
}
ws.activeRequests[&wsReq] = struct{}{}
- ws.peer.t.cl.numWebSeedRequests++
+ panicif.Zero(ws.hostKey)
+ ws.peer.t.cl.numWebSeedRequests[ws.hostKey]++
ws.slogger().Debug(
"starting webseed request",
"begin", begin,
func (ws *webseedPeer) deleteActiveRequest(wr *webseedRequest) {
g.MustDelete(ws.activeRequests, wr)
- ws.peer.t.cl.numWebSeedRequests--
+ ws.peer.t.cl.numWebSeedRequests[ws.hostKey]--
}
func (ws *webseedPeer) spawnRequests() {
next, stop := iter.Pull(ws.inactiveRequests())
defer stop()
- for {
- if !ws.peer.t.cl.underWebSeedHttpRequestLimit() {
- break
- }
- if ws.numRequests() >= ws.client.MaxRequests {
- break
- }
+ for ws.moreRequestsAllowed() {
req, ok := next()
if !ok {
break
package torrent
import (
+ "unique"
+
"github.com/anacrolix/torrent/metainfo"
requestStrategy "github.com/anacrolix/torrent/request-strategy"
)
+type (
+ webseedHostKey string
+ webseedHostKeyHandle = unique.Handle[webseedHostKey]
+)
+
/*
- Go through all the requestable pieces in order of priority, availability, whether there are peer requests, partial, infohash.
- For each piece calculate files involved. Record each file not seen before and the piece index.