]>
git.ipfire.org Git - ipfire.org.git/blob - www/webapp/handlers.py
16 import tornado
.database
17 import tornado
.httpclient
21 from banners
import banners
22 from helpers
import size
, Item
24 from mirrors
import mirrors
26 from releases
import releases
27 from torrent
import tracker
, bencode
, bdecode
, decode_hex
35 class BaseHandler(tornado
.web
.RequestHandler
):
36 def get_user_locale(self
):
37 uri
= self
.request
.uri
.split("/")
39 for lang
in tornado
.locale
.get_supported_locales(None):
40 if lang
[:2] == uri
[1]:
41 return tornado
.locale
.get(lang
)
44 def render_args(self
):
46 "banner" : banners
.get(),
47 "lang" : self
.locale
.code
[:2],
48 "langs" : [l
[:2] for l
in tornado
.locale
.get_supported_locales(None)],
49 "lang_link" : self
.lang_link
,
51 "title" : "no title given",
52 "server" : self
.request
.host
.replace("ipfire", "<span>ipfire</span>"),
53 "uri" : self
.request
.uri
,
54 "year" : time
.strftime("%Y"),
57 def render(self
, *args
, **kwargs
):
58 nargs
= self
.render_args
60 nargs
["hostname"] = self
.request
.host
61 tornado
.web
.RequestHandler
.render(self
, *args
, **nargs
)
64 return "/%s/%s" % (self
.locale
.code
[:2], s
)
66 def lang_link(self
, lang
):
67 return "/%s/%s" % (lang
, self
.request
.uri
[4:])
69 def get_error_html(self
, status_code
, **kwargs
):
70 if status_code
in (404, 500):
71 render_args
= self
.render_args
74 "exception" : kwargs
.get("exception", None),
75 "message" : httplib
.responses
[status_code
],
77 return self
.render_string("error-%s.html" % status_code
, **render_args
)
79 return tornado
.web
.RequestHandler
.get_error_html(self
, status_code
, **kwargs
)
83 return self
.application
.hash_db
87 return self
.application
.planet_db
91 return self
.application
.user_db
94 class MainHandler(BaseHandler
):
96 lang
= self
.locale
.code
[:2]
97 self
.redirect("/%s/index" % (lang
))
100 class DownloadHandler(BaseHandler
):
102 self
.render("downloads.html", release
=releases
.latest
)
105 class DownloadAllHandler(BaseHandler
):
107 self
.render("downloads-all.html", releases
=releases
)
110 class DownloadDevelopmentHandler(BaseHandler
):
112 self
.render("downloads-development.html", releases
=releases
)
115 class DownloadTorrentHandler(BaseHandler
):
116 tracker_url
= "http://tracker.ipfire.org:6969/stats?format=txt&mode=tpbs"
118 @tornado.web
.asynchronous
120 http
= tornado
.httpclient
.AsyncHTTPClient()
121 http
.fetch(self
.tracker_url
, callback
=self
.async_callback(self
.on_response
))
123 def on_response(self
, response
):
124 torrents
= releases
.torrents
126 if response
.code
== 200:
127 for line
in response
.body
.split("\n"):
128 if not line
: continue
129 hash, seeds
, peers
= line
.split(":")
136 self
.render("downloads-torrents.html",
139 request_time
=response
.request_time
,
140 tracker
=urlparse
.urlparse(response
.request
.url
).netloc
)
143 class DownloadMirrorHandler(BaseHandler
):
145 self
.render("downloads-mirrors.html", mirrors
=mirrors
)
148 class StaticHandler(BaseHandler
):
150 def static_path(self
):
151 return os
.path
.join(self
.application
.settings
["template_path"], "static")
154 def static_files(self
):
156 for filename
in os
.listdir(self
.static_path
):
157 if filename
.endswith(".html"):
161 def get(self
, name
=None):
162 name
= "%s.html" % name
164 if not name
in self
.static_files
:
165 raise tornado
.web
.HTTPError(404)
167 self
.render("static/%s" % name
)
170 class IndexHandler(BaseHandler
):
172 self
.render("index.html", news
=news
)
175 class NewsHandler(BaseHandler
):
177 self
.render("news.html", news
=news
)
180 class BuildHandler(BaseHandler
):
188 for build
in builds
.find():
189 if (time
.time() - float(build
.get("date"))) < 12*60*60:
190 self
.builds
["<12h"].append(build
)
191 elif (time
.time() - float(build
.get("date"))) < 24*60*60:
192 self
.builds
[">12h"].append(build
)
194 self
.builds
[">24h"].append(build
)
196 for l
in self
.builds
.values():
200 self
.render("builds.html", builds
=self
.builds
)
203 class UrielBaseHandler(BaseHandler
):
204 #db = uriel.Database()
207 class UrielHandler(UrielBaseHandler
):
212 class SourceHandler(BaseHandler
):
214 source_path
= "/srv/sources"
217 for dir, subdirs
, files
in os
.walk(source_path
):
221 if file in [f
["name"] for f
in fileobjects
]:
224 hash = self
.hash_db
.get_hash(os
.path
.join(dir, file))
227 hash = "0000000000000000000000000000000000000000"
230 "dir" : dir[len(source_path
)+1:],
233 "size" : size(os
.path
.getsize(os
.path
.join(source_path
, dir, file))),
236 fileobjects
.sort(key
=operator
.itemgetter("name"))
238 self
.render("sources.html", files
=fileobjects
)
241 class SourceDownloadHandler(BaseHandler
):
242 def head(self
, path
):
243 self
.get(path
, include_body
=False)
245 def get(self
, path
, include_body
=True):
246 source_path
= "/srv/sources"
248 path
= os
.path
.abspath(os
.path
.join(source_path
, path
[1:]))
250 if not path
.startswith(source_path
):
251 raise tornado
.web
.HTTPError(403)
252 if not os
.path
.exists(path
):
253 raise tornado
.web
.HTTPError(404)
255 stat_result
= os
.stat(path
)
256 modified
= datetime
.datetime
.fromtimestamp(stat_result
[stat
.ST_MTIME
])
258 self
.set_header("Last-Modified", modified
)
259 self
.set_header("Content-Length", stat_result
[stat
.ST_SIZE
])
261 mime_type
, encoding
= mimetypes
.guess_type(path
)
263 self
.set_header("Content-Type", mime_type
)
265 hash = self
.hash_db
.get_hash(path
)
267 self
.set_header("X-Hash-Sha1", "%s" % hash)
271 file = open(path
, "r")
273 self
.write(file.read())
278 class DownloadFileHandler(BaseHandler
):
280 for mirror
in mirrors
.with_file(path
):
281 if not mirror
.reachable
:
284 self
.redirect(mirror
.url
+ path
)
287 raise tornado
.web
.HTTPError(404)
289 def get_error_html(self
, status_code
, **kwargs
):
290 return tornado
.web
.RequestHandler
.get_error_html(self
, status_code
, **kwargs
)
293 class RSSHandler(BaseHandler
):
296 for item
in news
.get(15):
297 item
= Item(**item
.args
.copy())
298 for attr
in ("subject", "content"):
299 if type(item
[attr
]) == type({}):
300 item
[attr
] = item
[attr
][lang
]
303 self
.set_header("Content-Type", "application/rss+xml")
304 self
.render("rss.xml", items
=items
, lang
=lang
)
308 class TrackerBaseHandler(tornado
.web
.RequestHandler
):
309 def get_hexencoded_argument(self
, name
, all
=False):
311 arguments
= self
.request
.arguments
[name
]
316 for argument
in arguments
:
317 arguments_new
.append(decode_hex(argument
))
319 arguments
= arguments_new
326 def send_tracker_error(self
, error_message
):
327 self
.write(bencode({"failure reason" : error_message
}))
330 class TrackerAnnounceHandler(TrackerBaseHandler
):
332 self
.set_header("Content-Type", "text/plain")
334 info_hash
= self
.get_hexencoded_argument("info_hash")
336 self
.send_tracker_error("Your client forgot to send your torrent's info_hash.")
340 "id" : self
.get_hexencoded_argument("peer_id"),
341 "ip" : self
.get_argument("ip", None),
342 "port" : self
.get_argument("port", None),
343 "downloaded" : self
.get_argument("downloaded", 0),
344 "uploaded" : self
.get_argument("uploaded", 0),
345 "left" : self
.get_argument("left", 0),
348 event
= self
.get_argument("event", "")
349 if not event
in ("started", "stopped", "completed", ""):
350 self
.send_tracker_error("Got unknown event")
354 if peer
["ip"].startswith("10.") or \
355 peer
["ip"].startswith("172.") or \
356 peer
["ip"].startswith("192.168."):
357 peer
["ip"] = self
.request
.remote_ip
360 peer
["port"] = int(peer
["port"])
362 if peer
["port"] < 0 or peer
["port"] > 65535:
363 self
.send_tracker_error("Port number is not in valid range")
367 "started" : tracker
.event_started
,
368 "stopped" : tracker
.event_stopped
,
369 "completed" : tracker
.event_completed
,
373 eventhandlers
[event
](info_hash
, peer
["id"])
375 tracker
.update(hash=info_hash
, **peer
)
377 no_peer_id
= self
.get_argument("no_peer_id", False)
378 numwant
= self
.get_argument("numwant", tracker
.numwant
)
381 "tracker id" : tracker
.id,
382 "interval" : tracker
.interval
,
383 "min interval" : tracker
.min_interval
,
384 "peers" : tracker
.get_peers(info_hash
, limit
=numwant
,
385 random
=True, no_peer_id
=no_peer_id
),
386 "complete" : tracker
.complete(info_hash
),
387 "incomplete" : tracker
.incomplete(info_hash
),
392 class TrackerScrapeHandler(TrackerBaseHandler
):
394 info_hashes
= self
.get_hexencoded_argument("info_hash", all
=True)
396 self
.write(bencode(tracker
.scrape(hashes
=info_hashes
)))
399 class PlanetBaseHandler(BaseHandler
):
402 return self
.application
.planet_db
405 class PlanetMainHandler(PlanetBaseHandler
):
407 authors
= self
.db
.query("SELECT DISTINCT author_id FROM entries")
408 authors
= [a
["author_id"] for a
in authors
]
411 for user
in self
.user_db
.users
:
412 if user
.id in authors
:
415 entries
= self
.db
.query("SELECT * FROM entries "
416 "ORDER BY published DESC LIMIT 3")
418 for entry
in entries
:
419 entry
.author
= self
.user_db
.get_user_by_id(entry
.author_id
)
421 self
.render("planet-main.html", entries
=entries
, authors
=users
)
424 class PlanetUserHandler(PlanetBaseHandler
):
426 if not user
in [u
.name
for u
in self
.user_db
.users
]:
427 raise tornado
.web
.HTTPError(404, "User is unknown")
429 user
= self
.user_db
.get_user_by_name(user
)
431 entries
= self
.db
.query("SELECT * FROM entries "
432 "WHERE author_id = '%s' ORDER BY published DESC" % (user
.id))
434 self
.render("planet-user.html", entries
=entries
, user
=user
)
437 class PlanetPostingHandler(PlanetBaseHandler
):
439 entry
= self
.db
.get("SELECT * FROM entries WHERE slug = %s", slug
)
442 raise tornado
.web
.HTTPError(404)
444 user
= self
.user_db
.get_user_by_id(entry
.author_id
)
447 self
.render("planet-posting.html", entry
=entry
, user
=user
)