]> Sergey Matveev's repositories - btrtrc.git/blob - webseed-peer.go
Remove requests as soon as chunk data is received
[btrtrc.git] / webseed-peer.go
1 package torrent
2
3 import (
4         "fmt"
5         "strings"
6
7         "github.com/anacrolix/torrent/common"
8         "github.com/anacrolix/torrent/metainfo"
9         pp "github.com/anacrolix/torrent/peer_protocol"
10         "github.com/anacrolix/torrent/segments"
11         "github.com/anacrolix/torrent/webseed"
12         "github.com/pkg/errors"
13 )
14
15 type webseedPeer struct {
16         client webseed.Client
17         // TODO: Remove finished entries from this.
18         requests map[Request]webseed.Request
19         peer     Peer
20 }
21
22 var _ peerImpl = (*webseedPeer)(nil)
23
24 func (me *webseedPeer) connStatusString() string {
25         return me.client.Url
26 }
27
28 func (ws *webseedPeer) String() string {
29         return fmt.Sprintf("webseed peer for %q", ws.client.Url)
30 }
31
32 func (ws *webseedPeer) onGotInfo(info *metainfo.Info) {
33         ws.client.FileIndex = segments.NewIndex(common.LengthIterFromUpvertedFiles(info.UpvertedFiles()))
34         ws.client.Info = info
35 }
36
37 func (ws *webseedPeer) _postCancel(r Request) {
38         ws.cancel(r)
39 }
40
41 func (ws *webseedPeer) writeInterested(interested bool) bool {
42         return true
43 }
44
45 func (ws *webseedPeer) cancel(r Request) bool {
46         ws.requests[r].Cancel()
47         return true
48 }
49
50 func (ws *webseedPeer) intoSpec(r Request) webseed.RequestSpec {
51         return webseed.RequestSpec{ws.peer.t.requestOffset(r), int64(r.Length)}
52 }
53
54 func (ws *webseedPeer) request(r Request) bool {
55         webseedRequest := ws.client.NewRequest(ws.intoSpec(r))
56         ws.requests[r] = webseedRequest
57         go ws.requestResultHandler(r, webseedRequest)
58         return true
59 }
60
61 func (ws *webseedPeer) connectionFlags() string {
62         return "WS"
63 }
64
65 // TODO: This is called when banning peers. Perhaps we want to be able to ban webseeds too. We could
66 // return bool if this is even possible, and if it isn't, skip to the next drop candidate.
67 func (ws *webseedPeer) drop() {}
68
69 func (ws *webseedPeer) updateRequests() {
70         ws.peer.doRequestState()
71 }
72
73 func (ws *webseedPeer) onClose() {}
74
75 func (ws *webseedPeer) requestResultHandler(r Request, webseedRequest webseed.Request) {
76         result := <-webseedRequest.Result
77         ws.peer.t.cl.lock()
78         defer ws.peer.t.cl.unlock()
79         if result.Err != nil {
80                 ws.peer.logger.Printf("Request %v rejected: %v", r, result.Err)
81                 // Always close for now. We need to filter out temporary errors, but this is a nightmare in
82                 // Go. Currently a bad webseed URL can starve out the good ones due to the chunk selection
83                 // algorithm.
84                 const closeOnAllErrors = false
85                 if closeOnAllErrors || strings.Contains(errors.Cause(result.Err).Error(), "unsupported protocol scheme") {
86                         ws.peer.close()
87                 } else {
88                         ws.peer.remoteRejectedRequest(r)
89                 }
90         } else {
91                 err := ws.peer.receiveChunk(&pp.Message{
92                         Type:  pp.Piece,
93                         Index: r.Index,
94                         Begin: r.Begin,
95                         Piece: result.Bytes,
96                 })
97                 if err != nil {
98                         panic(err)
99                 }
100         }
101 }