gmyth-stream/server/0.3/lib/request_handler.py
author melunko
Mon Aug 13 22:54:55 2007 +0100 (2007-08-13)
branchtrunk
changeset 801 e51af4d0caf5
parent 795 2b4e9d183146
child 802 d0e8c542c38e
permissions -rw-r--r--
[svn r807] Added gmyth_scheduler_add_schedule_full() method
     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(".transcoded", 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         filename = self.query.get("uri", None)[0]
   359 
   360         if not os.path.exists (filename):
   361             self.send_error(404, "File not found")
   362             return
   363 
   364         size = int(os.path.getsize(filename))
   365         self.send_response(200)
   366         self.send_header("Content-Type", mimetypes.guess_type(filename)[0])
   367         self.send_header("Cache-Control","no-cache")
   368         self.send_header("Content-Length", size)
   369         #self.send_header("Connection", "close")
   370         self.end_headers()
   371 
   372         media = open(filename)
   373         data_in = " "
   374         total_read = 0
   375 
   376         test_tid = int(self.query.get("tid", "0")[0])
   377         if test_tid == 0 or test_tid not in self.tid_queue:
   378             test_tid = self._get_new_id(self.server.last_tid)
   379 
   380         self.transcoders_log.insert(test_tid, "gms.Stream: %s" % filename)
   381 
   382         try:
   383             while data_in != "":
   384                 data_in = media.read(4096)
   385                 total_read += 4096
   386                 self.wfile.write(data_in)
   387                 status = utils.progress_bar(total_read, size, 50)
   388                 msg_status = "Status:%s:%s%%" % (test_tid, status)
   389                 self.transcoders_log._update_status(test_tid, msg_status)
   390                 self.transcoders_log._update_status(test_tid, "OK: Done")
   391 
   392         except Exception, e:
   393             self.log.error("Stream error: %s" %e)
   394             self.transcoders_log._update_status(test_tid, "Error: %s" % e)
   395     # serve_stream()
   396 
   397     def serve_transcode(self, body):
   398         transcoder = self._get_transcoder()
   399         try:
   400             obj = transcoder(self.query)
   401         except Exception, e:
   402             self.send_error(500, str(e))
   403             return
   404 
   405         self.send_response(200)
   406         self.send_header("Content-Type", obj.get_mimetype())
   407         self.send_header("Cache-Control","no-cache")
   408 
   409         if (obj.name == "gmencoder"):
   410             self.send_header("Transfer-Encoding", "chunked")
   411 
   412         self.send_header("Connection", "close")
   413         self.end_headers()
   414 
   415         if body:
   416             test_tid = int(self.query.get("tid", "0")[0])
   417             if test_tid == 0 or test_tid not in self.tid_queue:
   418                 test_tid = self._get_new_id(self.server.last_tid)
   419 
   420             if self.query.get("transcoder", None):
   421                 self.transcoders_log.insert(test_tid, "gms.%s" % obj.name)
   422                 obj.tid = test_tid
   423                 obj.log = self.transcoders_log
   424 
   425                 self.server.add_transcoders(self, obj)
   426                 obj.start(self.wfile)
   427                 self.server.del_transcoders(self, obj)
   428                 files.TranscodedFile("", self.query)
   429 
   430     # serve_stream()
   431 
   432 
   433     def log_request(self, code='-', size='-'):
   434         self.log.info('"%s" %s %s', self.requestline, str(code), str(size))
   435     # log_request()
   436 
   437 
   438     def log_error(self, format, *args):
   439         self.log.error("%s: %s" % (self.address_string(), format % args))
   440     # log_error()
   441 
   442 
   443     def log_message(self, format, *args):
   444         self.log.info("%s: %s" % (self.address_string(), format % args))
   445     # log_message()
   446 
   447 # RequestHandler