diff options
Diffstat (limited to 'module/web')
-rw-r--r-- | module/web/ServerThread.py | 115 | ||||
-rw-r--r-- | module/web/servers.py | 162 | ||||
-rw-r--r-- | module/web/static/js/views/packageView.js | 6 | ||||
-rw-r--r-- | module/web/static/js/views/settingsView.js | 2 | ||||
-rw-r--r-- | module/web/utils.py | 28 | ||||
-rw-r--r-- | module/web/webinterface.py | 19 |
6 files changed, 231 insertions, 101 deletions
diff --git a/module/web/ServerThread.py b/module/web/ServerThread.py index dc30f4bc5..99137b591 100644 --- a/module/web/ServerThread.py +++ b/module/web/ServerThread.py @@ -31,13 +31,14 @@ class WebServer(threading.Thread): self.key = config["ssl"]["key"] self.host = config['webinterface']['host'] self.port = config['webinterface']['port'] + self.debug = config['general']['debug_mode'] + self.force_server = config['webinterface']['force_server'] self.error = None self.setDaemon(True) def run(self): self.running = True - import webinterface global webinterface @@ -46,76 +47,86 @@ class WebServer(threading.Thread): log.warning(_("SSL certificates not found.")) self.https = False - if self.server == "fastcgi": - try: - import flup - except: - log.warning(_("Can't use %(server)s, python-flup is not installed!") % { - "server": self.server}) - self.server = "builtin" - elif self.server == "lightweight": - try: - import bjoern - except Exception, e: - log.error(_("Error importing lightweight server: %s") % e) - log.warning(_("You need to download and compile bjoern, https://github.com/jonashaag/bjoern")) - log.warning(_("Copy the boern.so to module/lib folder or use setup.py install")) - log.warning(_("Of course you need to be familiar with linux and know how to compile software")) - self.server = "builtin" + prefer = None + + # These cases covers all settings + if self.server == "threaded": + prefer = "threaded" + elif self.server == "fastcgi": + prefer = "flup" + elif self.server == "fallback": + prefer = "wsgiref" + server = self.select_server(prefer) try: - if self.server == "fastcgi": - self.start_fcgi() - elif self.server in ("threaded", "builtin"): - self.start_threaded() - elif self.server == "lightweight": - self.start_lightweight() - else: - self.start_fallback() + self.start_server(server) + except Exception, e: log.error(_("Failed starting webserver: " + e.message)) self.error = e if core: core.print_exc() - def start_fallback(self): - if self.https: - log.warning(_("This server offers no SSL, please consider using threaded instead")) + def select_server(self, prefer=None): + """ find a working server """ + from servers import all_server - log.info(_("Starting fallback webserver: %(host)s:%(port)d") % {"host": self.host, "port": self.port}) - webinterface.run_server(host=self.host, port=self.port) + unavailable = [] + server = None + for server in all_server: - def start_threaded(self): - if self.https: - log.info(_("Starting threaded SSL webserver: %(host)s:%(port)d") % {"host": self.host, "port": self.port}) - else: - self.cert = "" - self.key = "" - log.info(_("Starting threaded webserver: %(host)s:%(port)d") % {"host": self.host, "port": self.port}) + if self.force_server and self.force_server == server.NAME: + break # Found server + # When force_server is set, no further checks have to be made + elif self.force_server: + continue - webinterface.run_threaded(host=self.host, port=self.port, cert=self.cert, key=self.key) + if prefer and prefer == server.NAME: + break # found prefered server + elif prefer: # prefer is similar to force, but force has precedence + continue - def start_fcgi(self): - from flup.server.threadedserver import ThreadedServer + # Filter for server that offer ssl if needed + if self.https and not server.SSL: + continue - def noop(*args, **kwargs): - pass + try: + if server.find(): + break # Found a server + else: + unavailable.append(server.NAME) + except Exception, e: + log.error(_("Failed importing webserver: " + e.message)) - # Monkey patch signal handler, it does not work from threads - ThreadedServer._installSignalHandlers = noop + if unavailable: # Just log whats not available to have some debug information + log.debug("Unavailable webserver: " + ",".join(unavailable)) - log.info(_("Starting fastcgi server: %(host)s:%(port)d") % {"host": self.host, "port": self.port}) - webinterface.run_server(host=self.host, port=self.port, server="flup") + if not server and self.force_server: + server = self.force_server # just return the name + return server - def start_lightweight(self): - if self.https: - log.warning(_("This server offers no SSL, please consider using threaded instead")) - log.info( - _("Starting lightweight webserver (bjoern): %(host)s:%(port)d") % {"host": self.host, "port": self.port}) - webinterface.run_server(host=self.host, port=self.port, server="bjoern") + def start_server(self, server): + + from servers import ServerAdapter + + if issubclass(server, ServerAdapter): + + if self.https and not server.SSL: + log.warning(_("This server offers no SSL, please consider using threaded instead")) + + # Now instantiate the serverAdapter + server = server(self.host, self.port, self.key, self.cert, 6, self.debug) # todo, num_connections + name = server.NAME + + else: # server is just a string + name = server + + log.info(_("Starting %(name)s webserver: %(host)s:%(port)d") % {"name": name, "host": self.host, "port": self.port}) + webinterface.run_server(host=self.host, port=self.port, server=server) + # check if an error was raised for n seconds diff --git a/module/web/servers.py b/module/web/servers.py new file mode 100644 index 000000000..a3c51e36b --- /dev/null +++ b/module/web/servers.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from bottle import ServerAdapter as BaseAdapter + +class ServerAdapter(BaseAdapter): + SSL = False + NAME = "" + + def __init__(self, host, port, key, cert, connections, debug, **kwargs): + BaseAdapter.__init__(self, host, port, **kwargs) + self.key = key + self.cert = cert + self.connection = connections + self.debug = debug + + @classmethod + def find(cls): + """ Check if server is available by trying to import it + + :raises Exception: importing C dependant library could also fail with other reasons + :return: True on success + """ + try: + __import__(cls.NAME) + return True + except ImportError: + return False + + def run(self, handler): + raise NotImplementedError + + +class CherryPyWSGI(ServerAdapter): + SSL = True + NAME = "threaded" + + @classmethod + def find(cls): + return True + + def run(self, handler): + from wsgiserver import CherryPyWSGIServer + + if self.cert and self.key: + CherryPyWSGIServer.ssl_certificate = self.cert + CherryPyWSGIServer.ssl_private_key = self.key + + server = CherryPyWSGIServer((self.host, self.port), handler, numthreads=self.connection) + server.start() + + +class FapwsServer(ServerAdapter): + """ Does not work very good currently """ + + NAME = "fapws" + + def run(self, handler): # pragma: no cover + import fapws._evwsgi as evwsgi + from fapws import base, config + + port = self.port + if float(config.SERVER_IDENT[-2:]) > 0.4: + # fapws3 silently changed its API in 0.5 + port = str(port) + evwsgi.start(self.host, port) + evwsgi.set_base_module(base) + + def app(environ, start_response): + environ['wsgi.multiprocess'] = False + return handler(environ, start_response) + + evwsgi.wsgi_cb(('', app)) + evwsgi.run() + + +# TODO: ssl +class MeinheldServer(ServerAdapter): + SSL = True + NAME = "meinheld" + + def run(self, handler): + from meinheld import server + + if self.quiet: + server.set_access_logger(None) + server.set_error_logger(None) + + server.listen((self.host, self.port)) + server.run(handler) + +# todo:ssl +class TornadoServer(ServerAdapter): + """ The super hyped asynchronous server by facebook. Untested. """ + + SSL = True + NAME = "tornado" + + def run(self, handler): # pragma: no cover + import tornado.wsgi, tornado.httpserver, tornado.ioloop + + container = tornado.wsgi.WSGIContainer(handler) + server = tornado.httpserver.HTTPServer(container) + server.listen(port=self.port) + tornado.ioloop.IOLoop.instance().start() + + +class BjoernServer(ServerAdapter): + """ Fast server written in C: https://github.com/jonashaag/bjoern """ + + NAME = "bjoern" + + def run(self, handler): + from bjoern import run + + run(handler, self.host, self.port) + + +# todo: ssl +class EventletServer(ServerAdapter): + + SSL = True + NAME = "eventlet" + + def run(self, handler): + from eventlet import wsgi, listen + + try: + wsgi.server(listen((self.host, self.port)), handler, + log_output=(not self.quiet)) + except TypeError: + # Needed to ignore the log + class NoopLog: + def write(self, *args): + pass + + # Fallback, if we have old version of eventlet + wsgi.server(listen((self.host, self.port)), handler, log=NoopLog()) + + +class FlupFCGIServer(ServerAdapter): + + SSL = False + NAME = "flup" + + def run(self, handler): # pragma: no cover + import flup.server.fcgi + from flup.server.threadedserver import ThreadedServer + + def noop(*args, **kwargs): + pass + + # Monkey patch signal handler, it does not work from threads + ThreadedServer._installSignalHandlers = noop + + self.options.setdefault('bindAddress', (self.host, self.port)) + flup.server.fcgi.WSGIServer(handler, **self.options).run() + +# Order is important and gives every server precedence over others! +all_server = [BjoernServer, TornadoServer, EventletServer, CherryPyWSGI] +# Some are deactivated because they have some flaws +##all_server = [FapwsServer, MeinheldServer, BjoernServer, TornadoServer, EventletServer, CherryPyWSGI]
\ No newline at end of file diff --git a/module/web/static/js/views/packageView.js b/module/web/static/js/views/packageView.js index 365f3a69f..5d8aa7738 100644 --- a/module/web/static/js/views/packageView.js +++ b/module/web/static/js/views/packageView.js @@ -53,13 +53,12 @@ define(['jquery', 'views/abstract/itemView', 'underscore', 'views/fileView'], ul.append(new fileView({model: file}).render().el); }); - this.$el.append(ul); - // TODO: additionally it could be placed out of viewport first // The real height can only be retrieved when element is on DOM and display:true ul.css('visibility', 'hidden'); + this.$el.append(ul); + var height = ul.height(); - ul.css('visibility', ''); // Hide the element when not expanded if (!this.expanded) { @@ -67,6 +66,7 @@ define(['jquery', 'views/abstract/itemView', 'underscore', 'views/fileView'], ul.height(0); } + ul.css('visibility', ''); ul.data('height', height); console.log(ul.data("height")); diff --git a/module/web/static/js/views/settingsView.js b/module/web/static/js/views/settingsView.js index aba16eb66..a322cdae7 100644 --- a/module/web/static/js/views/settingsView.js +++ b/module/web/static/js/views/settingsView.js @@ -1,7 +1,7 @@ define(['jquery', 'underscore', 'backbone'], function($, _, Backbone) { - // Renders a single package item + // Renders settings over view page return Backbone.View.extend({ el: "#content", diff --git a/module/web/utils.py b/module/web/utils.py index 0b8c8f9df..cbe8f3071 100644 --- a/module/web/utils.py +++ b/module/web/utils.py @@ -1,23 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -""" - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see <http://www.gnu.org/licenses/>. - - @author: RaNaN -""" import re -from bottle import request, HTTPError, redirect, ServerAdapter +from bottle import request, HTTPError, redirect from webinterface import env, TEMPLATE, PYLOAD, SETUP @@ -101,14 +86,3 @@ def login_required(perm=None): return _view return _dec - - -class CherryPyWSGI(ServerAdapter): - - numthreads = 6 - - def run(self, handler): - from wsgiserver import CherryPyWSGIServer - - server = CherryPyWSGIServer((self.host, self.port), handler, numthreads=self.numthreads) - server.start() diff --git a/module/web/webinterface.py b/module/web/webinterface.py index 0fdf3c2ab..cec0f24a4 100644 --- a/module/web/webinterface.py +++ b/module/web/webinterface.py @@ -124,26 +124,9 @@ import setup_app import cnl_app
import api_app
-
# Server Adapter
-
-def run_server(host="0.0.0.0", port="8000", server="wsgiref"):
+def run_server(host, port, server):
run(app=web, host=host, port=port, quiet=True, server=server)
-
-def run_threaded(host="0.0.0.0", port="8000", threads=6, cert="", key=""):
- from wsgiserver import CherryPyWSGIServer
-
- if cert and key:
- CherryPyWSGIServer.ssl_certificate = cert
- CherryPyWSGIServer.ssl_private_key = key
-
- # todo: threads configurable
- from utils import CherryPyWSGI
- CherryPyWSGI.numthreads = threads
-
- run(app=web, host=host, port=port, server=CherryPyWSGI, quiet=True)
-
-
if __name__ == "__main__":
run(app=web, port=8001)
|