morphbr@718: #!/usr/bin/env python morphbr@718: morphbr@718: __author__ = "Gustavo Sverzut Barbieri / Artur Duque de Souza" morphbr@718: __author_email__ = "barbieri@gmail.com / artur.souza@indt.org.br" morphbr@718: __license__ = "GPL" morphbr@723: __version__ = "0.3" morphbr@718: morphbr@718: import os morphbr@723: import cgi morphbr@723: import socket morphbr@723: import logging morphbr@723: import urlparse morphbr@718: import threading morphbr@718: import SocketServer morphbr@718: import BaseHTTPServer morphbr@723: morphbr@718: import lib.utils as utils morphbr@723: import lib.file_handler as files morphbr@723: import lib.transcoder as transcoder morphbr@718: morphbr@718: from log import Log morphbr@718: morphbr@718: __all__ = ("RequestHandler") morphbr@718: morphbr@718: class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): morphbr@718: """Class that implements an HTTP request handler for our server.""" morphbr@718: log = logging.getLogger("gms.request") morphbr@718: def_transcoder = None morphbr@718: transcoders = utils.PluginSet(transcoder.Transcoder) morphbr@718: transcoders_log = Log() morphbr@718: tid_queue = [] morphbr@718: morphbr@718: menu = { morphbr@718: "Log": "/get_log.do", morphbr@718: "Stop": "/stop-transcoder.do", morphbr@718: "Status": "/status.do", morphbr@718: "All Log": "/get_all_log.do", morphbr@718: "Version": "/version.do", morphbr@718: "Shutdown": "/shutdown.do" morphbr@718: } morphbr@718: morphbr@718: @classmethod morphbr@718: def load_plugins_transcoders(cls, directory): morphbr@718: cls.transcoders.load_from_directory(directory) morphbr@718: morphbr@718: if cls.def_transcoder is None and cls.transcoders: morphbr@718: cls.def_transcoder = cls.transcoders[0].name morphbr@718: # load_plugins_transcoders() morphbr@718: morphbr@718: morphbr@718: def do_dispatch(self, body): morphbr@718: self.url = self.path morphbr@718: pieces = urlparse.urlparse(self.path) morphbr@718: self.path = pieces[2] morphbr@718: self.query = cgi.parse_qs(pieces[4]) morphbr@718: morphbr@723: url = { morphbr@723: "/": self.serve_main, morphbr@723: "/shutdown.do": self.serve_shutdown, morphbr@723: "/stop-transcoder.do": self.serve_stop_transcoder, morphbr@723: "/status.do": self.serve_status, morphbr@723: "/version.do": self.serve_version, morphbr@723: "/new_id.do": self.serve_new_id, morphbr@723: "/get_log.do": self.serve_get_log, morphbr@723: "/get_all_log.do": self.serve_get_all_log, morphbr@723: "/stream.do": self.serve_stream, morphbr@723: "/list.do": self.serve_list, morphbr@723: } morphbr@723: morphbr@723: try: morphbr@723: url[self.path](body) morphbr@748: except KeyError: morphbr@744: try: morphbr@744: action = self.query.get("action", None) morphbr@744: if action and "stream.do" in action: morphbr@744: self.serve_stream(body) morphbr@744: elif os.path.exists("html/%s" % self.path): morphbr@744: data = open("html/%s" % self.path) morphbr@744: self.wfile.write(data.read()) morphbr@744: else: morphbr@744: self.send_error(404, "File not found") morphbr@744: except Exception, e: morphbr@744: self.log.error(e) morphbr@723: morphbr@718: # do_dispatch() morphbr@718: morphbr@718: morphbr@718: def do_GET(self): morphbr@718: self.do_dispatch(True) morphbr@718: # do_GET() morphbr@718: morphbr@718: morphbr@718: def do_HEAD(self): morphbr@718: self.do_dispatch(False) morphbr@718: # do_HEAD() morphbr@718: morphbr@718: morphbr@718: def _nav_items(self): morphbr@718: ret = "" morphbr@718: for name, url in self.menu.items(): morphbr@718: ret += utils.getHTML("menu", {"name": name, "url": url}) morphbr@718: return ret morphbr@718: # _nav_items() morphbr@718: morphbr@723: morphbr@718: def serve_main(self, body): morphbr@718: self.send_response(200) morphbr@718: self.send_header("Content-Type", "text/html") morphbr@718: self.send_header('Connection', 'close') morphbr@718: self.end_headers() morphbr@718: if body: morphbr@718: self.wfile.write(utils.getHTML("index", {"menu": self._nav_items()})) morphbr@718: # serve_main() morphbr@718: morphbr@723: morphbr@718: def serve_version(self, body): morphbr@718: self.send_response(200) morphbr@718: self.send_header("Content-Type", "text/html") morphbr@718: self.send_header('Connection', 'close') morphbr@718: self.end_headers() morphbr@718: if body: morphbr@718: self.wfile.write("Version: %s" % __version__) morphbr@723: # serve_version morphbr@718: morphbr@718: morphbr@718: def serve_shutdown(self, body): morphbr@718: self.send_response(200) morphbr@718: self.send_header("Content-Type", "text/html") morphbr@718: self.send_header('Connection', 'close') morphbr@718: self.end_headers() morphbr@718: if body: morphbr@718: self.wfile.write(utils.getHTML("shutdown")) morphbr@718: self.server.server_close() morphbr@718: # serve_shutdown() morphbr@718: morphbr@718: morphbr@723: def serve_list(self, body): morphbr@723: self.send_response(200) morphbr@723: self.send_header("Content-Type", "text/html") morphbr@723: self.send_header('Connection', 'close') morphbr@723: self.end_headers() morphbr@724: morphbr@724: if body: morphbr@723: file_list = [] morphbr@724: files.list_media_files(".transcoded", file_list) morphbr@723: output = files.FileList(map(lambda x, y: x+y, file_list, morphbr@723: ["
"]*len(file_list))) morphbr@724: self.wfile.write(output) morphbr@723: morphbr@723: # serve_list() morphbr@723: morphbr@723: morphbr@718: def serve_stop_all_transcoders(self, body): morphbr@718: self.send_response(200) morphbr@718: self.send_header("Content-Type", "text/html") morphbr@718: self.send_header('Connection', 'close') morphbr@718: self.end_headers() morphbr@718: if body: morphbr@718: self.server.stop_transcoders() morphbr@723: self.wfile.write(utils.getHTML("stop_all", morphbr@723: {"menu": self._nav_items()})) morphbr@718: # serve_stop_all_transcoders() morphbr@718: morphbr@718: morphbr@718: def serve_stop_selected_transcoders(self, body, tids=[]): morphbr@718: self.send_response(200) morphbr@718: self.send_header("Content-Type", "text/html") morphbr@718: self.send_header('Connection', 'close') morphbr@718: self.end_headers() morphbr@718: opts = "" morphbr@718: if body: morphbr@718: transcoders = self.server.get_transcoders() morphbr@718: morphbr@718: for tid in tids: morphbr@718: for t, r in transcoders: morphbr@718: if t.tid == int(tid): morphbr@718: try: morphbr@718: t.stop() morphbr@718: except Exception, e: morphbr@718: self.log.info("Plugin already stopped") morphbr@718: morphbr@718: opts += utils._create_html_item("%s" % t) morphbr@718: morphbr@718: break morphbr@718: morphbr@718: self.wfile.write(utils.getHTML("stop_selected", morphbr@718: {"menu": self._nav_items(), morphbr@718: "opts": opts})) morphbr@718: # serve_stop_selected_transcoders() morphbr@718: morphbr@718: morphbr@718: def serve_stop_transcoder(self, body): morphbr@718: req = self.query.get("request", None) morphbr@718: tid = self.query.get("tid", None) morphbr@718: if req and "all" in req: morphbr@718: self.serve_stop_all_transcoders(body) morphbr@718: elif tid: morphbr@718: self.serve_stop_selected_transcoders(body, tid[0].split(";")) morphbr@718: else: morphbr@718: self.serve_status(body) morphbr@718: # serve_stop_transcoder() morphbr@718: morphbr@718: morphbr@718: def serve_status(self, body): morphbr@718: self.send_response(200) morphbr@718: self.send_header("Content-Type", "text/html") morphbr@718: self.send_header('Connection', 'close') morphbr@718: self.end_headers() morphbr@718: stopone = "" morphbr@732: running = "" morphbr@732: stopall = "" morphbr@718: morphbr@718: if body: morphbr@718: tl = self.server.get_transcoders() morphbr@741: if not tl and not self.query.get("tid", None) and \ morphbr@741: not self.query.get("running", None): morphbr@718: running = "

