feat(download): judge a queued slskd peer by its queue position
No bytes for ten minutes usually means a peer has queued us, and the
stall timer could not tell position 2 from position 400: the first was
abandoned while it was about to start, the second was waited on for ten
minutes for nothing.
While a requested file is "Queued, Remotely", the grab asks slskd for
its place (GET .../downloads/{user}/{id}/position, which asks the peer)
once a minute. A place that improved counts as progress and restarts
the stall clock. A place beyond 50 twice running gives the peer up at
once, and the manager moves to the next copy; two readings because
slskd documents the figure as possibly inaccurate. Waiting in a queue
has an overall ceiling of an hour without a byte, since a queue moving
one place an hour would otherwise hold the grab all day. As with a
stall, files that already arrived still go forward.
Closes #275
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HJiuc3ZZhxsPXz3ozTirT
This commit is contained in:
1 parent
7a9dd69d30
commit
c88fc1c7c7
3 files changed
+287
-8
No files matched your search
@@ -65,8 +65,13 @@ type slskdStub struct {
|
||||
// under downloads when it is enqueued, keyed by file base name.
|
||||
batches bool
|
||||
batchBodies []map[string]any
|
||||
delivered map[string]string
|
||||
downloads string
|
||||
|
||||
// positions is what the queue-position endpoint answers, in order;
|
||||
// the last repeats. positionAsks counts the calls.
|
||||
positions []int
|
||||
positionAsks int
|
||||
delivered map[string]string
|
||||
downloads string
|
||||
}
|
||||
|
||||
func newSlskdStub(t *testing.T) *slskdStub {
|
||||
@@ -150,6 +155,23 @@ func newSlskdStub(t *testing.T) *slskdStub {
|
||||
s.paths = append(s.paths, r.URL.EscapedPath())
|
||||
s.mu.Unlock()
|
||||
|
||||
if r.Method == http.MethodGet && strings.HasSuffix(r.URL.Path, "/position") {
|
||||
s.mu.Lock()
|
||||
idx := min(s.positionAsks, len(s.positions)-1)
|
||||
s.positionAsks++
|
||||
place := 0
|
||||
|
||||
if idx >= 0 {
|
||||
place = s.positions[idx]
|
||||
}
|
||||
|
||||
s.mu.Unlock()
|
||||
|
||||
writeJSON(t, w, place)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if r.Method == http.MethodPost && strings.HasSuffix(r.URL.Path, "/batches") {
|
||||
s.enqueueBatch(t, w, r)
|
||||
|
||||
@@ -379,6 +401,8 @@ func newStubSlskd(t *testing.T, stub *slskdStub) (*slskd, string) {
|
||||
// tests about stalls and absences set their own.
|
||||
s.stallAfter = time.Minute
|
||||
s.absentGrace = time.Minute
|
||||
s.positionPoll = time.Millisecond
|
||||
s.queueCeiling = time.Hour
|
||||
|
||||
return s, downloads
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user