]>
Commit | Line | Data |
---|---|---|
940227cb MT |
1 | #!/usr/bin/python |
2 | ||
3 | import tornado.web | |
4 | ||
5 | from backend.tracker import bencode, bdecode, decode_hex | |
6 | from handlers_base import * | |
7 | ||
8 | ||
9 | class TrackerIndexHandler(BaseHandler): | |
10 | def get(self): | |
938d083d | 11 | releases = self.releases.get_all() |
940227cb | 12 | |
938d083d MT |
13 | limit = 5 |
14 | releases = releases[:limit] | |
940227cb | 15 | |
938d083d | 16 | self.render("tracker-torrents.html", releases=releases) |
940227cb MT |
17 | |
18 | ||
19 | class TrackerDetailHandler(BaseHandler): | |
938d083d MT |
20 | def get(self, torrent_hash): |
21 | file = self.releases.get_file_for_torrent_hash(torrent_hash) | |
940227cb | 22 | |
938d083d MT |
23 | if not file: |
24 | raise tornado.web.HTTPError(404, "Could not find torrent file for hash: %s" % torrent_hash) | |
940227cb | 25 | |
938d083d MT |
26 | peers = self.tracker.get_peers(torrent_hash) |
27 | seeds = self.tracker.get_seeds(torrent_hash) | |
940227cb | 28 | |
938d083d MT |
29 | self.render("tracker-torrent-detail.html", release=file.release, |
30 | file=file, peers=peers, seeds=seeds) | |
940227cb MT |
31 | |
32 | ||
fadcfd00 MT |
33 | class TrackerDownloadHandler(BaseHandler): |
34 | def get(self, torrent_hash): | |
938d083d | 35 | file = self.releases.get_file_for_torrent_hash(torrent_hash) |
fadcfd00 MT |
36 | |
37 | if not file: | |
938d083d | 38 | raise tornado.web.HTTPError(404, "Could not find torrent file for hash: %s" % torrent_hash) |
fadcfd00 MT |
39 | |
40 | # Redirect the user to the download redirector. | |
938d083d | 41 | self.redirect("http://downloads.ipfire.org/%s.torrent" % file.filename) |
fadcfd00 MT |
42 | |
43 | ||
940227cb MT |
44 | #class TrackerTorrentsHandler(BaseHandler): |
45 | # @property | |
46 | # def tracker(self): | |
47 | # return self.tracker | |
48 | # | |
49 | # def get(self): | |
50 | # releases = [] | |
51 | # | |
52 | # for release in self.releases.get_all(): | |
53 | # if not release.torrent_hash: | |
54 | # continue | |
55 | # | |
56 | # release.torrent_hash = release.torrent_hash.lower() | |
57 | # | |
58 | # release.torrent_peers = self.tracker.incomplete(release.torrent_hash) | |
59 | # release.torrent_seeds = self.tracker.complete(release.torrent_hash) | |
60 | # | |
61 | # releases.append(release) | |
62 | # | |
63 | # self.render("tracker-torrents.html", releases=releases) | |
64 | ||
65 | ||
66 | class TrackerBaseHandler(tornado.web.RequestHandler): | |
67 | @property | |
68 | def tracker(self): | |
69 | return backend.Tracker() | |
70 | ||
71 | def get_hexencoded_argument(self, name, all=False): | |
72 | try: | |
73 | arguments = self.request.arguments[name] | |
74 | except KeyError: | |
75 | return None | |
76 | ||
77 | arguments_new = [] | |
78 | for argument in arguments: | |
79 | arguments_new.append(decode_hex(argument)) | |
80 | ||
81 | arguments = arguments_new | |
82 | ||
83 | if all: | |
84 | return arguments | |
85 | ||
86 | return arguments[0] | |
87 | ||
88 | def send_tracker_error(self, error_message): | |
89 | self.write(bencode({"failure reason" : error_message })) | |
90 | self.finish() | |
91 | ||
92 | ||
93 | class TrackerAnnounceHandler(TrackerBaseHandler): | |
94 | def get(self): | |
95 | self.set_header("Content-Type", "text/plain") | |
96 | ||
97 | info_hash = self.get_hexencoded_argument("info_hash") | |
98 | if not info_hash: | |
99 | self.send_tracker_error("Your client forgot to send your torrent's info_hash.") | |
100 | return | |
101 | ||
f611ae02 MT |
102 | # Fix for clients behind a proxy that sends "X-Forwarded-For". |
103 | ip_addr = self.request.remote_ip.split(", ") | |
104 | if ip_addr: | |
105 | ip_addr = ip_addr[-1] | |
106 | ||
940227cb MT |
107 | peer = { |
108 | "id" : self.get_hexencoded_argument("peer_id"), | |
f611ae02 | 109 | "ip" : ip_addr, |
940227cb MT |
110 | "port" : self.get_argument("port", None), |
111 | "downloaded" : self.get_argument("downloaded", 0), | |
112 | "uploaded" : self.get_argument("uploaded", 0), | |
113 | "left" : self.get_argument("left", 0), | |
114 | } | |
115 | ||
116 | event = self.get_argument("event", "") | |
117 | if not event in ("started", "stopped", "completed", ""): | |
118 | self.send_tracker_error("Got unknown event") | |
119 | return | |
120 | ||
121 | if peer["port"]: | |
122 | peer["port"] = int(peer["port"]) | |
123 | ||
124 | if peer["port"] < 0 or peer["port"] > 65535: | |
125 | self.send_tracker_error("Port number is not in valid range") | |
126 | return | |
127 | ||
128 | eventhandlers = { | |
129 | "started" : self.tracker.event_started, | |
130 | "stopped" : self.tracker.event_stopped, | |
131 | "completed" : self.tracker.event_completed, | |
132 | } | |
133 | ||
134 | if event: | |
135 | eventhandlers[event](info_hash, peer["id"]) | |
136 | ||
137 | self.tracker.update(hash=info_hash, **peer) | |
138 | ||
139 | no_peer_id = self.get_argument("no_peer_id", False) | |
140 | numwant = self.get_argument("numwant", self.tracker.numwant) | |
141 | ||
142 | self.write(bencode({ | |
143 | "tracker id" : self.tracker.id, | |
144 | "interval" : self.tracker.interval, | |
145 | "min interval" : self.tracker.min_interval, | |
146 | "peers" : self.tracker.get_peers(info_hash, limit=numwant, | |
147 | random=True, no_peer_id=no_peer_id), | |
148 | "complete" : self.tracker.complete(info_hash), | |
149 | "incomplete" : self.tracker.incomplete(info_hash), | |
150 | })) | |
151 | self.finish() | |
152 | ||
153 | ||
154 | class TrackerScrapeHandler(TrackerBaseHandler): | |
155 | def get(self): | |
156 | info_hashes = self.get_hexencoded_argument("info_hash", all=True) | |
157 | ||
158 | self.write(bencode(self.tracker.scrape(hashes=info_hashes))) | |
159 | self.finish() |