]>
git.ipfire.org Git - people/shoehn/ipfire.org.git/blob - www/webapp/handlers.py
14 import tornado
.httpclient
18 from banners
import banners
19 from helpers
import size
, Item
21 from mirrors
import mirrors
23 from releases
import releases
24 from torrent
import tracker
, bencode
, bdecode
, decode_hex
30 class BaseHandler(tornado
.web
.RequestHandler
):
31 def get_user_locale(self
):
32 uri
= self
.request
.uri
.split("/")
34 for lang
in tornado
.locale
.get_supported_locales(None):
35 if lang
[:2] == uri
[1]:
36 return tornado
.locale
.get(lang
)
39 def render_args(self
):
41 "banner" : banners
.get(),
42 "lang" : self
.locale
.code
[:2],
43 "langs" : [l
[:2] for l
in tornado
.locale
.get_supported_locales(None)],
44 "lang_link" : self
.lang_link
,
46 "title" : "no title given",
47 "server" : self
.request
.host
.replace("ipfire", "<span>ipfire</span>"),
48 "uri" : self
.request
.uri
,
49 "year" : time
.strftime("%Y"),
52 def render(self
, *args
, **kwargs
):
53 nargs
= self
.render_args
55 nargs
["hostname"] = self
.request
.host
56 tornado
.web
.RequestHandler
.render(self
, *args
, **nargs
)
59 return "/%s/%s" % (self
.locale
.code
[:2], s
)
61 def lang_link(self
, lang
):
62 return "/%s/%s" % (lang
, self
.request
.uri
[4:])
64 def get_error_html(self
, status_code
, **kwargs
):
65 if status_code
in (404, 500):
66 render_args
= self
.render_args
69 "exception" : kwargs
.get("exception", None),
70 "message" : httplib
.responses
[status_code
],
72 return self
.render_string("error-%s.html" % status_code
, **render_args
)
74 return tornado
.web
.RequestHandler
.get_error_html(self
, status_code
, **kwargs
)
78 return self
.application
.hash_db
80 class MainHandler(BaseHandler
):
82 lang
= self
.locale
.code
[:2]
83 self
.redirect("/%s/index" % (lang
))
86 class DownloadHandler(BaseHandler
):
88 self
.render("downloads.html", release
=releases
.latest
)
91 class DownloadAllHandler(BaseHandler
):
93 self
.render("downloads-all.html", releases
=releases
)
96 class DownloadDevelopmentHandler(BaseHandler
):
98 self
.render("downloads-development.html", releases
=releases
)
101 class DownloadTorrentHandler(BaseHandler
):
102 tracker_url
= "http://tracker.ipfire.org:6969/stats?format=txt&mode=tpbs"
104 @tornado.web
.asynchronous
106 http
= tornado
.httpclient
.AsyncHTTPClient()
107 http
.fetch(self
.tracker_url
, callback
=self
.async_callback(self
.on_response
))
109 def on_response(self
, response
):
110 torrents
= releases
.torrents
112 if response
.code
== 200:
113 for line
in response
.body
.split("\n"):
114 if not line
: continue
115 hash, seeds
, peers
= line
.split(":")
122 self
.render("downloads-torrents.html",
125 request_time
=response
.request_time
,
126 tracker
=urlparse
.urlparse(response
.request
.url
).netloc
)
129 class DownloadMirrorHandler(BaseHandler
):
131 self
.render("downloads-mirrors.html", mirrors
=mirrors
)
134 class StaticHandler(BaseHandler
):
136 def static_path(self
):
137 return os
.path
.join(self
.application
.settings
["template_path"], "static")
140 def static_files(self
):
142 for filename
in os
.listdir(self
.static_path
):
143 if filename
.endswith(".html"):
147 def get(self
, name
=None):
148 name
= "%s.html" % name
150 if not name
in self
.static_files
:
151 raise tornado
.web
.HTTPError(404)
153 self
.render("static/%s" % name
)
156 class IndexHandler(BaseHandler
):
158 self
.render("index.html", news
=news
)
161 class NewsHandler(BaseHandler
):
163 self
.render("news.html", news
=news
)
166 class BuildHandler(BaseHandler
):
174 for build
in builds
.find():
175 if (time
.time() - float(build
.get("date"))) < 12*60*60:
176 self
.builds
["<12h"].append(build
)
177 elif (time
.time() - float(build
.get("date"))) < 24*60*60:
178 self
.builds
[">12h"].append(build
)
180 self
.builds
[">24h"].append(build
)
182 for l
in self
.builds
.values():
186 self
.render("builds.html", builds
=self
.builds
)
189 class UrielBaseHandler(BaseHandler
):
190 #db = uriel.Database()
193 class UrielHandler(UrielBaseHandler
):
198 class SourceHandler(BaseHandler
):
200 source_path
= "/srv/sources"
203 for dir, subdirs
, files
in os
.walk(source_path
):
207 if file in [f
["name"] for f
in fileobjects
]:
210 hash = self
.hash_db
.get_hash(os
.path
.join(dir, file))
213 hash = "0000000000000000000000000000000000000000"
216 "dir" : dir[len(source_path
)+1:],
219 "size" : size(os
.path
.getsize(os
.path
.join(source_path
, dir, file))),
222 fileobjects
.sort(key
=operator
.itemgetter("name"))
224 self
.render("sources.html", files
=fileobjects
)
227 class SourceDownloadHandler(BaseHandler
):
228 def head(self
, path
):
229 self
.get(path
, include_body
=False)
231 def get(self
, path
, include_body
=True):
232 source_path
= "/srv/sources"
234 path
= os
.path
.abspath(os
.path
.join(source_path
, path
[1:]))
236 if not path
.startswith(source_path
):
237 raise tornado
.web
.HTTPError(403)
238 if not os
.path
.exists(path
):
239 raise tornado
.web
.HTTPError(404)
241 stat_result
= os
.stat(path
)
242 modified
= datetime
.datetime
.fromtimestamp(stat_result
[stat
.ST_MTIME
])
244 self
.set_header("Last-Modified", modified
)
245 self
.set_header("Content-Length", stat_result
[stat
.ST_SIZE
])
247 mime_type
, encoding
= mimetypes
.guess_type(path
)
249 self
.set_header("Content-Type", mime_type
)
251 hash = self
.hash_db
.get_hash(path
)
253 self
.set_header("X-Hash-Sha1", "%s" % hash)
257 file = open(path
, "r")
259 self
.write(file.read())
264 class DownloadFileHandler(BaseHandler
):
266 for mirror
in mirrors
.with_file(path
):
267 if not mirror
.reachable
:
270 self
.redirect(mirror
.url
+ path
)
273 raise tornado
.web
.HTTPError(404)
275 def get_error_html(self
, status_code
, **kwargs
):
276 return tornado
.web
.RequestHandler
.get_error_html(self
, status_code
, **kwargs
)
279 class RSSHandler(BaseHandler
):
282 for item
in news
.get(15):
283 item
= Item(**item
.args
.copy())
284 for attr
in ("subject", "content"):
285 if type(item
[attr
]) == type({}):
286 item
[attr
] = item
[attr
][lang
]
289 self
.set_header("Content-Type", "application/rss+xml")
290 self
.render("rss.xml", items
=items
, lang
=lang
)
293 class TrackerBaseHandler(tornado
.web
.RequestHandler
):
294 def get_hexencoded_argument(self
, name
, all
=False):
296 arguments
= self
.request
.arguments
[name
]
301 for argument
in arguments
:
302 arguments_new
.append(decode_hex(argument
))
304 arguments
= arguments_new
311 def send_tracker_error(self
, error_message
):
312 self
.write(bencode({"failure reason" : error_message
}))
315 class TrackerAnnounceHandler(TrackerBaseHandler
):
317 self
.set_header("Content-Type", "text/plain")
319 info_hash
= self
.get_hexencoded_argument("info_hash")
321 self
.send_tracker_error("Your client forgot to send your torrent's info_hash.")
325 "id" : self
.get_hexencoded_argument("peer_id"),
326 "ip" : self
.get_argument("ip", None),
327 "port" : self
.get_argument("port", None),
328 "downloaded" : self
.get_argument("downloaded", 0),
329 "uploaded" : self
.get_argument("uploaded", 0),
330 "left" : self
.get_argument("left", 0),
333 event
= self
.get_argument("event", "")
334 if not event
in ("started", "stopped", "completed", ""):
335 self
.send_tracker_error("Got unknown event")
339 if peer
["ip"].startswith("10.") or \
340 peer
["ip"].startswith("172.") or \
341 peer
["ip"].startswith("192.168."):
342 peer
["ip"] = self
.request
.remote_ip
345 peer
["port"] = int(peer
["port"])
347 if peer
["port"] < 0 or peer
["port"] > 65535:
348 self
.send_tracker_error("Port number is not in valid range")
352 "started" : tracker
.event_started
,
353 "stopped" : tracker
.event_stopped
,
354 "completed" : tracker
.event_completed
,
358 eventhandlers
[event
](info_hash
, peer
["id"])
360 tracker
.update(hash=info_hash
, **peer
)
362 no_peer_id
= self
.get_argument("no_peer_id", False)
363 numwant
= self
.get_argument("numwant", tracker
.numwant
)
366 "tracker id" : tracker
.id,
367 "interval" : tracker
.interval
,
368 "min interval" : tracker
.min_interval
,
369 "peers" : tracker
.get_peers(info_hash
, limit
=numwant
,
370 random
=True, no_peer_id
=no_peer_id
),
371 "complete" : tracker
.complete(info_hash
),
372 "incomplete" : tracker
.incomplete(info_hash
),
377 class TrackerScrapeHandler(TrackerBaseHandler
):
379 info_hashes
= self
.get_hexencoded_argument("info_hash", all
=True)
381 self
.write(bencode(tracker
.scrape(hashes
=info_hashes
)))