now upto date

This commit is contained in:
Tim Bentley 2016-06-16 22:00:20 +01:00
commit 8b98ee002b
3 changed files with 81 additions and 27 deletions

View File

@ -42,7 +42,13 @@ def register_endpoint(end_point):
""" """
Register an endpoint with the app Register an endpoint with the app
""" """
for url, view_func, method, secure in end_point.routes: for url, view_func, method in end_point.routes:
# Set the view functions
route = _route_from_url(end_point.url_prefix, url) route = _route_from_url(end_point.url_prefix, url)
application.add_route(route, view_func, method, secure) application.add_route(route, view_func, method)
# Add a static route if necessary
if end_point.static_dir:
static_route = _route_from_url(end_point.url_prefix, 'static')
static_route += '(.*)'
application.add_static_route(static_route, end_point.static_dir)

View File

@ -20,29 +20,34 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
openlp/core/api/endpoint.py: Endpoint stuff The Endpoint class, which provides plugins with a way to serve their own portion of the API
""" """
import os
from mako.template import Template
class Endpoint(object): class Endpoint(object):
""" """
This is an endpoint for the HTTP API This is an endpoint for the HTTP API
""" """
def __init__(self, url_prefix): def __init__(self, url_prefix, template_dir=None, static_dir=None):
""" """
Create an endpoint with a URL prefix Create an endpoint with a URL prefix
""" """
print("init") print("init")
self.url_prefix = url_prefix self.url_prefix = url_prefix
self.static_dir = static_dir
self.template_dir = template_dir
self.routes = [] self.routes = []
def add_url_route(self, url, view_func, method, secure): def add_url_route(self, url, view_func, method):
""" """
Add a url route to the list of routes Add a url route to the list of routes
""" """
self.routes.append((url, view_func, method, secure)) self.routes.append((url, view_func, method))
def route(self, rule, method='GET', secure=False): def route(self, rule, method='GET'):
""" """
Set up a URL route Set up a URL route
""" """
@ -50,7 +55,7 @@ class Endpoint(object):
""" """
Make this a decorator Make this a decorator
""" """
self.add_url_route(rule, func, method, secure) self.add_url_route(rule, func, method)
return func return func
return decorator return decorator

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 # vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
# pylint: disable=logging-format-interpolation
############################################################################### ###############################################################################
# OpenLP - Open Source Lyrics Projection # # OpenLP - Open Source Lyrics Projection #
@ -22,17 +23,48 @@
""" """
App stuff App stuff
""" """
import logging
import json import json
import logging
import os
import re import re
from webob import Request, Response from webob import Request, Response
from webob.static import DirectoryApp
from openlp.core.api.http.errors import HttpError, NotFound, ServerError from openlp.core.api.http.errors import HttpError, NotFound, ServerError
ARGS_REGEX = re.compile(r'''\{(\w+)(?::([^}]+))?\}''', re.VERBOSE)
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def _route_to_regex(route):
"""
Convert a route to a regular expression
For example:
'songs/{song_id}' becomes 'songs/(?P<song_id>[^/]+)'
and
'songs/{song_id:\d+}' becomes 'songs/(?P<song_id>\d+)'
"""
route_regex = ''
last_pos = 0
for match in ARGS_REGEX.finditer(route):
route_regex += re.escape(route[last_pos:match.start()])
arg_name = match.group(1)
expr = match.group(2) or '[^/]+'
expr = '(?P<%s>%s)' % (arg_name, expr)
route_regex += expr
last_pos = match.end()
route_regex += re.escape(route[last_pos:])
route_regex = '^%s$' % route_regex
return route_regex
def _make_response(view_result): def _make_response(view_result):
""" """
Create a Response object from response Create a Response object from response
@ -49,18 +81,11 @@ def _make_response(view_result):
response = Response(body=body, status=view_result[1], response = Response(body=body, status=view_result[1],
content_type=content_type, charset='utf8') content_type=content_type, charset='utf8')
if len(view_result) >= 3: if len(view_result) >= 3:
response.headers = view_result[2] response.headers.update(view_result[2])
return response return response
elif isinstance(view_result, dict): elif isinstance(view_result, dict):
return Response(body=json.dumps(view_result), status=200, return Response(body=json.dumps(view_result), status=200,
content_type='application/json', charset='utf8') content_type='application/json', charset='utf8')
elif isinstance(view_result, str):
if 'body {' in view_result:
return Response(body=view_result, status=200,
content_type='text/css', charset='utf8')
else:
return Response(body=view_result, status=200,
content_type='text/html', charset='utf8')
def _handle_exception(error): def _handle_exception(error):
@ -83,26 +108,44 @@ class WSGIApplication(object):
Create the app object Create the app object
""" """
self.name = name self.name = name
self.static_routes = {}
self.route_map = {} self.route_map = {}
def add_route(self, route, view_func, method, secure): def add_route(self, route, view_func, method):
""" """
Add a route Add a route
""" """
if route not in self.route_map: route_regex = _route_to_regex(route)
self.route_map[route] = {} if route_regex not in self.route_map:
self.route_map[route][method.upper()] = {'function': view_func, 'secure': secure} self.route_map[route_regex] = {}
self.route_map[route_regex][method.upper()] = view_func
def add_static_route(self, route, static_dir):
"""
Add a static directory as a route
"""
if not route in self.static_routes:
self.static_routes[route] = DirectoryApp(os.path.abspath(static_dir))
def dispatch(self, request): def dispatch(self, request):
""" """
Find the appropriate URL and run the view function Find the appropriate URL and run the view function
""" """
for route, views in self.route_map.items(): # First look to see if this is a static file request
for route, static_app in self.static_routes.items():
if re.match(route, request.path): if re.match(route, request.path):
if request.method.upper() in views: # Pop the path info twice in order to get rid of the "/<plugin>/static"
log.debug('Found {method} {url}'.format(method=request.method, url=request.path)) request.path_info_pop()
view_func = views[request.method.upper()]['function'] request.path_info_pop()
return _make_response(view_func(request)) return request.get_response(static_app)
# If not a static route, try the views
for route, views in self.route_map.items():
match = re.match(route, request.path)
if match and request.method.upper() in views:
kwargs = match.groupdict()
log.debug('Found {method} {url}'.format(method=request.method, url=request.path))
view_func = views[request.method.upper()]
return _make_response(view_func(request, **kwargs))
log.error('Not Found url {url} '.format(url=request.path)) log.error('Not Found url {url} '.format(url=request.path))
raise NotFound() raise NotFound()