from __future__ import division
-import random
-
-from misc import Object
-
-def encode_hex(s):
- return s.encode("hex")
-
-def decode_hex(s):
- return s.decode("hex")
-
-
-class Tracker(Object):
- @property
- def tracker_id(self):
- return self.settings.get("tracker_id", "TheIPFireTorrentTracker")
-
- def _fuzzy_interval(self, interval, fuzz=120):
- return interval - random.randint(0, fuzz)
-
- @property
- def _interval(self):
- return self.settings.get_int("tracker_interval", 3600)
-
- @property
- def interval(self):
- return self._fuzzy_interval(self._interval)
-
- @property
- def min_interval(self):
- return self.settings.get_int("tracker_min_interval", self._interval // 2)
-
- @property
- def numwant(self):
- return self.settings.get_int("tracker_numwant", 50)
-
- def get_peers(self, info_hash, limit=None, random=True, no_peer_id=False, ipfamily=None):
- query = "SELECT * FROM tracker WHERE last_update >= NOW() - INTERVAL '%ss'"
- args = [self._interval,]
-
- if info_hash:
- query += " AND hash = %s"
- args.append(info_hash)
-
- if random:
- query += " ORDER BY RANDOM()"
-
- if limit:
- query += " LIMIT %s"
- args.append(limit)
-
- peers = []
- for row in self.db.query(query, *args):
- peer6 = None
- peer4 = None
-
- if row.address6 and row.port6:
- peer6 = {
- "ip" : row.address6,
- "port" : row.port6,
- }
-
- if row.address4 and row.port4:
- peer4 = {
- "ip" : row.address4,
- "port" : row.port4,
- }
-
- if not no_peer_id:
- if peer6:
- peer6["peer id"] = decode_hex(row.id)
-
- if peer4:
- peer4["peer id"] = decode_hex(row.id)
-
- if peer6:
- peers.append(peer6)
-
- if peer4:
- peers.append(peer4)
-
- return peers
-
- def cleanup_peers(self):
- """
- Remove all peers that have timed out.
- """
- self.db.execute("DELETE FROM tracker \
- WHERE last_update < NOW() - INTERVAL '%s s'", int(self._interval * 1.2))
-
- def update_peer(self, peer_id, info_hash, **kwargs):
- # Translate the location IP address
- address4 = kwargs.get("address4", None)
- if address4 and address4.startswith("172.28.1."):
- kwargs.update({
- "address4" : "178.63.73.246",
- })
-
- if self.peer_exists(peer_id, info_hash):
- self.__update_peer(peer_id, info_hash, **kwargs)
- else:
- self.__insert_peer(peer_id, info_hash, **kwargs)
-
- def complete(self, info_hash):
- ret = self.db.get("SELECT COUNT(*) AS c FROM tracker \
- WHERE hash = %s AND left_data = 0", info_hash)
-
- if ret:
- return ret.c
-
- def incomplete(self, info_hash):
- ret = self.db.get("SELECT COUNT(*) AS c FROM tracker \
- WHERE hash = %s AND left_data > 0", info_hash)
-
- if ret:
- return ret.c
-
- def handle_event(self, event, peer_id, info_hash, **kwargs):
- # stopped
- if event == "stopped":
- self.remove_peer(peer_id, info_hash)
-
- def peer_exists(self, peer_id, info_hash):
- ret = self.db.get("SELECT COUNT(*) AS c FROM tracker \
- WHERE id = %s AND hash = %s", peer_id, info_hash)
-
- if ret and ret.c > 0:
- return True
-
- return False
-
- def __insert_peer(self, peer_id, info_hash, address6=None, port6=None, address4=None, port4=None, left_data=0, **kwargs):
- self.db.execute("INSERT INTO tracker(id, hash, address6, port6, address4, port4, left_data) \
- VALUES(%s, %s, %s, %s, %s, %s, %s)", peer_id, info_hash, address6, port6, address4, port4, left_data)
-
- def __update_peer(self, peer_id, info_hash, address6=None, port6=None,
- address4=None, port4=None, downloaded=None, uploaded=None, left_data=None):
- query = "UPDATE tracker SET last_update = NOW()"
- args = []
-
- if address6:
- query += ", address6 = %s"
- args.append(address6)
-
- if port6:
- query += ", port6 = %s"
- args.append(port6)
-
- if address4:
- query += ", address4 = %s"
- args.append(address4)
-
- if port4:
- query += ", port4 = %s"
- args.append(port4)
-
- if downloaded:
- query += ", downloaded = %s"
- args.append(downloaded)
-
- if uploaded:
- query += ", uploaded = %s"
- args.append(uploaded)
-
- if left_data:
- query += ", left_data = %s"
- args.append(left_data)
-
- query += " WHERE id = %s AND hash = %s"
- args += [peer_id, info_hash]
-
- self.db.execute(query, *args)
-
- def remove_peer(self, peer_id, info_hash):
- self.db.execute("DELETE FROM tracker \
- WHERE id = %s AND hash = %s", peer_id, info_hash)
-
- def scrape(self, info_hashes):
- ret = {
- "files" : {},
- "flags" : {
- "min_request_interval" : self.interval,
- }
- }
-
- if info_hashes:
- for info_hash in info_hashes:
- ret["files"][info_hash] = {
- "complete" : self.complete(info_hash),
- "incomplete" : self.incomplete(info_hash),
- "downloaded" : 0,
- }
-
- return ret
-
-
##### This is borrowed from the bittorrent client libary #####
def decode_int(x, f):