- commit
- 474da8ad2523a3329021bde04a437c4984c085b7
- parent
- d28b945f1a8c255237304178d9cf9d3a4933a18c
- Author
- Tobias Bengfort <tobias.bengfort@posteo.de>
- Date
- 2017-07-28 21:30
use aiohttp directly instead of deprecated fakes we losse some minor functionality like - automatic redirects on missing trailing slash - automatic HEAD/OPTIONS routes - ordered json response
Diffstat
| M | jsonproxy/__init__.py | 96 | +++++++++++++++++++++++++++++++++++++++++++------------------ |
| M | setup.py | 2 | +- |
2 files changed, 69 insertions, 29 deletions
diff --git a/jsonproxy/__init__.py b/jsonproxy/__init__.py
@@ -1,13 +1,13 @@ -1 1 from functools import lru_cache -1 2 from pkg_resources import resource_filename 1 3 import argparse -1 4 import asyncio 2 5 import os 3 6 import sys 4 7 -1 8 from aiohttp import web 5 9 import aiohttp6 -17 -1 from fakes import Fakes8 -1 from fakes import jsonify9 -1 from fakes import make_response10 -1 from fakes import abort-1 10 import jinja2 11 11 12 12 from .lib import check_config 13 13 from .lib import _doc @@ -16,14 +16,32 @@ from .lib import scrape 16 16 17 17 __version__ = '2.0.0' 18 1819 -1 app = Fakes(__name__)-1 19 CONFIG = {} 20 20 21 21 22 22 def get_config(endpoint): 23 23 try:24 -1 return app.config[ENDPOINTS][endpoint]-1 24 return CONFIG[ENDPOINTS][endpoint] 25 25 except KeyError:26 -1 abort(404)-1 26 raise aiohttp.web_exceptions.HTTPNotFound -1 27 -1 28 -1 29 @lru_cache() -1 30 def get_template(name): -1 31 local_path = os.path.join('templates', name) -1 32 path = resource_filename(__name__, local_path) -1 33 with open(path) as fh: -1 34 s = fh.read() -1 35 return jinja2.Template(s) -1 36 -1 37 -1 38 def render_template(name, **kwargs): -1 39 """Shortcut for rendering a jinja template to a response.""" -1 40 template = get_template(name) -1 41 text = template.render(**kwargs) -1 42 return web.Response( -1 43 body=text.encode('utf8'), -1 44 content_type='text/html') 27 45 28 46 29 47 def async_cache(maxsize=128): @@ -43,17 +61,16 @@ def async_cache(maxsize=128): 43 61 44 62 @async_cache() 45 63 async def _request(method, url):46 -1 app.logger.info('{}:{}'.format(method, url))-1 64 print('{}:{}'.format(method, url)) 47 65 async with aiohttp.request(method, url) as response:48 -1 if response.status != 200:49 -1 abort(response.status)50 -1 else:51 -1 # get response before closing the connection52 -1 await response.read()53 -1 return response-1 66 if response.status == 404: -1 67 raise aiohttp.web_exceptions.HTTPNotFound -1 68 response.raise_for_status() -1 69 # get response before closing the connection -1 70 await response.read() -1 71 return response 54 72 55 7356 -1 @app.route('/{endpoint}/{path:.+}')57 74 async def handle(request): 58 75 endpoint = request.match_info['endpoint'] 59 76 @@ -70,27 +87,26 @@ async def handle(request): 70 87 body = await remote.read() 71 88 72 89 if 'fields' in config:73 -1 response = jsonify(scrape(url, body, config), status=remote.status)-1 90 data = scrape(url, body, config) -1 91 response = web.json_response(data, status=remote.status) 74 9275 -1 if app.config.get('ALLOW_CORS', False):-1 93 if CONFIG.get('ALLOW_CORS', False): 76 94 response.headers['Access-Control-Allow-Origin'] = '*' 77 95 78 96 return response 79 97 80 9881 -1 @app.route('/')82 99 def index(request):83 -1 config = app.config[ENDPOINTS]-1 100 config = CONFIG[ENDPOINTS] 84 101 data = [_doc(config[endpoint], endpoint) for endpoint in config]85 -1 return app.render_template('index.html', endpoints=data)-1 102 return render_template('index.html', endpoints=data) 86 103 87 10488 -1 @app.route('/{endpoint}/')89 105 def doc(request): 90 106 endpoint = request.match_info['endpoint'] 91 107 config = get_config(endpoint) 92 108 data = [_doc(config, endpoint)]93 -1 return app.render_template('index.html', endpoints=data)-1 109 return render_template('index.html', endpoints=data) 94 110 95 111 96 112 def parse_args(): @@ -106,16 +122,40 @@ def parse_args(): 106 122 def main(): 107 123 args = parse_args() 108 124109 -1 app.config_from_file(os.path.abspath(args.config))110 -1 app.debug = args.debug-1 125 config_path = os.path.abspath(args.config) -1 126 with open(config_path) as fh: -1 127 exec(compile(fh.read(), config_path, 'exec'), CONFIG) # nosec 111 128112 -1 errors = check_config(app.config)-1 129 errors = check_config(CONFIG) 113 130 if errors: 114 131 for error in errors:115 -1 app.logger.error(error)-1 132 print(error) 116 133 sys.exit(1) 117 134118 -1 app.run(host=args.host, port=args.port)-1 135 loop = asyncio.get_event_loop() -1 136 app = web.Application(loop=loop) -1 137 -1 138 app.router.add_route('GET', '/', index) -1 139 app.router.add_route('GET', '/{endpoint}/', doc) -1 140 app.router.add_route('GET', '/{endpoint}/{path:.+}', handle) -1 141 -1 142 h = app.make_handler() -1 143 f = loop.create_server(h, args.host, args.port) -1 144 srv = loop.run_until_complete(f) -1 145 msg = "Running on http://{}:{}/ (Press CTRL+C to quit)" -1 146 print(msg.format(args.host, args.port)) -1 147 -1 148 try: -1 149 loop.run_forever() -1 150 except KeyboardInterrupt: -1 151 pass -1 152 finally: -1 153 loop.run_until_complete(h.finish_connections(1.0)) -1 154 srv.close() -1 155 loop.run_until_complete(srv.wait_closed()) -1 156 loop.run_until_complete(app.cleanup()) -1 157 -1 158 loop.close() 119 159 120 160 121 161 if __name__ == '__main__':
diff --git a/setup.py b/setup.py
@@ -23,7 +23,7 @@ setup( 23 23 packages=['jsonproxy'], 24 24 include_package_data=True, 25 25 install_requires=[26 -1 'Fakes',-1 26 'aiohttp', 27 27 'beautifulsoup4', 28 28 ], 29 29 entry_points={'console_scripts': [