1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/gmyth-stream/server/lib/request_handler.py Thu Aug 30 12:51:31 2007 +0100
1.3 @@ -0,0 +1,470 @@
1.4 +#!/usr/bin/env python
1.5 +
1.6 +__author__ = "Gustavo Sverzut Barbieri / Artur Duque de Souza"
1.7 +__author_email__ = "barbieri@gmail.com / artur.souza@indt.org.br"
1.8 +__license__ = "GPL"
1.9 +__version__ = "0.3"
1.10 +
1.11 +import os
1.12 +import cgi
1.13 +import socket
1.14 +import logging
1.15 +import urlparse
1.16 +import threading
1.17 +import SocketServer
1.18 +import BaseHTTPServer
1.19 +import mimetypes
1.20 +
1.21 +import lib.utils as utils
1.22 +import lib.file_handler as files
1.23 +import lib.transcoder as transcoder
1.24 +
1.25 +from log import Log
1.26 +
1.27 +__all__ = ("RequestHandler")
1.28 +
1.29 +class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1.30 + """Class that implements an HTTP request handler for our server."""
1.31 + log = logging.getLogger("gms.request")
1.32 + def_transcoder = None
1.33 + transcoders = utils.PluginSet(transcoder.Transcoder)
1.34 + transcoders_log = Log()
1.35 + tid_queue = []
1.36 +
1.37 + menu = {
1.38 + "Log": "/get_log.do",
1.39 + "Stop": "/stop-transcoder.do",
1.40 + "Status": "/status.do",
1.41 + "All Log": "/get_all_log.do",
1.42 + "Version": "/version.do",
1.43 + "Shutdown": "/shutdown.do"
1.44 + }
1.45 +
1.46 + @classmethod
1.47 + def load_plugins_transcoders(cls, directory):
1.48 + cls.transcoders.load_from_directory(directory)
1.49 +
1.50 + if cls.def_transcoder is None and cls.transcoders:
1.51 + cls.def_transcoder = cls.transcoders[0].name
1.52 + # load_plugins_transcoders()
1.53 +
1.54 +
1.55 + def do_dispatch(self, body):
1.56 + self.url = self.path
1.57 + pieces = urlparse.urlparse(self.path)
1.58 + self.path = pieces[2]
1.59 + self.query = cgi.parse_qs(pieces[4])
1.60 +
1.61 + url = {
1.62 + "/": self.serve_main,
1.63 + "/shutdown.do": self.serve_shutdown,
1.64 + "/stop-transcoder.do": self.serve_stop_transcoder,
1.65 + "/status.do": self.serve_status,
1.66 + "/version.do": self.serve_version,
1.67 + "/new_id.do": self.serve_new_id,
1.68 + "/get_log.do": self.serve_get_log,
1.69 + "/get_all_log.do": self.serve_get_all_log,
1.70 + "/stream.do": self.serve_stream,
1.71 + "/transcode.do": self.serve_transcode,
1.72 + "/list.do": self.serve_list,
1.73 + "/get_file_info.do": self.serve_file_info,
1.74 + }
1.75 +
1.76 + try:
1.77 + url[self.path](body)
1.78 + except KeyError:
1.79 + try:
1.80 + action = self.query.get("action", None)
1.81 + if action and "stream.do" in action:
1.82 + self.serve_stream(body)
1.83 + elif os.path.exists("html/%s" % self.path):
1.84 + data = open("html/%s" % self.path)
1.85 + self.wfile.write(data.read())
1.86 + else:
1.87 + self.send_error(404, "File not found")
1.88 + except Exception, e:
1.89 + self.log.error(e)
1.90 +
1.91 + # do_dispatch()
1.92 +
1.93 +
1.94 + def do_GET(self):
1.95 + self.do_dispatch(True)
1.96 + # do_GET()
1.97 +
1.98 +
1.99 + def do_HEAD(self):
1.100 + self.do_dispatch(False)
1.101 + # do_HEAD()
1.102 +
1.103 +
1.104 + def _nav_items(self):
1.105 + ret = ""
1.106 + for name, url in self.menu.items():
1.107 + ret += utils.getHTML("menu", {"name": name, "url": url})
1.108 + return ret
1.109 + # _nav_items()
1.110 +
1.111 +
1.112 + def serve_main(self, body):
1.113 + self.send_response(200)
1.114 + self.send_header("Content-Type", "text/html")
1.115 + self.send_header('Connection', 'close')
1.116 + self.end_headers()
1.117 + if body:
1.118 + self.wfile.write(utils.getHTML("index", {"menu": self._nav_items()}))
1.119 + # serve_main()
1.120 +
1.121 +
1.122 + def serve_version(self, body):
1.123 + self.send_response(200)
1.124 + self.send_header("Content-Type", "text/html")
1.125 + self.send_header('Connection', 'close')
1.126 + self.end_headers()
1.127 + if body:
1.128 + self.wfile.write("Version: %s" % __version__)
1.129 + # serve_version
1.130 +
1.131 +
1.132 + def serve_shutdown(self, body):
1.133 + self.send_response(200)
1.134 + self.send_header("Content-Type", "text/html")
1.135 + self.send_header('Connection', 'close')
1.136 + self.end_headers()
1.137 + if body:
1.138 + self.wfile.write(utils.getHTML("shutdown"))
1.139 + self.server.server_close()
1.140 + # serve_shutdown()
1.141 +
1.142 +
1.143 + def serve_list(self, body):
1.144 + self.send_response(200)
1.145 + self.send_header("Content-Type", "text/html")
1.146 + self.send_header('Connection', 'close')
1.147 + self.end_headers()
1.148 +
1.149 + if body:
1.150 + file_list = []
1.151 + files.list_media_files(utils.config.get_transcoded_location(), file_list)
1.152 + output = files.FileList(map(lambda x, y: x+y, file_list,
1.153 + ["<br>"]*len(file_list)))
1.154 + self.wfile.write(output)
1.155 +
1.156 + # serve_list()
1.157 +
1.158 +
1.159 + def serve_stop_all_transcoders(self, body):
1.160 + self.send_response(200)
1.161 + self.send_header("Content-Type", "text/html")
1.162 + self.send_header('Connection', 'close')
1.163 + self.end_headers()
1.164 + if body:
1.165 + self.server.stop_transcoders()
1.166 + self.wfile.write(utils.getHTML("stop_all",
1.167 + {"menu": self._nav_items()}))
1.168 + # serve_stop_all_transcoders()
1.169 +
1.170 +
1.171 + def serve_stop_selected_transcoders(self, body, tids=[]):
1.172 + self.send_response(200)
1.173 + self.send_header("Content-Type", "text/html")
1.174 + self.send_header('Connection', 'close')
1.175 + self.end_headers()
1.176 + opts = ""
1.177 + if body:
1.178 + transcoders = self.server.get_transcoders()
1.179 +
1.180 + for tid in tids:
1.181 + for t, r in transcoders:
1.182 + if t.tid == int(tid):
1.183 + try:
1.184 + t.stop()
1.185 + except Exception, e:
1.186 + self.log.info("Plugin already stopped")
1.187 +
1.188 + opts += utils._create_html_item("%s" % t)
1.189 +
1.190 + break
1.191 +
1.192 + self.wfile.write(utils.getHTML("stop_selected",
1.193 + {"menu": self._nav_items(),
1.194 + "opts": opts}))
1.195 + # serve_stop_selected_transcoders()
1.196 +
1.197 +
1.198 + def serve_stop_transcoder(self, body):
1.199 + req = self.query.get("request", None)
1.200 + tid = self.query.get("tid", None)
1.201 + if req and "all" in req:
1.202 + self.serve_stop_all_transcoders(body)
1.203 + elif tid:
1.204 + self.serve_stop_selected_transcoders(body, tid[0].split(";"))
1.205 + else:
1.206 + self.serve_status(body)
1.207 + # serve_stop_transcoder()
1.208 +
1.209 +
1.210 + def serve_status(self, body):
1.211 + self.send_response(200)
1.212 + self.send_header("Content-Type", "text/html")
1.213 + self.send_header('Connection', 'close')
1.214 + self.end_headers()
1.215 + stopone = ""
1.216 + running = ""
1.217 + stopall = ""
1.218 +
1.219 + if body:
1.220 + tl = self.server.get_transcoders()
1.221 + if not tl and not self.query.get("tid", None) and \
1.222 + not self.query.get("running", None):
1.223 + running = "<p>No running transcoder.</p>\n"
1.224 +
1.225 + elif not tl and self.query.get("tid", None):
1.226 + tids = self.query.get("tid")
1.227 + for tid in tids:
1.228 + stat = self.transcoders_log.get_status(int(tid))
1.229 + self.wfile.write("%s<br>" % stat)
1.230 + return True
1.231 +
1.232 + elif self.query.get("running", None):
1.233 + for transcoder, request in tl:
1.234 + outf = transcoder.params_first("outfile")
1.235 + tid = transcoder.tid
1.236 + self.wfile.write("%s:%s<br>" % (tid, outf))
1.237 + return True
1.238 +
1.239 + elif self.query.get("tid", None):
1.240 + req_tid = self.query.get("tid")
1.241 + for transcoder, request in tl:
1.242 + if str(transcoder.tid) in req_tid:
1.243 + self.wfile.write("Status:%s:%s %%" % (\
1.244 + transcoder.tid, transcoder.status))
1.245 + return True
1.246 + stat = self.transcoders_log.get_status(int(req_tid[0]))
1.247 + self.wfile.write("%s<br>" % stat)
1.248 + return True
1.249 +
1.250 + else:
1.251 + running = "<p>Running transcoders:</p>\n"
1.252 + stopall = utils._create_html_item("<a href='%s?request=all'>"
1.253 + "[STOP ALL]</a>" %
1.254 + self.menu["Stop"])
1.255 +
1.256 + for transcoder, request in tl:
1.257 + stopone += utils._create_html_item("%s;"
1.258 + "<a href='%s?tid=%s'>"
1.259 + " [STOP] </a>") % (
1.260 + transcoder, self.menu["Stop"], transcoder.tid)
1.261 +
1.262 + self.wfile.write(utils.getHTML("status",
1.263 + {"menu": self._nav_items(),
1.264 + "running": running,
1.265 + "stopall": stopall,
1.266 + "stopone": stopone}))
1.267 + # serve_status()
1.268 +
1.269 +
1.270 + def _get_transcoder(self):
1.271 + # get transcoder option: mencoder is the default
1.272 + request_transcoders = self.query.get("transcoder", ["mencoder"])
1.273 +
1.274 + for t in request_transcoders:
1.275 + transcoder = self.transcoders.get(t)
1.276 + if transcoder:
1.277 + return transcoder
1.278 +
1.279 + if not transcoder:
1.280 + return self.transcoders[self.def_transcoder]
1.281 + # _get_transcoder()
1.282 +
1.283 +
1.284 + def _get_new_id(self, tid):
1.285 + self.server.last_tid = utils.create_tid(tid)
1.286 + self.tid_queue.append(self.server.last_tid)
1.287 + return self.server.last_tid
1.288 + # _get_new_id()
1.289 +
1.290 +
1.291 + def serve_new_id(self, body):
1.292 + self.send_response(200)
1.293 + self.send_header("Content-Type", "text/html")
1.294 + self.send_header('Connection', 'close')
1.295 + self.end_headers()
1.296 +
1.297 + if body:
1.298 + self.wfile.write("%s" % self._get_new_id(self.server.last_tid))
1.299 + # serve_new_id()
1.300 +
1.301 + def serve_get_log(self, body):
1.302 + self.send_response(200)
1.303 + self.send_header("Content-Type", "text/html")
1.304 + self.send_header('Connection', 'close')
1.305 + self.end_headers()
1.306 +
1.307 + if body:
1.308 + if self.query.get("tid", None):
1.309 + tid = int(self.query.get("tid")[0])
1.310 + stat = self.transcoders_log.get_status(tid)
1.311 + self.wfile.write("Status: %s" % stat)
1.312 + else:
1.313 + stat = self.transcoders_log.get_status()
1.314 + for rtid, status in stat.iteritems():
1.315 + self.wfile.write("<b>%s</b>: %s<br><br>" % (rtid, status))
1.316 + # serve_get_log()
1.317 +
1.318 + def serve_get_all_log(self, body):
1.319 + self.send_response(200)
1.320 + self.send_header("Content-Type", "text/html")
1.321 + self.send_header('Connection', 'close')
1.322 + self.end_headers()
1.323 +
1.324 + if body:
1.325 + if self.query.get("tid", None):
1.326 + tid = int(self.query.get("tid")[0])
1.327 + stat = self.transcoders_log.get_status(tid, True)
1.328 + for status in stat:
1.329 + self.wfile.write("%s<br><br>" % status)
1.330 + else:
1.331 + stat = self.transcoders_log.get_status(None, True)
1.332 + for rtid, history in stat.iteritems():
1.333 + for status in history:
1.334 + self.wfile.write("<b>%s</b>: %s<br>" % (rtid, status))
1.335 + self.wfile.write("<br><br>")
1.336 + # serve_get_all_log()
1.337 +
1.338 +
1.339 + def serve_file_info(self, body):
1.340 + if body:
1.341 +
1.342 + file_dat = self.query.get("file", None)
1.343 +
1.344 + if file_dat:
1.345 + self.send_response(200)
1.346 + self.send_header("Content-Type", "text/html")
1.347 + self.send_header('Connection', 'close')
1.348 + self.end_headers()
1.349 +
1.350 + try:
1.351 + opts = files.TranscodedFile(file_dat[0], self.query).opts
1.352 + for key in opts.keys():
1.353 + self.wfile.write("%s=%s<br>" % (key, opts.get(key, "None")[0]))
1.354 +
1.355 + except Exception, e:
1.356 + self.send_error(500, str(e))
1.357 + return
1.358 + # serve_file_info()
1.359 +
1.360 + def serve_stream(self, body):
1.361 + args = self.query.get("file", None)
1.362 + if not args:
1.363 + self.send_error(404, "File not found")
1.364 + return
1.365 +
1.366 + filename = args[0];
1.367 + if not filename:
1.368 + self.send_error(404, "File not found")
1.369 + return
1.370 +
1.371 + #Only stream files on .transcode dir
1.372 + filename = os.path.join (utils.config.get_transcoded_location(),
1.373 + os.path.basename(filename))
1.374 + self.log.error("Stream file: %s" % filename)
1.375 + if not os.path.exists (filename):
1.376 + self.send_error(404, "File not found")
1.377 + return
1.378 +
1.379 + size = int(os.path.getsize(filename))
1.380 + self.send_response(200)
1.381 + self.send_header("Content-Type", mimetypes.guess_type(filename)[0])
1.382 + self.send_header("Cache-Control","no-cache")
1.383 + self.send_header("Content-Length", size)
1.384 + self.end_headers()
1.385 +
1.386 + media = open(filename)
1.387 + data_in = " "
1.388 + total_read = 0
1.389 +
1.390 + test_tid = int(self.query.get("tid", "0")[0])
1.391 + if test_tid == 0 or test_tid not in self.tid_queue:
1.392 + test_tid = self._get_new_id(self.server.last_tid)
1.393 +
1.394 + self.transcoders_log.insert(test_tid, "gms.Stream: %s" % filename)
1.395 +
1.396 + try:
1.397 + file_data = ""
1.398 + while data_in != "":
1.399 + data_in = media.read(4096)
1.400 + file_data += data_in
1.401 +
1.402 + #total_read += 4096
1.403 + self.wfile.write(file_data)
1.404 + #status = utils.progress_bar(total_read, size, 50)
1.405 + #msg_status = "Status:%s:%s%%" % (test_tid, status)
1.406 + #self.transcoders_log._update_status(test_tid, msg_status)
1.407 +
1.408 + self.transcoders_log._update_status(test_tid, "OK: Done")
1.409 +
1.410 + except Exception, e:
1.411 + self.log.error("Stream error: %s" %e)
1.412 + self.transcoders_log._update_status(test_tid, "Error: %s" % e)
1.413 + # serve_stream()
1.414 +
1.415 + def serve_transcode(self, body):
1.416 + type = self.query.get("type", None)[0]
1.417 + if type.upper() == "FILE":
1.418 + self.send_error(404, "Transcode local files not allowed")
1.419 + return
1.420 +
1.421 + transcoder = self._get_transcoder()
1.422 + try:
1.423 + obj = transcoder(self.query)
1.424 + except Exception, e:
1.425 + self.send_error(500, str(e))
1.426 + return
1.427 +
1.428 + self.send_response(200)
1.429 + self.send_header("Content-Type", obj.get_mimetype())
1.430 + self.send_header("Cache-Control","no-cache")
1.431 +
1.432 + if (obj.name == "gmencoder"):
1.433 + self.send_header("Transfer-Encoding", "chunked")
1.434 +
1.435 + self.end_headers()
1.436 +
1.437 + if body:
1.438 + test_tid = int(self.query.get("tid", "0")[0])
1.439 + if test_tid == 0 or test_tid not in self.tid_queue:
1.440 + test_tid = self._get_new_id(self.server.last_tid)
1.441 +
1.442 + if self.query.get("transcoder", None):
1.443 + self.transcoders_log.insert(test_tid, "gms.%s" % obj.name)
1.444 + obj.tid = test_tid
1.445 + obj.log = self.transcoders_log
1.446 +
1.447 + self.server.add_transcoders(self, obj)
1.448 + if obj.start(self.wfile):
1.449 + self.transcoders_log.info (test_tid, "OK")
1.450 + else:
1.451 + self.transcoders_log.info (test_tid, "Fail")
1.452 +
1.453 + self.server.del_transcoders(self, obj)
1.454 + files.TranscodedFile("", self.query)
1.455 +
1.456 + # serve_stream()
1.457 +
1.458 +
1.459 + def log_request(self, code='-', size='-'):
1.460 + self.log.info('"%s" %s %s', self.requestline, str(code), str(size))
1.461 + # log_request()
1.462 +
1.463 +
1.464 + def log_error(self, format, *args):
1.465 + self.log.error("%s: %s" % (self.address_string(), format % args))
1.466 + # log_error()
1.467 +
1.468 +
1.469 + def log_message(self, format, *args):
1.470 + self.log.info("%s: %s" % (self.address_string(), format % args))
1.471 + # log_message()
1.472 +
1.473 +# RequestHandler