Initial commit
commit
a3c69c2771
|
@ -0,0 +1,5 @@
|
|||
/dist/
|
||||
*.egg-info/
|
||||
__pycache__/
|
||||
*.py[co]
|
||||
*.ini
|
|
@ -0,0 +1,43 @@
|
|||
from __future__ import unicode_literals
|
||||
import gunicorn.app.base
|
||||
import os
|
||||
import webob.static
|
||||
import logging
|
||||
|
||||
|
||||
config = os.path.join(os.path.dirname(__file__), 'development.ini')
|
||||
|
||||
|
||||
class DebugApplication(object):
|
||||
|
||||
def __init__(self, app, staticpath='.'):
|
||||
self.app = app
|
||||
self.static = webob.static.DirectoryApp(os.path.realpath(staticpath))
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
if os.path.exists(environ['PATH_INFO'].lstrip('/')):
|
||||
return self.static(environ, start_response)
|
||||
else:
|
||||
return self.app(environ, start_response)
|
||||
|
||||
|
||||
class Server(gunicorn.app.base.BaseApplication):
|
||||
|
||||
def load_config(self):
|
||||
self.cfg.set('bind', '[::]:8080')
|
||||
self.cfg.set('reload', True)
|
||||
self.cfg.set('workers', 1)
|
||||
self.cfg.set('threads', 1)
|
||||
self.cfg.set('accesslog', '-')
|
||||
self.cfg.set('timeout', 9001)
|
||||
|
||||
def load(self):
|
||||
import rouse.web
|
||||
app = rouse.web.Application.create(config)
|
||||
return DebugApplication(app)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logging.getLogger('sqlalchemy.engine.base.Engine').propagate = False
|
||||
Server().run()
|
|
@ -0,0 +1,16 @@
|
|||
from setuptools import find_packages, setup
|
||||
|
||||
setup(
|
||||
name='Rouse',
|
||||
version='0.1',
|
||||
description='Wake-on-LAN sender with convenient browser user interface',
|
||||
author='Dustin C. Hatch',
|
||||
author_email='dustin@hatch.name',
|
||||
url='',
|
||||
license='GPL-3',
|
||||
packages=find_packages('src'),
|
||||
package_dir={'': 'src'},
|
||||
install_requires=[
|
||||
'Milla>=0.3',
|
||||
],
|
||||
)
|
|
@ -0,0 +1,92 @@
|
|||
from __future__ import unicode_literals
|
||||
from milla.dispatch import routing
|
||||
import functools
|
||||
import jinja2
|
||||
import json
|
||||
import milla.util
|
||||
import os
|
||||
|
||||
|
||||
class SmartJSONEncoder(json.JSONEncoder):
|
||||
|
||||
def default(self, obj): # pylint: disable=method-hidden
|
||||
if hasattr(obj, 'to_json'):
|
||||
return obj.to_json()
|
||||
super(SmartJSONEncoder, self).default(obj)
|
||||
|
||||
|
||||
class VariedResponse(milla.Response):
|
||||
|
||||
TMPL_LOADER = jinja2.PackageLoader(__name__)
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(VariedResponse, self).__init__(*args, **kwargs)
|
||||
self.request = request
|
||||
|
||||
@classmethod
|
||||
def for_request(cls, request):
|
||||
return functools.partial(cls, request)
|
||||
|
||||
def set_payload(self, template, context=None):
|
||||
if not self.vary:
|
||||
self.vary = ['Accept']
|
||||
elif 'accept' not in (v.lower() for v in self.vary):
|
||||
self.vary += 'Accept',
|
||||
if context is None:
|
||||
context = {}
|
||||
if template is None or self.request.want == 'json':
|
||||
self.content_type = str('application/json')
|
||||
json.dump(context, self.body_file, cls=SmartJSONEncoder)
|
||||
else:
|
||||
if self.request.want == 'xhtml':
|
||||
self.content_type = str('application/xhtml+xml')
|
||||
self.render(template, context)
|
||||
|
||||
def render(self, template, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
env = jinja2.Environment(loader=self.TMPL_LOADER)
|
||||
env.globals.update(
|
||||
url=self.request.create_href,
|
||||
static=self.request.static_resource,
|
||||
)
|
||||
if hasattr(self.request, 'user'):
|
||||
env.globals['user'] = self.request.user
|
||||
self.text = env.get_template(template).render(**context)
|
||||
|
||||
|
||||
class Application(milla.Application):
|
||||
|
||||
def __init__(self, config=None): # pylint: disable=super-init-not-called
|
||||
self.config = {}
|
||||
if config and os.path.exists(config):
|
||||
self.config.update(milla.util.read_config(config))
|
||||
self.config['milla.favicon'] = False
|
||||
|
||||
self.setup_routes()
|
||||
|
||||
@classmethod
|
||||
def create(cls, config):
|
||||
app = cls(config)
|
||||
return app
|
||||
|
||||
def setup_routes(self):
|
||||
self.dispatcher = r = routing.Router()
|
||||
|
||||
def make_request(self, environ):
|
||||
request = super(Application, self).make_request(environ)
|
||||
default_format = VariedResponse.default_content_type
|
||||
offers = [
|
||||
'application/json',
|
||||
'application/xhtml+xml',
|
||||
'text/html',
|
||||
]
|
||||
want_fmt = request.accept.best_match(offers, default_format)
|
||||
if want_fmt == 'application/json':
|
||||
request.want = 'json'
|
||||
elif want_fmt == 'text/html':
|
||||
request.want = 'html'
|
||||
else:
|
||||
request.want = 'xhtml'
|
||||
request.ResponseClass = VariedResponse.for_request(request)
|
||||
return request
|
Loading…
Reference in New Issue