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 renatofilho@800: import mimetypes 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, renatofilho@800: "/transcode.do": self.serve_transcode, morphbr@723: "/list.do": self.serve_list, morphbr@773: "/get_file_info.do": self.serve_file_info, 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 = [] renatofilho@815: files.list_media_files(utils.config.get_transcoded_location(), 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)) melunko@795: return True melunko@795: stat = self.transcoders_log.get_status(int(req_tid[0])) melunko@795: self.wfile.write("%s
" % stat) 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@773: morphbr@773: def serve_file_info(self, body): morphbr@773: if body: morphbr@773: morphbr@773: file_dat = self.query.get("file", None) morphbr@773: morphbr@773: if file_dat: morphbr@773: self.send_response(200) morphbr@773: self.send_header("Content-Type", "text/html") morphbr@773: self.send_header('Connection', 'close') morphbr@773: self.end_headers() morphbr@773: morphbr@773: try: morphbr@775: opts = files.TranscodedFile(file_dat[0], self.query).opts morphbr@773: for key in opts.keys(): morphbr@775: self.wfile.write("%s=%s
" % (key, opts.get(key, "None")[0])) morphbr@775: morphbr@774: except Exception, e: morphbr@773: self.send_error(500, str(e)) morphbr@773: return morphbr@773: # serve_file_info() morphbr@773: morphbr@718: def serve_stream(self, body): melunko@824: args = self.query.get("file", None) melunko@824: if not args: melunko@824: self.send_error(404, "File not found") melunko@824: return renatofilho@800: melunko@824: filename = args[0]; renatofilho@802: if not filename: renatofilho@802: self.send_error(404, "File not found") renatofilho@802: return renatofilho@802: renatofilho@802: #Only stream files on .transcode dir renatofilho@815: filename = os.path.join (utils.config.get_transcoded_location(), os.path.basename(filename)) renatofilho@803: self.log.error("Stream file: %s" % filename) renatofilho@800: if not os.path.exists (filename): renatofilho@800: self.send_error(404, "File not found") renatofilho@800: return renatofilho@800: renatofilho@800: size = int(os.path.getsize(filename)) renatofilho@800: self.send_response(200) renatofilho@800: self.send_header("Content-Type", mimetypes.guess_type(filename)[0]) renatofilho@800: self.send_header("Cache-Control","no-cache") renatofilho@800: self.send_header("Content-Length", size) renatofilho@800: #self.send_header("Connection", "close") renatofilho@800: self.end_headers() renatofilho@800: renatofilho@800: media = open(filename) renatofilho@800: data_in = " " renatofilho@800: total_read = 0 renatofilho@800: renatofilho@800: test_tid = int(self.query.get("tid", "0")[0]) renatofilho@800: if test_tid == 0 or test_tid not in self.tid_queue: renatofilho@800: test_tid = self._get_new_id(self.server.last_tid) renatofilho@800: renatofilho@800: self.transcoders_log.insert(test_tid, "gms.Stream: %s" % filename) renatofilho@800: renatofilho@800: try: renatofilho@803: file_data = "" renatofilho@800: while data_in != "": renatofilho@800: data_in = media.read(4096) renatofilho@803: file_data += data_in renatofilho@803: renatofilho@803: #total_read += 4096 renatofilho@803: self.wfile.write(file_data) renatofilho@803: #status = utils.progress_bar(total_read, size, 50) renatofilho@803: #msg_status = "Status:%s:%s%%" % (test_tid, status) renatofilho@803: #self.transcoders_log._update_status(test_tid, msg_status) renatofilho@802: renatofilho@802: self.transcoders_log._update_status(test_tid, "OK: Done") renatofilho@800: renatofilho@800: except Exception, e: renatofilho@800: self.log.error("Stream error: %s" %e) renatofilho@800: self.transcoders_log._update_status(test_tid, "Error: %s" % e) renatofilho@800: # serve_stream() renatofilho@800: renatofilho@800: def serve_transcode(self, body): renatofilho@802: type = self.query.get("type", None)[0] renatofilho@802: if type.upper() == "FILE": renatofilho@802: self.send_error(404, "Transcode local files not allowed") renatofilho@802: return renatofilho@802: 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()) renatofilho@800: self.send_header("Cache-Control","no-cache") morphbr@765: morphbr@765: if (obj.name == "gmencoder"): morphbr@765: self.send_header("Transfer-Encoding", "chunked") morphbr@765: renatofilho@802: #self.send_header("Connection", "close") morphbr@718: self.end_headers() morphbr@718: morphbr@718: if body: 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@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) renatofilho@803: if obj.start(self.wfile): renatofilho@803: self.transcoders_log.info (test_tid, "OK") renatofilho@803: else: renatofilho@803: self.transcoders_log.info (test_tid, "Fail") renatofilho@803: morphbr@724: self.server.del_transcoders(self, obj) morphbr@726: files.TranscodedFile("", self.query) morphbr@724: 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