diff --git a/swh/objstorage/api/common.py b/swh/objstorage/api/common.py deleted file mode 100644 index 8b883f2..0000000 --- a/swh/objstorage/api/common.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (C) 2015 The Software Heritage developers -# See the AUTHORS file at the top-level directory of this distribution -# License: GNU General Public License version 3, or any later version -# See top-level LICENSE file for more information - -import json -import pickle - -from flask import Request, Response - -from swh.core.serializers import msgpack_dumps, msgpack_loads, SWHJSONDecoder - - -class BytesRequest(Request): - """Request with proper escaping of arbitrary byte sequences.""" - encoding = 'utf-8' - encoding_errors = 'surrogateescape' - - -def encode_data_server(data): - return Response( - msgpack_dumps(data), - mimetype='application/x-msgpack', - ) - - -def decode_request(request): - content_type = request.mimetype - data = request.get_data() - - if content_type == 'application/x-msgpack': - r = msgpack_loads(data) - elif content_type == 'application/json': - r = json.loads(data, cls=SWHJSONDecoder) - else: - raise ValueError('Wrong content type `%s` for API request' - % content_type) - - return r - - -def error_handler(exception, encoder): - # XXX: this breaks language-independence and should be - # replaced by proper serialization of errors - response = encoder(pickle.dumps(exception)) - response.status_code = 400 - return response diff --git a/swh/objstorage/api/server.py b/swh/objstorage/api/server.py index 2e983e9..3c4c063 100644 --- a/swh/objstorage/api/server.py +++ b/swh/objstorage/api/server.py @@ -1,114 +1,113 @@ -# Copyright (C) 2015 The Software Heritage developers +# Copyright (C) 2015-2017 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information import click import logging -from flask import Flask, g, request +from flask import g, request from swh.core import config +from swh.core.api import (SWHServerAPIApp, decode_request, + error_handler, + encode_data_server as encode_data) from swh.objstorage import get_objstorage -from swh.objstorage.api.common import (BytesRequest, decode_request, - error_handler, - encode_data_server as encode_data) DEFAULT_CONFIG = { 'cls': ('str', 'pathslicing'), 'args': ('dict', { 'root': '/srv/softwareheritage/objects', 'slicing': '0:2/2:4/4:6', }) } -app = Flask(__name__) -app.request_class = BytesRequest +app = SWHServerAPIApp(__name__) @app.errorhandler(Exception) def my_error_handler(exception): return error_handler(exception, encode_data) @app.before_request def before_request(): g.objstorage = get_objstorage(app.config['cls'], app.config['args']) @app.route('/') def index(): return "SWH Objstorage API server" @app.route('/check_config', methods=['POST']) def check_config(): return encode_data(g.objstorage.check_config(**decode_request(request))) @app.route('/content') def content(): return str(list(g.storage)) @app.route('/content/contains', methods=['POST']) def contains(): return encode_data(g.objstorage.__contains__(**decode_request(request))) @app.route('/content/add', methods=['POST']) def add_bytes(): return encode_data(g.objstorage.add(**decode_request(request))) @app.route('/content/get', methods=['POST']) def get_bytes(): return encode_data(g.objstorage.get(**decode_request(request))) @app.route('/content/get/batch', methods=['POST']) def get_batch(): return encode_data(g.objstorage.get_batch(**decode_request(request))) @app.route('/content/get/random', methods=['POST']) def get_random_contents(): return encode_data( g.objstorage.get_random(**decode_request(request)) ) @app.route('/content/check', methods=['POST']) def check(): return encode_data(g.objstorage.check(**decode_request(request))) def run_from_webserver(environ, start_response): """Run the WSGI app from the webserver, loading the configuration. """ config_path = '/etc/softwareheritage/storage/objstorage.yml' app.config.update(config.read(config_path, DEFAULT_CONFIG)) handler = logging.StreamHandler() app.logger.addHandler(handler) return app(environ, start_response) @click.command() @click.argument('config-path', required=1) @click.option('--host', default='0.0.0.0', help="Host to run the server") @click.option('--port', default=5000, type=click.INT, help="Binding port of the server") @click.option('--debug/--nodebug', default=True, help="Indicates if the server should run in debug mode") def launch(config_path, host, port, debug): app.config.update(config.read(config_path, DEFAULT_CONFIG)) app.run(host, port=int(port), debug=bool(debug)) if __name__ == '__main__': launch()