No running transcoder.

\n" morphbr@718: morphbr@741: elif not tl and self.query.get("tid", None): morphbr@724: tids = self.query.get("tid") morphbr@724: for tid in tids: morphbr@724: stat = self.transcoders_log.get_status(int(tid)) morphbr@729: self.wfile.write("%s
" % stat) morphbr@743: return True morphbr@723: morphbr@741: elif self.query.get("running", None): morphbr@741: for transcoder, request in tl: morphbr@741: outf = transcoder.params_first("outfile") morphbr@741: tid = transcoder.tid morphbr@741: self.wfile.write("%s:%s
" % (tid, outf)) morphbr@741: return True morphbr@741: morphbr@718: elif self.query.get("tid", None): morphbr@724: req_tid = self.query.get("tid") morphbr@718: for transcoder, request in tl: morphbr@724: if str(transcoder.tid) in req_tid: morphbr@734: self.wfile.write("Status:%s:%s %%" % (\ morphbr@724: transcoder.tid, transcoder.status)) morphbr@724: return True morphbr@718: morphbr@718: else: morphbr@718: running = "

Running transcoders:

\n" morphbr@718: stopall = utils._create_html_item("" morphbr@718: "[STOP ALL]" % morphbr@718: self.menu["Stop"]) morphbr@718: morphbr@718: for transcoder, request in tl: morphbr@718: stopone += utils._create_html_item("%s;" morphbr@718: "" morphbr@718: " [STOP] ") % ( morphbr@718: transcoder, self.menu["Stop"], transcoder.tid) morphbr@718: morphbr@718: self.wfile.write(utils.getHTML("status", morphbr@718: {"menu": self._nav_items(), morphbr@718: "running": running, morphbr@718: "stopall": stopall, morphbr@718: "stopone": stopone})) morphbr@718: # serve_status() morphbr@718: morphbr@718: morphbr@718: def _get_transcoder(self): morphbr@718: # get transcoder option: mencoder is the default morphbr@718: request_transcoders = self.query.get("transcoder", ["mencoder"]) morphbr@718: morphbr@718: for t in request_transcoders: morphbr@718: transcoder = self.transcoders.get(t) morphbr@718: if transcoder: morphbr@718: return transcoder morphbr@718: morphbr@718: if not transcoder: morphbr@718: return self.transcoders[self.def_transcoder] morphbr@718: # _get_transcoder() morphbr@718: morphbr@718: morphbr@718: def _get_new_id(self, tid): morphbr@718: self.server.last_tid = utils.create_tid(tid) morphbr@718: self.tid_queue.append(self.server.last_tid) morphbr@718: return self.server.last_tid morphbr@718: # _get_new_id() morphbr@718: morphbr@718: morphbr@718: def serve_new_id(self, body): morphbr@718: self.send_response(200) morphbr@718: self.send_header("Content-Type", "text/html") morphbr@718: self.send_header('Connection', 'close') morphbr@718: self.end_headers() morphbr@718: morphbr@718: if body: morphbr@718: self.wfile.write("%s" % self._get_new_id(self.server.last_tid)) morphbr@718: # serve_new_id() morphbr@718: morphbr@718: def serve_get_log(self, body): morphbr@718: self.send_response(200) morphbr@718: self.send_header("Content-Type", "text/html") morphbr@718: self.send_header('Connection', 'close') morphbr@718: self.end_headers() morphbr@718: morphbr@718: if body: morphbr@718: if self.query.get("tid", None): morphbr@718: tid = int(self.query.get("tid")[0]) morphbr@718: stat = self.transcoders_log.get_status(tid) morphbr@723: self.wfile.write("Status: %s" % stat) morphbr@718: else: morphbr@718: stat = self.transcoders_log.get_status() morphbr@718: for rtid, status in stat.iteritems(): morphbr@718: self.wfile.write("%s: %s

