3 __author__ = "Gustavo Sverzut Barbieri / Artur Duque de Souza"
4 __author_email__ = "barbieri@gmail.com / artur.souza@indt.org.br"
15 import lib.utils as utils
18 __all__ = ("Transcoder", "RequestHandler", "Server", "serve_forever",
19 "load_plugins_transcoders")
21 class Transcoder(object):
22 log = log.getLogger("gms.transcoder")
23 priority = 0 # negative values have higher priorities
24 name = None # to be used in requests
28 def __init__(self, params):
33 def params_first(self, key, default=None):
35 return self.params[key][0]
38 return self.params[key][0]
44 def get_mimetype(self):
45 mux = self.params_first("mux", "mpg")
50 return "video/x-msvideo"
52 return "application/octet-stream"
56 def start(self, outfile):
67 return '%s( params=%s )' % \
68 (self.__class__.__name__,
75 class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
76 log = log.getLogger("gms.request")
78 transcoders = utils.PluginSet(Transcoder)
81 "Stop": "/stop-transcoder.do",
82 "Status": "/status.do",
83 "Version": "/version.do",
84 "Shutdown": "/shutdown.do"
88 def load_plugins_transcoders(cls, directory):
89 cls.transcoders.load_from_directory(directory)
91 if cls.def_transcoder is None and cls.transcoders:
92 cls.def_transcoder = cls.transcoders[0].name
93 # load_plugins_transcoders()
96 def do_dispatch(self, body):
99 pieces = urlparse.urlparse(self.path)
100 self.path = pieces[2]
101 self.query = cgi.parse_qs(pieces[4])
104 self.serve_main(body)
105 elif self.path == "/shutdown.do":
106 self.serve_shutdown(body)
107 elif self.path == "/stop-transcoder.do":
108 self.serve_stop_transcoder(body)
109 elif self.path == "/status.do":
110 self.serve_status(body)
111 elif self.path == "/version.do":
112 self.serve_version(body)
113 elif self.path == "/stream.do":
114 self.serve_stream(body)
116 action = self.query.get("action", None)
117 if "stream.do" in action:
118 self.serve_stream(body)
120 self.send_error(404, "File not found")
125 self.do_dispatch(True)
130 self.do_dispatch(False)
134 def _nav_items(self):
136 for name, url in self.menu.items():
137 ret += utils.getHTML("menu", {"name": name, "url": url})
142 def serve_main(self, body):
143 self.send_response(200)
144 self.send_header("Content-Type", "text/html")
145 self.send_header('Connection', 'close')
148 self.wfile.write(utils.getHTML("index", {"menu": self._nav_items()}))
151 def serve_version(self, body):
152 self.send_response(200)
153 self.send_header("Content-Type", "text/html")
154 self.send_header('Connection', 'close')
157 self.wfile.write("Version: %s" % __version__)
160 def serve_shutdown(self, body):
161 self.send_response(200)
162 self.send_header("Content-Type", "text/html")
163 self.send_header('Connection', 'close')
166 self.wfile.write(utils.getHTML("shutdown"))
167 self.server.server_close()
171 def serve_stop_all_transcoders(self, body):
172 self.send_response(200)
173 self.send_header("Content-Type", "text/html")
174 self.send_header('Connection', 'close')
177 self.server.stop_transcoders()
178 self.wfile.write(utils.getHTML("stop_all", {"menu": self._nav_items()}))
179 # serve_stop_all_transcoders()
182 def serve_stop_selected_transcoders(self, body, requests):
183 self.send_response(200)
184 self.send_header("Content-Type", "text/html")
185 self.send_header('Connection', 'close')
189 transcoders = self.server.get_transcoders()
193 host, port = req.split(":")
200 for t, r in transcoders:
201 if r.client_address == addr:
205 self.log.info("Plugin already stopped")
207 opts += self._create_html_item("%s: %s:%s" % (
208 t, addr[0], addr[1]))
212 self.wfile.write(utils.getHTML("stop_selected",
213 {"menu": self._nav_items(),
215 # serve_stop_selected_transcoders()
218 def serve_stop_transcoder(self, body):
219 req = self.query.get("request", None)
220 if req and "all" in req:
221 self.serve_stop_all_transcoders(body)
223 self.serve_stop_selected_transcoders(body, req)
225 self.serve_status(body)
226 # serve_stop_transcoder()
229 def serve_status(self, body):
230 self.send_response(200)
231 self.send_header("Content-Type", "text/html")
232 self.send_header('Connection', 'close')
237 tl = self.server.get_transcoders()
239 running = "<p>No running transcoder.</p>\n"
242 elif self.query.get("ip") and self.query.get("file"):
243 for transcoder, request in tl:
244 filename = "%s" % self.query.get("file")[0]
245 tfilename = "%s" % transcoder.params_first("uri")
247 if tfilename.find(filename) >= 0 and \
248 request.client_address[0] == self.query.get("ip")[0]:
249 self.wfile.write("Status: %s %%" % transcoder.status)
255 running = "<p>Running transcoders:</p>\n"
256 stopall = utils._create_html_item("<a href='%s?request=all'>"
260 for transcoder, request in tl:
261 stopone += utils._create_html_item("%s: %s:%s<a href='%s?"
266 transcoder, request.client_address[0],
267 request.client_address[1],
268 self.menu["Stop"], request.client_address[0],
269 request.client_address[1],
272 self.wfile.write(utils.getHTML("status",
273 {"menu": self._nav_items(),
276 "stopone": stopone}))
280 def _get_transcoder(self):
281 # get transcoder option: mencoder is the default
282 request_transcoders = self.query.get("transcoder", ["mencoder"])
284 for t in request_transcoders:
285 transcoder = self.transcoders.get(t)
290 return self.transcoders[self.def_transcoder]
294 def serve_stream(self, body):
295 transcoder = self._get_transcoder()
297 obj = transcoder(self.query)
299 self.send_error(500, str(e))
302 self.send_response(200)
303 self.send_header("Content-Type", obj.get_mimetype())
304 self.send_header('Connection', 'close')
308 self.server.add_transcoders(self, obj)
309 obj.start(self.wfile)
310 self.server.del_transcoders(self, obj)
314 def log_request(self, code='-', size='-'):
315 self.log.info('"%s" %s %s', self.requestline, str(code), str(size))
319 def log_error(self, format, *args):
320 self.log.error("%s: %s" % (self.address_string(), format % args))
324 def log_message(self, format, *args):
325 self.log.info("%s: %s" % (self.address_string(), format % args))
331 class Server(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
332 log = log.getLogger("gms.server")
335 _lock = threading.RLock()
337 def serve_forever(self):
338 self.log.info("GMyth-Streamer serving HTTP on %s:%s" %
339 self.socket.getsockname())
342 self.handle_request()
343 except KeyboardInterrupt, e:
346 self.log.debug("Stopping all remaining transcoders...")
347 self.stop_transcoders()
348 self.log.debug("Transcoders stopped!")
352 def get_request(self):
354 old = skt.gettimeout()
361 except socket.timeout, e:
363 raise socket.error("Not running")
367 def server_close(self):
369 self.stop_transcoders()
371 BaseHTTPServer.HTTPServer.server_close(self)
375 def stop_transcoders(self):
377 for transcoder, request in self._transcoders.iteritems():
378 self.log.info("Stop transcoder: %s, client=%s" %
379 (transcoder, request.client_address))
385 def get_transcoders(self):
388 return self._transcoders.items()
394 def add_transcoders(self, request, transcoder):
397 self._transcoders[transcoder] = request
403 def del_transcoders(self, request, transcoder):
406 del self._transcoders[transcoder]
414 def serve_forever(host="0.0.0.0", port=40000):
416 RequestHandler.protocol_version = "HTTP/1.0"
417 httpd = Server(addr, RequestHandler)
418 httpd.serve_forever()
422 def load_plugins_transcoders(directory):
423 RequestHandler.load_plugins_transcoders(directory)
424 # load_plugins_transcoders()