]> git.ipfire.org Git - people/shoehn/ipfire.org.git/blame - webapp/handlers_tracker.py
Major update of the webapp.
[people/shoehn/ipfire.org.git] / webapp / handlers_tracker.py
CommitLineData
940227cb
MT
1#!/usr/bin/python
2
9068dba1 3import re
940227cb
MT
4import tornado.web
5
6from backend.tracker import bencode, bdecode, decode_hex
7from handlers_base import *
8
9
10class TrackerIndexHandler(BaseHandler):
11 def get(self):
938d083d 12 releases = self.releases.get_all()
940227cb 13
938d083d
MT
14 limit = 5
15 releases = releases[:limit]
940227cb 16
938d083d 17 self.render("tracker-torrents.html", releases=releases)
940227cb
MT
18
19
20class TrackerDetailHandler(BaseHandler):
938d083d
MT
21 def get(self, torrent_hash):
22 file = self.releases.get_file_for_torrent_hash(torrent_hash)
940227cb 23
938d083d
MT
24 if not file:
25 raise tornado.web.HTTPError(404, "Could not find torrent file for hash: %s" % torrent_hash)
940227cb 26
938d083d
MT
27 peers = self.tracker.get_peers(torrent_hash)
28 seeds = self.tracker.get_seeds(torrent_hash)
940227cb 29
938d083d
MT
30 self.render("tracker-torrent-detail.html", release=file.release,
31 file=file, peers=peers, seeds=seeds)
940227cb
MT
32
33
fadcfd00
MT
34class TrackerDownloadHandler(BaseHandler):
35 def get(self, torrent_hash):
938d083d 36 file = self.releases.get_file_for_torrent_hash(torrent_hash)
fadcfd00
MT
37
38 if not file:
938d083d 39 raise tornado.web.HTTPError(404, "Could not find torrent file for hash: %s" % torrent_hash)
fadcfd00
MT
40
41 # Redirect the user to the download redirector.
938d083d 42 self.redirect("http://downloads.ipfire.org/%s.torrent" % file.filename)
fadcfd00
MT
43
44
9068dba1 45class TrackerBaseHandler(BaseHandler):
940227cb
MT
46 def get_hexencoded_argument(self, name, all=False):
47 try:
48 arguments = self.request.arguments[name]
49 except KeyError:
50 return None
51
52 arguments_new = []
53 for argument in arguments:
54 arguments_new.append(decode_hex(argument))
55
56 arguments = arguments_new
57
58 if all:
59 return arguments
60
61 return arguments[0]
62
63 def send_tracker_error(self, error_message):
9068dba1
MT
64 msg = bencode({"failure reason" : error_message })
65 self.finish(msg)
940227cb
MT
66
67
68class TrackerAnnounceHandler(TrackerBaseHandler):
9068dba1 69 def prepare(self):
940227cb
MT
70 self.set_header("Content-Type", "text/plain")
71
9068dba1
MT
72 def get_ipv6_address(self, default_port):
73 # Get the external IP address of the client.
74 addr = self.get_remote_ip()
75
76 if ":" in addr:
77 return addr, default_port
78
79 # IPv6
80 ipv6 = self.get_argument("ipv6", None)
81 if ipv6:
82 port = default_port
83
84 m = re.match("^\[(.*)\]\:(\d)$", ipv6)
85 if m:
86 ipv6, port = (m.group(1), m.group(2))
87
88 return ipv6, port
89
90 return None, None
91
92 def get_ipv4_address(self, default_port):
93 # Get the external IP address of the client.
94 addr = self.get_remote_ip()
95
96 if not ":" in addr:
97 return addr, default_port
98
99 # IPv4
100 ipv4 = self.get_argument("ipv4", None)
101 if ipv4:
102 return ipv4, default_port
103
104 ip = self.get_argument("ip", None)
105 if ip:
106 return ip, default_port
107
108 return None, None
109
110 def get_port(self):
111 # Get the port and check it for sanity
112 port = self.get_argument("port", None)
113
114 try:
115 port = int(port)
116
117 if port < 0 or port > 65535:
118 raise ValueError
119 except (TypeError, ValueError):
120 port = None
121
122 return port
123
124 def get(self):
125 # Get the info hash
940227cb
MT
126 info_hash = self.get_hexencoded_argument("info_hash")
127 if not info_hash:
9068dba1 128 self.send_tracker_error("Your client forgot to send your torrent's info_hash")
940227cb
MT
129 return
130
9068dba1
MT
131 # Get the peer id
132 peer_id = self.get_hexencoded_argument("peer_id")
f611ae02 133
9068dba1
MT
134 # Get the port and check it for sanity
135 port = self.get_port()
136 if not port:
137 self.send_tracker_error("Invalid port number or port number missing")
940227cb
MT
138 return
139
9068dba1
MT
140 addr_ipv6, port_ipv6 = self.get_ipv6_address(port)
141 addr_ipv4, port_ipv4 = self.get_ipv4_address(port)
940227cb 142
9068dba1
MT
143 # Handle events
144 event = self.get_argument("event", None)
145 if event:
146 if not event in ("started", "stopped", "completed"):
147 self.send_tracker_error("Got unknown event")
940227cb
MT
148 return
149
9068dba1
MT
150 self.tracker.handle_event(event, peer_id, info_hash,
151 address6=addr_ipv6, port6=port_ipv6, address4=addr_ipv4, port4=port_ipv4)
940227cb 152
9068dba1
MT
153 peer_info = {
154 "address6" : addr_ipv6,
155 "port6" : port_ipv6,
156 "address4" : addr_ipv4,
157 "port4" : port_ipv4,
158 "downloaded" : self.get_argument("downloaded", 0),
159 "uploaded" : self.get_argument("uploaded", 0),
160 "left_data" : self.get_argument("left", 0),
161 }
940227cb 162
9068dba1 163 self.tracker.update_peer(peer_id, info_hash, **peer_info)
940227cb
MT
164
165 no_peer_id = self.get_argument("no_peer_id", False)
166 numwant = self.get_argument("numwant", self.tracker.numwant)
167
9068dba1
MT
168 peers = self.tracker.get_peers(info_hash, limit=numwant, no_peer_id=no_peer_id)
169
170 response = bencode({
171 "tracker id" : self.tracker.tracker_id,
172 "interval" : self.tracker.interval,
940227cb 173 "min interval" : self.tracker.min_interval,
9068dba1
MT
174 "peers" : peers,
175 "complete" : self.tracker.complete(info_hash),
176 "incomplete" : self.tracker.incomplete(info_hash),
177 })
178 self.finish(response)
179
180 def on_finish(self):
181 """
182 Cleanup after every request.
183 """
184 self.tracker.cleanup_peers()
940227cb
MT
185
186
187class TrackerScrapeHandler(TrackerBaseHandler):
188 def get(self):
189 info_hashes = self.get_hexencoded_argument("info_hash", all=True)
190
9068dba1
MT
191 response = self.tracker.scrape(info_hashes)
192
193 self.finish(bencode(response))