gmyth-stream/server/0.3/lib/request_handler.py
author melunko
Wed Aug 22 14:57:53 2007 +0100 (2007-08-22)
branchtrunk
changeset 821 411a01dfcd21
parent 803 b1d0964060b3
child 824 e711a64ba03d
permissions -rw-r--r--
[svn r827] GMyth 0.4 release
     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         filename = self.query.get("file", None)[0]
   359 
   360         if not filename:
   361             self.send_error(404, "File not found")
   362             return
   363 
   364         #Only stream files on .transcode dir
   365         filename = os.path.join (utils.config.get_transcoded_location(), os.path.basename(filename))
   366         self.log.error("Stream file: %s" % filename)
   367         if not os.path.exists (filename):
   368             self.send_error(404, "File not found")
   369             return
   370 
   371         size = int(os.path.getsize(filename))
   372         self.send_response(200)
   373         self.send_header("Content-Type", mimetypes.guess_type(filename)[0])
   374         self.send_header("Cache-Control","no-cache")
   375         self.send_header("Content-Length", size)
   376         #self.send_header("Connection", "close")
   377         self.end_headers()
   378 
   379         media = open(filename)
   380         data_in = " "
   381         total_read = 0
   382 
   383         test_tid = int(self.query.get("tid", "0")[0])
   384         if test_tid == 0 or test_tid not in self.tid_queue:
   385             test_tid = self._get_new_id(self.server.last_tid)
   386 
   387         self.transcoders_log.insert(test_tid, "gms.Stream: %s" % filename)
   388 
   389         try:
   390             file_data = ""
   391             while data_in != "":
   392                 data_in = media.read(4096)
   393                 file_data += data_in
   394 
   395                 #total_read += 4096
   396             self.wfile.write(file_data)
   397                 #status = utils.progress_bar(total_read, size, 50)
   398                 #msg_status = "Status:%s:%s%%" % (test_tid, status)
   399                 #self.transcoders_log._update_status(test_tid, msg_status)
   400 
   401             self.transcoders_log._update_status(test_tid, "OK: Done")
   402 
   403         except Exception, e:
   404             self.log.error("Stream error: %s" %e)
   405             self.transcoders_log._update_status(test_tid, "Error: %s" % e)
   406     # serve_stream()
   407 
   408     def serve_transcode(self, body):
   409         type = self.query.get("type", None)[0]
   410         if type.upper() == "FILE":
   411             self.send_error(404, "Transcode local files not allowed")
   412             return
   413 
   414         transcoder = self._get_transcoder()
   415         try:
   416             obj = transcoder(self.query)
   417         except Exception, e:
   418             self.send_error(500, str(e))
   419             return
   420 
   421         self.send_response(200)
   422         self.send_header("Content-Type", obj.get_mimetype())
   423         self.send_header("Cache-Control","no-cache")
   424 
   425         if (obj.name == "gmencoder"):
   426             self.send_header("Transfer-Encoding", "chunked")
   427 
   428         #self.send_header("Connection", "close")
   429         self.end_headers()
   430 
   431         if body:
   432             test_tid = int(self.query.get("tid", "0")[0])
   433             if test_tid == 0 or test_tid not in self.tid_queue:
   434                 test_tid = self._get_new_id(self.server.last_tid)
   435 
   436             if self.query.get("transcoder", None):
   437                 self.transcoders_log.insert(test_tid, "gms.%s" % obj.name)
   438                 obj.tid = test_tid
   439                 obj.log = self.transcoders_log
   440 
   441                 self.server.add_transcoders(self, obj)
   442                 if obj.start(self.wfile):
   443                     self.transcoders_log.info (test_tid, "OK")
   444                 else:
   445                     self.transcoders_log.info (test_tid, "Fail")
   446 
   447                 self.server.del_transcoders(self, obj)
   448                 files.TranscodedFile("", self.query)
   449 
   450     # serve_stream()
   451 
   452 
   453     def log_request(self, code='-', size='-'):
   454         self.log.info('"%s" %s %s', self.requestline, str(code), str(size))
   455     # log_request()
   456 
   457 
   458     def log_error(self, format, *args):
   459         self.log.error("%s: %s" % (self.address_string(), format % args))
   460     # log_error()
   461 
   462 
   463     def log_message(self, format, *args):
   464         self.log.info("%s: %s" % (self.address_string(), format % args))
   465     # log_message()
   466 
   467 # RequestHandler