]>
git.ipfire.org Git - people/shoehn/ipfire.org.git/blob - www/webapp/backend/tracker.py
9 from databases
import Databases
, Row
10 from misc
import Singleton
19 ret
.append("%02x" % i
)
23 class Tracker(object):
24 id = "TheIPFireTorrentTracker"
26 # Intervals # XXX needs to be in Settings
30 random_interval
= -60, 60
36 return Databases().webapp
38 def _fetch(self
, hash, limit
=None, random
=False, completed
=False, no_peer_id
=False):
39 query
= "SELECT * FROM tracker_peers WHERE last_update >= %d" % self
.since
42 query
+= " AND hash = '%s'" % hash
45 query
+= " AND left_data = 0"
47 query
+= " AND left_data != 0"
50 query
+= " ORDER BY RAND()"
53 query
+= " LIMIT %s" % limit
56 for peer
in self
.db
.query(query
):
57 if not peer
.ip
or not peer
.port
:
62 "port" : int(peer
.port
),
66 peer_dict
["peer id"] = str(peer
.id),
68 peers
.append(peer_dict
)
72 def get_peers(self
, hash, **kwargs
):
73 return self
._fetch
(hash, **kwargs
)
75 def get_seeds(self
, hash, **kwargs
):
76 kwargs
.update({"completed" : True})
77 return self
._fetch
(hash, **kwargs
)
79 def complete(self
, hash):
80 return len(self
.get_seeds(hash))
82 def incomplete(self
, hash):
83 return len(self
.get_peers(hash))
85 def event_started(self
, hash, peer_id
):
86 # Damn, mysql does not support INSERT IF NOT EXISTS...
87 if not self
.db
.query("SELECT id FROM tracker_peers WHERE hash = '%s' AND peer_id = '%s'" % (hash, peer_id
)):
88 self
.db
.execute("INSERT INTO tracker_peers(hash, peer_id) VALUES('%s', '%s')" % (hash, peer_id
))
90 if not hash in self
.hashes
:
91 self
.db
.execute("INSERT INTO tracker_hashes(hash) VALUES('%s')" % hash)
93 def event_stopped(self
, hash, peer_id
):
94 self
.db
.execute("DELETE FROM tracker_peers WHERE hash = '%s' AND peer_id = '%s'" % (hash, peer_id
))
96 def event_completed(self
, hash, peer_id
):
97 self
.db
.execute("UPDATE tracker_hashes SET completed=completed+1 WHERE hash = '%s'" % hash)
99 def scrape(self
, hashes
=[]):
101 for hash in self
.db
.query("SELECT hash, completed FROM tracker_hashes"):
102 hash, completed
= hash.hash, hash.completed
104 if hashes
and hash not in hashes
:
108 "complete" : self
.complete(hash),
109 "downloaded" : completed
or 0,
110 "incomplete" : self
.incomplete(hash),
115 def update(self
, hash, id, ip
=None, port
=None, downloaded
=None, uploaded
=None, left
=None):
116 args
= [ "last_update = '%s'" % self
.now
]
119 if ip
.startswith("172.28.1."):
122 args
.append("ip='%s'" % ip
)
125 args
.append("port='%s'" % port
)
128 args
.append("downloaded='%s'" % downloaded
)
131 args
.append("uploaded='%s'" % uploaded
)
134 args
.append("left_data='%s'" % left
)
139 query
= "UPDATE tracker_peers SET " + ", ".join(args
) + \
140 " WHERE hash = '%s' AND peer_id = '%s'" % (hash, id)
142 self
.db
.execute(query
)
147 for h
in self
.db
.query("SELECT hash FROM tracker_hashes"):
148 hashes
.append(h
["hash"].lower())
154 return int(time
.time())
158 return int(time
.time() - self
.interval
)
162 return self
._interval
+ random
.randint(*self
.random_interval
)
165 def min_interval(self
):
166 return self
._min
_interval
+ random
.randint(*self
.random_interval
)
169 ##### This is borrowed from the bittorrent client libary #####
171 def decode_int(x
, f
):
173 newf
= x
.index('e', f
)
178 elif x
[f
] == '0' and newf
!= f
+1:
182 def decode_string(x
, f
):
183 colon
= x
.index(':', f
)
185 if x
[f
] == '0' and colon
!= f
+1:
188 return (x
[colon
:colon
+n
], colon
+n
)
190 def decode_list(x
, f
):
193 v
, f
= decode_func
[x
[f
]](x
, f
)
197 def decode_dict(x
, f
):
200 k
, f
= decode_string(x
, f
)
201 r
[k
], f
= decode_func
[x
[f
]](x
, f
)
205 decode_func
['l'] = decode_list
206 decode_func
['d'] = decode_dict
207 decode_func
['i'] = decode_int
208 decode_func
['0'] = decode_string
209 decode_func
['1'] = decode_string
210 decode_func
['2'] = decode_string
211 decode_func
['3'] = decode_string
212 decode_func
['4'] = decode_string
213 decode_func
['5'] = decode_string
214 decode_func
['6'] = decode_string
215 decode_func
['7'] = decode_string
216 decode_func
['8'] = decode_string
217 decode_func
['9'] = decode_string
221 r
, l
= decode_func
[x
[0]](x
, 0)
222 except (IndexError, KeyError, ValueError):
223 raise Exception("not a valid bencoded string")
225 raise Exception("invalid bencoded value (data after valid prefix)")
228 from types
import StringType
, IntType
, LongType
, DictType
, ListType
, TupleType
231 class Bencached(object):
233 __slots__
= ['bencoded']
235 def __init__(self
, s
):
238 def encode_bencached(x
,r
):
241 def encode_int(x
, r
):
242 r
.extend(('i', str(x
), 'e'))
244 def encode_bool(x
, r
):
250 def encode_string(x
, r
):
251 r
.extend((str(len(x
)), ':', x
))
253 def encode_list(x
, r
):
256 encode_func
[type(i
)](i
, r
)
259 def encode_dict(x
,r
):
264 r
.extend((str(len(k
)), ':', k
))
265 encode_func
[type(v
)](v
, r
)
269 encode_func
[Bencached
] = encode_bencached
270 encode_func
[IntType
] = encode_int
271 encode_func
[LongType
] = encode_int
272 encode_func
[StringType
] = encode_string
273 encode_func
[ListType
] = encode_list
274 encode_func
[TupleType
] = encode_list
275 encode_func
[DictType
] = encode_dict
278 from types
import BooleanType
279 encode_func
[BooleanType
] = encode_bool
285 encode_func
[type(x
)](x
, r
)