]>
git.ipfire.org Git - 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
32 class BaseHandler(tornado
.web
.RequestHandler
):
33 def get_user_locale(self
):
34 uri
= self
.request
.uri
.split("/")
36 for lang
in tornado
.locale
.get_supported_locales(None):
37 if lang
[:2] == uri
[1]:
38 return tornado
.locale
.get(lang
)
41 def render_args(self
):
43 "banner" : banners
.get(),
44 "lang" : self
.locale
.code
[:2],
45 "langs" : [l
[:2] for l
in tornado
.locale
.get_supported_locales(None)],
46 "lang_link" : self
.lang_link
,
48 "title" : "no title given",
49 "server" : self
.request
.host
.replace("ipfire", "<span>ipfire</span>"),
50 "uri" : self
.request
.uri
,
51 "year" : time
.strftime("%Y"),
54 def render(self
, *args
, **kwargs
):
55 nargs
= self
.render_args
57 nargs
["title"] = "%s - %s" % (self
.request
.host
, nargs
["title"])
58 tornado
.web
.RequestHandler
.render(self
, *args
, **nargs
)
61 return "/%s/%s" % (self
.locale
.code
[:2], s
)
63 def lang_link(self
, lang
):
64 return "/%s/%s" % (lang
, self
.request
.uri
[4:])
66 def get_error_html(self
, status_code
, **kwargs
):
67 if status_code
in (404, 500):
68 render_args
= self
.render_args
71 "exception" : kwargs
.get("exception", None),
72 "message" : httplib
.responses
[status_code
],
74 return self
.render_string("error-%s.html" % status_code
, **render_args
)
76 return tornado
.web
.RequestHandler
.get_error_html(self
, status_code
, **kwargs
)
80 return self
.application
.hash_db
82 class MainHandler(BaseHandler
):
84 lang
= self
.locale
.code
[:2]
85 self
.redirect("/%s/index" % (lang
))
88 class DownloadHandler(BaseHandler
):
90 self
.render("downloads.html", release
=releases
.latest
)
93 class DownloadAllHandler(BaseHandler
):
95 self
.render("downloads-all.html", releases
=releases
)
98 class DownloadDevelopmentHandler(BaseHandler
):
100 self
.render("downloads-development.html", releases
=releases
)
103 class DownloadTorrentHandler(BaseHandler
):
104 tracker_url
= "http://tracker.ipfire.org:6969/stats?format=txt&mode=tpbs"
106 @tornado.web
.asynchronous
108 http
= tornado
.httpclient
.AsyncHTTPClient()
109 http
.fetch(self
.tracker_url
, callback
=self
.async_callback(self
.on_response
))
111 def on_response(self
, response
):
112 torrents
= releases
.torrents
114 if response
.code
== 200:
115 for line
in response
.body
.split("\n"):
116 if not line
: continue
117 hash, seeds
, peers
= line
.split(":")
124 self
.render("downloads-torrents.html",
127 request_time
=response
.request_time
,
128 tracker
=urlparse
.urlparse(response
.request
.url
).netloc
)
131 class DownloadMirrorHandler(BaseHandler
):
133 self
.render("downloads-mirrors.html", mirrors
=mirrors
)
136 class StaticHandler(BaseHandler
):
138 def static_path(self
):
139 return os
.path
.join(self
.application
.settings
["template_path"], "static")
142 def static_files(self
):
144 for filename
in os
.listdir(self
.static_path
):
145 if filename
.endswith(".html"):
149 def get(self
, name
=None):
150 name
= "%s.html" % name
152 if not name
in self
.static_files
:
153 raise tornado
.web
.HTTPError(404)
155 self
.render("static/%s" % name
)
158 class IndexHandler(BaseHandler
):
160 self
.render("index.html", news
=news
)
163 class NewsHandler(BaseHandler
):
165 self
.render("news.html", news
=news
)
168 class BuildHandler(BaseHandler
):
176 for build
in builds
.find():
177 if (time
.time() - float(build
.get("date"))) < 12*60*60:
178 self
.builds
["<12h"].append(build
)
179 elif (time
.time() - float(build
.get("date"))) < 24*60*60:
180 self
.builds
[">12h"].append(build
)
182 self
.builds
[">24h"].append(build
)
184 for l
in self
.builds
.values():
188 self
.render("builds.html", builds
=self
.builds
)
191 class UrielBaseHandler(BaseHandler
):
192 #db = uriel.Database()
195 class UrielHandler(UrielBaseHandler
):
200 class ApiClusterInfoHandler(BaseHandler
):
202 id = self
.get_argument("id", "null")
204 c
= cluster
.Cluster(info
["cluster"]["hostname"])
206 self
.write(simplejson
.dumps({
210 "error" : "null", }))
214 class TranslationHandler(BaseHandler
):
216 self
.render("translations.html", projects
=translations
.projects
)
219 class SourceHandler(BaseHandler
):
221 source_path
= "/srv/sources"
224 for dir, subdirs
, files
in os
.walk(source_path
):
228 if file in [f
["name"] for f
in fileobjects
]:
231 hash = self
.hash_db
.get_hash(os
.path
.join(dir, file))
234 hash = "0000000000000000000000000000000000000000"
237 "dir" : dir[len(source_path
)+1:],
240 "size" : size(os
.path
.getsize(os
.path
.join(source_path
, dir, file))),
243 fileobjects
.sort(key
=operator
.itemgetter("name"))
245 self
.render("sources.html", files
=fileobjects
)
248 class SourceDownloadHandler(BaseHandler
):
249 def head(self
, path
):
250 self
.get(path
, include_body
=False)
252 def get(self
, path
, include_body
=True):
253 source_path
= "/srv/sources"
255 path
= os
.path
.abspath(os
.path
.join(source_path
, path
[1:]))
257 if not path
.startswith(source_path
):
258 raise tornado
.web
.HTTPError(403)
259 if not os
.path
.exists(path
):
260 raise tornado
.web
.HTTPError(404)
262 stat_result
= os
.stat(path
)
263 modified
= datetime
.datetime
.fromtimestamp(stat_result
[stat
.ST_MTIME
])
265 self
.set_header("Last-Modified", modified
)
266 self
.set_header("Content-Length", stat_result
[stat
.ST_SIZE
])
268 mime_type
, encoding
= mimetypes
.guess_type(path
)
270 self
.set_header("Content-Type", mime_type
)
272 hash = self
.hash_db
.get_hash(path
)
274 self
.set_header("X-Hash-Sha1", "%s" % hash)
278 file = open(path
, "r")
280 self
.write(file.read())
285 class DownloadFileHandler(BaseHandler
):
287 for mirror
in mirrors
.with_file(path
):
288 if not mirror
.reachable
:
291 self
.redirect(mirror
.url
+ path
)
294 raise tornado
.web
.HTTPError(404)
296 def get_error_html(self
, status_code
, **kwargs
):
297 return tornado
.web
.RequestHandler
.get_error_html(self
, status_code
, **kwargs
)
300 class RSSHandler(BaseHandler
):
303 for item
in news
.get(15):
304 item
= Item(**item
.args
.copy())
305 for attr
in ("subject", "content"):
306 if type(item
[attr
]) == type({}):
307 item
[attr
] = item
[attr
][lang
]
310 self
.set_header("Content-Type", "application/rss+xml")
311 self
.render("rss.xml", items
=items
, lang
=lang
)
314 class TrackerBaseHandler(tornado
.web
.RequestHandler
):
315 def get_hexencoded_argument(self
, name
, all
=False):
317 arguments
= self
.request
.arguments
[name
]
322 for argument
in arguments
:
323 arguments_new
.append(decode_hex(argument
))
325 arguments
= arguments_new
332 def send_tracker_error(self
, error_message
):
333 self
.write(bencode({"failure reason" : error_message
}))
336 class TrackerAnnounceHandler(TrackerBaseHandler
):
338 self
.set_header("Content-Type", "text/plain")
340 info_hash
= self
.get_hexencoded_argument("info_hash")
342 self
.send_tracker_error("Your client forgot to send your torrent's info_hash.")
346 "id" : self
.get_hexencoded_argument("peer_id"),
347 "ip" : self
.get_argument("ip", None),
348 "port" : self
.get_argument("port", None),
349 "downloaded" : self
.get_argument("downloaded", 0),
350 "uploaded" : self
.get_argument("uploaded", 0),
351 "left" : self
.get_argument("left", 0),
354 event
= self
.get_argument("event", "")
355 if not event
in ("started", "stopped", "completed", ""):
356 self
.send_tracker_error("Got unknown event")
360 if peer
["ip"].startswith("10.") or \
361 peer
["ip"].startswith("172.") or \
362 peer
["ip"].startswith("192.168."):
363 peer
["ip"] = self
.request
.remote_ip
366 peer
["port"] = int(peer
["port"])
368 if peer
["port"] < 0 or peer
["port"] > 65535:
369 self
.send_tracker_error("Port number is not in valid range")
373 "started" : tracker
.event_started
,
374 "stopped" : tracker
.event_stopped
,
375 "completed" : tracker
.event_completed
,
379 eventhandlers
[event
](info_hash
, peer
["id"])
381 tracker
.update(hash=info_hash
, **peer
)
383 no_peer_id
= self
.get_argument("no_peer_id", False)
384 numwant
= self
.get_argument("numwant", tracker
.numwant
)
387 "tracker id" : tracker
.id,
388 "interval" : tracker
.interval
,
389 "min interval" : tracker
.min_interval
,
390 "peers" : tracker
.get_peers(info_hash
, limit
=numwant
,
391 random
=True, no_peer_id
=no_peer_id
),
392 "complete" : tracker
.complete(info_hash
),
393 "incomplete" : tracker
.incomplete(info_hash
),
398 class TrackerScrapeHandler(TrackerBaseHandler
):
400 info_hashes
= self
.get_hexencoded_argument("info_hash", all
=True)
402 self
.write(bencode(tracker
.scrape(hashes
=info_hashes
)))