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