summaryrefslogtreecommitdiffstats
path: root/module/web
diff options
context:
space:
mode:
Diffstat (limited to 'module/web')
-rw-r--r--module/web/ServerThread.py115
-rw-r--r--module/web/servers.py162
-rw-r--r--module/web/static/js/views/packageView.js6
-rw-r--r--module/web/static/js/views/settingsView.js2
-rw-r--r--module/web/utils.py28
-rw-r--r--module/web/webinterface.py19
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)