forked from staceysern/bt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
trackerproxy.py
93 lines (73 loc) · 3.32 KB
/
trackerproxy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
"""
The TrackerProxy contacts the tracker specified in the supplied Metainfo object
and provides information about peers upon request. During initialization, the
TrackerProxy raises a TrackerError if the tracker can't be contacted or
returns an invalid response.
This blocking TrackerProxy should be made non-blocking.
Right now, this client doesn't support multiple trackers specified by
announce-list in the Metainfo object.
The TrackerProxy should periodically report progress back to the tracker and
notify it when it has downloaded the entire torrent. If the peer list is
exhausted, it should also get more peers from the tracker.
"""
import bencode
import logging
import requests
import sys
logger = logging.getLogger('bt.trackerproxy')
class TrackerError(Exception):
pass
class TrackerProxy(object):
def __init__(self, metainfo, port, peer_id):
self._metainfo = metainfo
self._port = port
self._peer_id = peer_id
params = {'info_hash': self._metainfo.info_hash,
'peer_id': self._peer_id,
'port': self._port,
'uploaded': 0,
'downloaded': 0,
'left': sum([pair[1] for pair in self._metainfo.files]),
'compact': 1,
'event': 'started'}
try:
response = requests.get(self._metainfo.announce, params=params)
except requests.ConnectionError:
raise TrackerError("Can't connect to the tracker at {}"
.format(self._metainfo.announce))
response = bencode.bdecode(response.content)
if 'failure reason' in response:
raise TrackerError("Failure reason: {}"
.format(response['failure reason']))
if 'warning message' in response:
logger.warning("Warning: {}".format(response['warning message']))
print >> sys.stderr, ("Warning: {}"
.format(response['warning message']))
try:
self._min_interval = response.get('min interval', 0)
if 'tracker id' in response:
self._tracker_id = response['tracker id']
self._interval = response['interval']
self._complete = response['complete']
self._incomplete = response['incomplete']
if isinstance(response['peers'], list):
self._peers = response['peers']
else:
self._peers = []
peers = response['peers']
for offset in xrange(0, len(peers), 6):
self._peers.append({'ip': "{}.{}.{}.{}"
.format(str(ord(peers[offset])),
str(ord(peers[offset+1])),
str(ord(peers[offset+2])),
str(ord(peers[offset+3]))),
'port': (ord(peers[offset+4])*256 +
ord(peers[offset+5]))})
except Exception:
raise TrackerError("Invalid tracker response")
def get_peers(self, n):
if (len(self._peers) <= n):
n = len(self._peers)
peers = self._peers[:n]
self._peers = self._peers[n:]
return peers