]>
git.ipfire.org Git - ipfire.org.git/blob - www/webapp/backend/tracker.py
5 from databases
import Databases
6 from misc
import Singleton
15 ret
.append("%02x" % i
)
19 class Tracker(object):
20 id = "TheIPFireTorrentTracker"
22 # Intervals # XXX needs to be in Settings
30 return Databases().tracker
32 def _fetch(self
, hash, limit
=None, random
=False, completed
=False, no_peer_id
=False):
33 query
= "SELECT * FROM peers WHERE last_update >= %d" % self
.since
36 query
+= " AND hash = '%s'" % hash
39 query
+= " AND left_data = 0"
41 query
+= " AND left_data != 0"
44 query
+= " ORDER BY RAND()"
47 query
+= " LIMIT %s" % limit
50 for peer
in self
.db
.query(query
):
51 if not peer
.ip
or not peer
.port
:
56 "port" : int(peer
.port
),
60 peer_dict
["peer id"] = str(peer
.id),
62 peers
.append(peer_dict
)
66 def get_peers(self
, hash, **kwargs
):
67 return self
._fetch
(hash, **kwargs
)
69 def get_seeds(self
, hash, **kwargs
):
70 kwargs
.update({"completed" : True})
71 return self
._fetch
(hash, **kwargs
)
73 def complete(self
, hash):
74 return len(self
.get_seeds(hash))
76 def incomplete(self
, hash):
77 return len(self
.get_peers(hash))
79 def event_started(self
, hash, peer_id
):
80 # Damn, mysql does not support INSERT IF NOT EXISTS...
81 if not self
.db
.query("SELECT id FROM peers WHERE hash = '%s' AND peer_id = '%s'" % (hash, peer_id
)):
82 self
.db
.execute("INSERT INTO peers(hash, peer_id) VALUES('%s', '%s')" % (hash, peer_id
))
84 if not hash in self
.hashes
:
85 self
.db
.execute("INSERT INTO hashes(hash) VALUES('%s')" % hash)
87 def event_stopped(self
, hash, peer_id
):
88 self
.db
.execute("DELETE FROM peers WHERE hash = '%s' AND peer_id = '%s'" % (hash, peer_id
))
90 def event_completed(self
, hash, peer_id
):
91 self
.db
.execute("UPDATE hashes SET completed=completed+1 WHERE hash = '%s'" % hash)
93 def scrape(self
, hashes
=[]):
95 for hash in self
.db
.query("SELECT hash, completed FROM hashes"):
96 hash, completed
= hash.hash, hash.completed
98 if hashes
and hash not in hashes
:
102 "complete" : self
.complete(hash),
103 "downloaded" : completed
or 0,
104 "incomplete" : self
.incomplete(hash),
109 def update(self
, hash, id, ip
=None, port
=None, downloaded
=None, uploaded
=None, left
=None):
110 args
= [ "last_update = '%s'" % self
.now
]
113 args
.append("ip='%s'" % ip
)
116 args
.append("port='%s'" % port
)
119 args
.append("downloaded='%s'" % downloaded
)
122 args
.append("uploaded='%s'" % uploaded
)
125 args
.append("left_data='%s'" % left
)
130 query
= "UPDATE peers SET " + ", ".join(args
) + \
131 " WHERE hash = '%s' AND peer_id = '%s'" % (hash, id)
133 self
.db
.execute(query
)
138 for h
in self
.db
.query("SELECT hash FROM hashes"):
139 hashes
.append(h
["hash"].lower())
145 return int(time
.time())
149 return int(time
.time() - self
.interval
)
152 ##### This is borrowed from the bittorrent client libary #####
154 def decode_int(x
, f
):
156 newf
= x
.index('e', f
)
161 elif x
[f
] == '0' and newf
!= f
+1:
165 def decode_string(x
, f
):
166 colon
= x
.index(':', f
)
168 if x
[f
] == '0' and colon
!= f
+1:
171 return (x
[colon
:colon
+n
], colon
+n
)
173 def decode_list(x
, f
):
176 v
, f
= decode_func
[x
[f
]](x
, f
)
180 def decode_dict(x
, f
):
183 k
, f
= decode_string(x
, f
)
184 r
[k
], f
= decode_func
[x
[f
]](x
, f
)
188 decode_func
['l'] = decode_list
189 decode_func
['d'] = decode_dict
190 decode_func
['i'] = decode_int
191 decode_func
['0'] = decode_string
192 decode_func
['1'] = decode_string
193 decode_func
['2'] = decode_string
194 decode_func
['3'] = decode_string
195 decode_func
['4'] = decode_string
196 decode_func
['5'] = decode_string
197 decode_func
['6'] = decode_string
198 decode_func
['7'] = decode_string
199 decode_func
['8'] = decode_string
200 decode_func
['9'] = decode_string
204 r
, l
= decode_func
[x
[0]](x
, 0)
205 except (IndexError, KeyError, ValueError):
206 raise Exception("not a valid bencoded string")
208 raise Exception("invalid bencoded value (data after valid prefix)")
211 from types
import StringType
, IntType
, LongType
, DictType
, ListType
, TupleType
214 class Bencached(object):
216 __slots__
= ['bencoded']
218 def __init__(self
, s
):
221 def encode_bencached(x
,r
):
224 def encode_int(x
, r
):
225 r
.extend(('i', str(x
), 'e'))
227 def encode_bool(x
, r
):
233 def encode_string(x
, r
):
234 r
.extend((str(len(x
)), ':', x
))
236 def encode_list(x
, r
):
239 encode_func
[type(i
)](i
, r
)
242 def encode_dict(x
,r
):
247 r
.extend((str(len(k
)), ':', k
))
248 encode_func
[type(v
)](v
, r
)
252 encode_func
[Bencached
] = encode_bencached
253 encode_func
[IntType
] = encode_int
254 encode_func
[LongType
] = encode_int
255 encode_func
[StringType
] = encode_string
256 encode_func
[ListType
] = encode_list
257 encode_func
[TupleType
] = encode_list
258 encode_func
[DictType
] = encode_dict
261 from types
import BooleanType
262 encode_func
[BooleanType
] = encode_bool
268 encode_func
[type(x
)](x
, r
)