gmyth-stream/server/lib/request_handler.py
author renatofilho
Wed Nov 21 13:10:19 2007 +0000 (2007-11-21)
branchtrunk
changeset 883 e8a82fc5f075
parent 837 6b3c7c0b32ad
permissions -rw-r--r--
[svn r889] updated to use theora
     1 #!/usr/bin/env python
     2 
     3 __author__ = "Gustavo Sverzut Barbieri / Artur Duque de Souza"
     4 __author_email__ = "barbieri@gmail.com / artur.souza@indt.org.br"
     5 __license__ = "GPL"
     6 __version__ = "0.3"
     7 
     8 import os
     9 import cgi
    10 import socket
    11 import logging
    12 import urlparse
    13 import threading
    14 import SocketServer
    15 import BaseHTTPServer
    16 import mimetypes
    17 
    18 import lib.utils as utils
    19 import lib.file_handler as files
    20 import lib.transcoder as transcoder
    21 
    22 from log import Log
    23 
    24 __all__ = ("RequestHandler")
    25 
    26 class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    27     """Class that implements an HTTP request handler for our server."""
    28     log = logging.getLogger("gms.request")
    29     def_transcoder = None
    30     transcoders = utils.PluginSet(transcoder.Transcoder)
    31     transcoders_log = Log()
    32     tid_queue = []
    33 
    34     menu = {
    35         "Log": "/get_log.do",
    36         "Stop": "/stop-transcoder.do",
    37         "Status": "/status.do",
    38         "All Log": "/get_all_log.do",
    39         "Version": "/version.do",
    40         "Shutdown": "/shutdown.do"
    41         }
    42 
    43     @classmethod
    44     def load_plugins_transcoders(cls, directory):
    45         cls.transcoders.load_from_directory(directory)
    46 
    47         if cls.def_transcoder is None and cls.transcoders:
    48             cls.def_transcoder = cls.transcoders[0].name
    49     # load_plugins_transcoders()
    50 
    51 
    52     def do_dispatch(self, body):
    53         self.url = self.path
    54         pieces = urlparse.urlparse(self.path)
    55         self.path = pieces[2]
    56         self.query = cgi.parse_qs(pieces[4])
    57 
    58         url = {
    59             "/": self.serve_main,
    60             "/shutdown.do": self.serve_shutdown,
    61             "/stop-transcoder.do": self.serve_stop_transcoder,
    62             "/status.do": self.serve_status,
    63             "/version.do": self.serve_version,
    64             "/new_id.do": self.serve_new_id,
    65             "/get_log.do": self.serve_get_log,
    66             "/get_all_log.do": self.serve_get_all_log,
    67             "/stream.do": self.serve_stream,
    68             "/transcode.do": self.serve_transcode,
    69             "/list.do": self.serve_list,
    70             "/get_file_info.do": self.serve_file_info,
    71             }
    72 
    73         try:
    74             url[self.path](body)
    75         except KeyError:
    76             try:
    77                 action = self.query.get("action", None)
    78                 if action and "stream.do" in action:
    79                     self.serve_stream(body)
    80                 elif os.path.exists("html/%s" % self.path):
    81                     data = open("html/%s" % self.path)
    82                     self.wfile.write(data.read())
    83                 else:
    84                     self.send_error(404, "File not found")
    85             except Exception, e:
    86                 self.log.error(e)
    87 
    88     # do_dispatch()
    89 
    90 
    91     def do_GET(self):
    92         self.do_dispatch(True)
    93     # do_GET()
    94 
    95 
    96     def do_HEAD(self):
    97         self.do_dispatch(False)
    98     # do_HEAD()
    99 
   100 
   101     def _nav_items(self):
   102         ret = ""
   103         for name, url in self.menu.items():
   104             ret += utils.getHTML("menu", {"name": name, "url": url})
   105         return ret
   106     # _nav_items()
   107 
   108 
   109     def serve_main(self, body):
   110         self.send_response(200)
   111         self.send_header("Content-Type", "text/html")
   112         self.send_header('Connection', 'close')
   113         self.end_headers()
   114         if body:
   115             self.wfile.write(utils.getHTML("index", {"menu": self._nav_items()}))
   116     # serve_main()
   117 
   118 
   119     def serve_version(self, body):
   120         self.send_response(200)
   121         self.send_header("Content-Type", "text/html")
   122         self.send_header('Connection', 'close')
   123         self.end_headers()
   124         if body:
   125             self.wfile.write("Version: %s" %  __version__)
   126     # serve_version
   127 
   128 
   129     def serve_shutdown(self, body):
   130         self.send_response(200)
   131         self.send_header("Content-Type", "text/html")
   132         self.send_header('Connection', 'close')
   133         self.end_headers()
   134         if body:
   135             self.wfile.write(utils.getHTML("shutdown"))
   136         self.server.server_close()
   137     # serve_shutdown()
   138 
   139 
   140     def serve_list(self, body):
   141         self.send_response(200)
   142         self.send_header("Content-Type", "text/html")
   143         self.send_header('Connection', 'close')
   144         self.end_headers()
   145 
   146         if body:
   147             file_list = []
   148             files.list_media_files(utils.config.get_transcoded_location(), file_list)
   149             output = files.FileList(map(lambda x, y: x+y, file_list,
   150                                         ["<br>"]*len(file_list)))
   151             self.wfile.write(output)
   152 
   153     # serve_list()
   154 
   155 
   156     def serve_stop_all_transcoders(self, body):
   157         self.send_response(200)
   158         self.send_header("Content-Type", "text/html")
   159         self.send_header('Connection', 'close')
   160         self.end_headers()
   161         if body:
   162             self.server.stop_transcoders()
   163             self.wfile.write(utils.getHTML("stop_all",
   164                                            {"menu": self._nav_items()}))
   165     # serve_stop_all_transcoders()
   166 
   167 
   168     def serve_stop_selected_transcoders(self, body, tids=[]):
   169         self.send_response(200)
   170         self.send_header("Content-Type", "text/html")
   171         self.send_header('Connection', 'close')
   172         self.end_headers()
   173         opts = ""
   174         if body:
   175             transcoders = self.server.get_transcoders()
   176 
   177             for tid in tids:
   178                 for t, r in transcoders:
   179                     if t.tid == int(tid):
   180                         try:
   181                             t.stop()
   182                         except Exception, e:
   183                             self.log.info("Plugin already stopped")
   184 
   185                         opts += utils._create_html_item("%s" % t)
   186 
   187                         break
   188 
   189                 self.wfile.write(utils.getHTML("stop_selected",
   190                                                {"menu": self._nav_items(),
   191                                                 "opts": opts}))
   192     # serve_stop_selected_transcoders()
   193 
   194 
   195     def serve_stop_transcoder(self, body):
   196         req = self.query.get("request", None)
   197         tid = self.query.get("tid", None)
   198         if req and "all" in req:
   199             self.serve_stop_all_transcoders(body)
   200         elif tid:
   201             self.serve_stop_selected_transcoders(body, tid[0].split(";"))
   202         else:
   203             self.serve_status(body)
   204     # serve_stop_transcoder()
   205 
   206 
   207     def serve_status(self, body):
   208         self.send_response(200)
   209         self.send_header("Content-Type", "text/html")
   210         self.send_header('Connection', 'close')
   211         self.end_headers()
   212         stopone = ""
   213         running = ""
   214         stopall = ""
   215 
   216         if body:
   217             tl = self.server.get_transcoders()
   218             if not tl and not self.query.get("tid", None) and \
   219                    not self.query.get("running", None):
   220                 running = "<p>No running transcoder.</p>\n"
   221 
   222             elif not tl and self.query.get("tid", None):
   223                 tids = self.query.get("tid")
   224                 for tid in tids:
   225                     stat = self.transcoders_log.get_status(int(tid))
   226                     self.wfile.write("%s<br>" % stat)
   227                 return True
   228 
   229             elif self.query.get("running", None):
   230                 for transcoder, request in tl:
   231                     outf = transcoder.params_first("outfile")
   232                     tid = transcoder.tid
   233                     self.wfile.write("%s:%s<br>" % (tid, outf))
   234                 return True
   235 
   236             elif self.query.get("tid", None):
   237                 req_tid = self.query.get("tid")
   238                 for transcoder, request in tl:
   239                     if str(transcoder.tid) in req_tid:
   240                         self.wfile.write("Status:%s:%s %%" % (\
   241                             transcoder.tid, transcoder.status))
   242                         return True
   243                 stat = self.transcoders_log.get_status(int(req_tid[0]))
   244                 self.wfile.write("%s<br>" % stat)
   245                 return True
   246 
   247             else:
   248                 running = "<p>Running transcoders:</p>\n"
   249                 stopall = utils._create_html_item("<a href='%s?request=all'>"
   250                                                  "[STOP ALL]</a>" %
   251                                                  self.menu["Stop"])
   252 
   253                 for transcoder, request in tl:
   254                     stopone += utils._create_html_item("%s;"
   255                                                        "<a href='%s?tid=%s'>"
   256                                                        " [STOP] </a>") % (
   257                         transcoder, self.menu["Stop"], transcoder.tid)
   258 
   259             self.wfile.write(utils.getHTML("status",
   260                                            {"menu": self._nav_items(),
   261                                             "running": running,
   262                                             "stopall": stopall,
   263                                             "stopone": stopone}))
   264     # serve_status()
   265 
   266 
   267     def _get_transcoder(self):
   268         # get transcoder option: mencoder is the default
   269         request_transcoders = self.query.get("transcoder", ["mencoder"])
   270 
   271         for t in request_transcoders:
   272             transcoder = self.transcoders.get(t)
   273             if transcoder:
   274                 return transcoder
   275 
   276         if not transcoder:
   277             return self.transcoders[self.def_transcoder]
   278     # _get_transcoder()
   279 
   280 
   281     def _get_new_id(self, tid):
   282         self.server.last_tid = utils.create_tid(tid)
   283         self.tid_queue.append(self.server.last_tid)
   284         return self.server.last_tid
   285     # _get_new_id()
   286 
   287 
   288     def serve_new_id(self, body):
   289         self.send_response(200)
   290         self.send_header("Content-Type", "text/html")
   291         self.send_header('Connection', 'close')
   292         self.end_headers()
   293 
   294         if body:
   295             self.wfile.write("%s" % self._get_new_id(self.server.last_tid))
   296     # serve_new_id()
   297 
   298     def serve_get_log(self, body):
   299         self.send_response(200)
   300         self.send_header("Content-Type", "text/html")
   301         self.send_header('Connection', 'close')
   302         self.end_headers()
   303 
   304         if body:
   305             if self.query.get("tid", None):
   306                 tid = int(self.query.get("tid")[0])
   307                 stat = self.transcoders_log.get_status(tid)
   308                 self.wfile.write("Status: %s" % stat)
   309             else:
   310                 stat = self.transcoders_log.get_status()
   311                 for rtid, status in stat.iteritems():
   312                     self.wfile.write("<b>%s</b>: %s<br><br>" % (rtid, status))
   313     # serve_get_log()
   314 
   315     def serve_get_all_log(self, body):
   316         self.send_response(200)
   317         self.send_header("Content-Type", "text/html")
   318         self.send_header('Connection', 'close')
   319         self.end_headers()
   320 
   321         if body:
   322             if self.query.get("tid", None):
   323                 tid = int(self.query.get("tid")[0])
   324                 stat = self.transcoders_log.get_status(tid, True)
   325                 for status in stat:
   326                     self.wfile.write("%s<br><br>" % status)
   327             else:
   328                 stat = self.transcoders_log.get_status(None, True)
   329                 for rtid, history in stat.iteritems():
   330                     for status in history:
   331                         self.wfile.write("<b>%s</b>: %s<br>" % (rtid, status))
   332                     self.wfile.write("<br><br>")
   333     # serve_get_all_log()
   334 
   335 
   336     def serve_file_info(self, body):
   337         if body:
   338 
   339             file_dat = self.query.get("file", None)
   340 
   341             if file_dat:
   342                 self.send_response(200)
   343                 self.send_header("Content-Type", "text/html")
   344                 self.send_header('Connection', 'close')
   345                 self.end_headers()
   346 
   347                 try:
   348                     opts = files.TranscodedFile(file_dat[0], self.query).opts
   349                     for key in opts.keys():
   350                         self.wfile.write("%s=%s<br>" % (key, opts.get(key, "None")[0]))
   351 
   352                 except Exception, e:
   353                     self.send_error(500, str(e))
   354                     return
   355     # serve_file_info()
   356 
   357     def serve_stream(self, body):
   358 	args = self.query.get("file", None)
   359 	if not args:
   360 	    self.send_error(404, "File not found")
   361 	    return
   362 
   363         filename = args[0];
   364         if not filename:
   365             self.send_error(404, "File not found")
   366             return
   367 
   368         #Only stream files on .transcode dir
   369         filename = os.path.join (utils.config.get_transcoded_location(),
   370                                  os.path.basename(filename))
   371         self.log.error("Stream file: %s" % filename)
   372         if not os.path.exists (filename):
   373             self.send_error(404, "File not found")
   374             return
   375 
   376         size = int(os.path.getsize(filename))
   377         self.send_response(200)
   378         self.send_header("Content-Type", mimetypes.guess_type(filename)[0])
   379         self.send_header("Cache-Control","no-cache")
   380         self.send_header("Content-Length", size)
   381         self.end_headers()
   382 
   383         media = open(filename)
   384         data_in = " "
   385         total_read = 0
   386 
   387         test_tid = int(self.query.get("tid", "0")[0])
   388         if test_tid == 0 or test_tid not in self.tid_queue:
   389             test_tid = self._get_new_id(self.server.last_tid)
   390 
   391         self.transcoders_log.insert(test_tid, "gms.Stream: %s" % filename)
   392 
   393         try:
   394             file_data = ""
   395             while data_in != "":
   396                 data_in = media.read(4096)
   397                 file_data += data_in
   398 
   399                 #total_read += 4096
   400             self.wfile.write(file_data)
   401                 #status = utils.progress_bar(total_read, size, 50)
   402                 #msg_status = "Status:%s:%s%%" % (test_tid, status)
   403                 #self.transcoders_log._update_status(test_tid, msg_status)
   404 
   405             self.transcoders_log._update_status(test_tid, "OK: Done")
   406 
   407         except Exception, e:
   408             self.log.error("Stream error: %s" %e)
   409             self.transcoders_log._update_status(test_tid, "Error: %s" % e)
   410     # serve_stream()
   411 
   412     def serve_transcode(self, body):
   413         type = self.query.get("type", None)[0]
   414         #if type.upper() == "FILE":
   415         #    self.send_error(404, "Transcode local files not allowed")
   416         #   #return
   417 
   418         transcoder = self._get_transcoder()
   419         try:
   420             obj = transcoder(self.query)
   421         except Exception, e:
   422             self.send_error(500, str(e))
   423             return
   424 
   425         self.send_response(200)
   426         self.send_header("Content-Type", obj.get_mimetype())
   427         self.send_header("Cache-Control","no-cache")
   428         self.end_headers()
   429 
   430         if body:
   431             test_tid = int(self.query.get("tid", "0")[0])
   432             if test_tid == 0 or test_tid not in self.tid_queue:
   433                 test_tid = self._get_new_id(self.server.last_tid)
   434 
   435             if self.query.get("transcoder", None):
   436                 self.transcoders_log.insert(test_tid, "gms.%s" % obj.name)
   437                 obj.tid = test_tid
   438                 obj.log = self.transcoders_log
   439 
   440                 self.server.add_transcoders(self, obj)
   441                 if obj.start(self.wfile):
   442                     self.transcoders_log.info(test_tid, "OK")
   443                 else:
   444                     self.transcoders_log.info(test_tid, "Fail")
   445 
   446                 self.server.del_transcoders(self, obj)
   447                 files.TranscodedFile("", self.query)
   448 
   449     # serve_stream()
   450 
   451 
   452     def log_request(self, code='-', size='-'):
   453         self.log.info('"%s" %s %s', self.requestline, str(code), str(size))
   454     # log_request()
   455 
   456 
   457     def log_error(self, format, *args):
   458         self.log.error("%s: %s" % (self.address_string(), format % args))
   459     # log_error()
   460 
   461 
   462     def log_message(self, format, *args):
   463         self.log.info("%s: %s" % (self.address_string(), format % args))
   464     # log_message()
   465 
   466 # RequestHandler