" % (rtid, status)) morphbr@718: # serve_get_log() morphbr@718: morphbr@718: def serve_get_all_log(self, body): morphbr@718: self.send_response(200) morphbr@718: self.send_header("Content-Type", "text/html") morphbr@718: self.send_header('Connection', 'close') morphbr@718: self.end_headers() morphbr@718: morphbr@718: if body: morphbr@718: if self.query.get("tid", None): morphbr@718: tid = int(self.query.get("tid")[0]) morphbr@718: stat = self.transcoders_log.get_status(tid, True) morphbr@718: for status in stat: morphbr@718: self.wfile.write("%s

" % status) morphbr@718: else: morphbr@718: stat = self.transcoders_log.get_status(None, True) morphbr@718: for rtid, history in stat.iteritems(): morphbr@718: for status in history: morphbr@718: self.wfile.write("%s: %s
" % (rtid, status)) morphbr@718: self.wfile.write("

") morphbr@718: # serve_get_all_log() morphbr@718: morphbr@718: def serve_stream(self, body): morphbr@718: transcoder = self._get_transcoder() morphbr@718: try: morphbr@718: obj = transcoder(self.query) morphbr@718: except Exception, e: morphbr@718: self.send_error(500, str(e)) morphbr@718: return morphbr@718: morphbr@718: self.send_response(200) morphbr@718: self.send_header("Content-Type", obj.get_mimetype()) morphbr@743: self.send_header("Connection", "close") morphbr@718: self.end_headers() morphbr@718: morphbr@718: if body: morphbr@742: morphbr@744: test_tid = int(self.query.get("tid", "0")[0]) morphbr@744: if test_tid == 0 or test_tid not in self.tid_queue: morphbr@744: test_tid = self._get_new_id(self.server.last_tid) morphbr@744: morphbr@748: morphbr@724: if self.query.get("transcoder", None): morphbr@724: self.transcoders_log.insert(test_tid, "gms.%s" % obj.name) morphbr@724: obj.tid = test_tid morphbr@724: obj.log = self.transcoders_log morphbr@718: morphbr@724: self.server.add_transcoders(self, obj) morphbr@724: obj.start(self.wfile) morphbr@724: self.server.del_transcoders(self, obj) morphbr@726: files.TranscodedFile("", self.query) morphbr@724: morphbr@724: elif self.query.get("type", "")[0] == "file" and \ morphbr@724: self.query.get("uri", None): morphbr@745: morphbr@745: filename = self.query.get("uri", None)[0] morphbr@745: self.transcoders_log.insert(test_tid, "gms.%s" % filename) morphbr@745: morphbr@742: try: morphbr@744: media = open(filename) morphbr@744: data_in = " " morphbr@744: total_read = 0 morphbr@744: size = int(os.path.getsize(filename)) morphbr@744: morphbr@744: while data_in != "": morphbr@744: data_in = media.read(4096) morphbr@744: total_read += 4096 morphbr@744: self.wfile.write(data_in) morphbr@744: status = utils.progress_bar(total_read, size, 50) morphbr@744: msg_status = "Status:%s:%s%%" % (test_tid, status) morphbr@744: self.transcoders_log._update_status(test_tid, morphbr@744: msg_status) morphbr@744: morphbr@745: self.transcoders_log._update_status(test_tid, "OK: Done") morphbr@745: morphbr@743: except Exception, e: morphbr@742: self.log.error("Stream error: %s" %e) morphbr@745: self.transcoders_log._update_status(test_tid, morphbr@745: "Error: %s" % e) morphbr@718: # serve_stream() morphbr@718: morphbr@718: morphbr@718: def log_request(self, code='-', size='-'): morphbr@718: self.log.info('"%s" %s %s', self.requestline, str(code), str(size)) morphbr@718: # log_request() morphbr@718: morphbr@718: morphbr@718: def log_error(self, format, *args): morphbr@718: self.log.error("%s: %s" % (self.address_string(), format % args)) morphbr@718: # log_error() morphbr@718: morphbr@718: morphbr@718: def log_message(self, format, *args): morphbr@718: self.log.info("%s: %s" % (self.address_string(), format % args)) morphbr@718: # log_message() morphbr@724: morphbr@718: # RequestHandler