Changeset View
Changeset View
Standalone View
Standalone View
swh/storage/objstorage/api/server.py
- This file was added.
# 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 pickle | |||||
import json | |||||
from flask import Flask, Request, Response, g, request | |||||
from swh.core import config | |||||
from swh.core.serializers import msgpack_dumps, msgpack_loads, SWHJSONDecoder | |||||
from swh.storage.objstorage import ObjStorage | |||||
DEFAULT_CONFIG = { | |||||
'storage_base': ('str', '/tmp/swh/backup/'), | |||||
zack: let's make this /tmp/swh-storage/objects/ | |||||
'storage_depth': ('int', 3), | |||||
} | |||||
Not Done Inline ActionsI noticed that this setting (the port) is not the storage server default config. Any reason to have it here? If not, please remove it for uniformity. zack: I noticed that this setting (the port) is not the storage server default config. Any reason to… | |||||
class BytesRequest(Request): | |||||
"""Request with proper escaping of arbitrary byte sequences.""" | |||||
encoding = 'utf-8' | |||||
encoding_errors = 'surrogateescape' | |||||
app = Flask(__name__) | |||||
app.request_class = BytesRequest | |||||
def encode_data(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 | |||||
@app.errorhandler(Exception) | |||||
def error_handler(exception): | |||||
# XXX: this breaks language-independence and should be | |||||
# replaced by proper serialization of errors | |||||
response = encode_data(pickle.dumps(exception)) | |||||
response.status_code = 400 | |||||
return response | |||||
Not Done Inline ActionsAll this seems copy/pasted from storage/api/server.py, we should avoid that. zack: All this seems copy/pasted from storage/api/server.py, we should avoid that.
This should be… | |||||
@app.before_request | |||||
def before_request(): | |||||
g.objstorage = ObjStorage(app.config['storage_base'], | |||||
app.config['storage_depth']) | |||||
@app.route('/') | |||||
def index(): | |||||
return "Helloworld!" | |||||
@app.route('/content') | |||||
def content(): | |||||
return str(list(g.storage)) | |||||
@app.route('/content/add', methods=['POST']) | |||||
def add_bytes(): | |||||
return encode_data(g.objstorage.add_bytes(**decode_request(request))) | |||||
@app.route('/content/get', methods=['POST']) | |||||
def get_bytes(): | |||||
return encode_data(g.objstorage.get_bytes(**decode_request(request))) | |||||
@app.route('/content/check', methods=['POST']) | |||||
def check(): | |||||
# TODO verify that an error on this content will be properly intercepted | |||||
# by @app.errorhandler and the answer will be sent to client. | |||||
return encode_data(g.objstorage.check(**decode_request(request))) | |||||
if __name__ == '__main__': | |||||
app.config.update(config.read(None, DEFAULT_CONFIG)) | |||||
app.run(host='0.0.0.0', port=8080, debug=True) |
let's make this /tmp/swh-storage/objects/