From b87027a3c7d3bc88e2674c9e22c8745c9dbf1043 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 20 Jul 2019 17:18:23 +0300 Subject: Add: MuckStore --- ick2/__init__.py | 2 ++ ick2/apibase.py | 3 +- ick2/exceptions.py | 6 ++++ ick2/store.py | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) (limited to 'ick2') diff --git a/ick2/__init__.py b/ick2/__init__.py index 2720d61..235ee96 100644 --- a/ick2/__init__.py +++ b/ick2/__init__.py @@ -17,6 +17,7 @@ from .version import __version__, __version_info__ from .logging import setup_logging, log from .store import ( MemoryStore, + MuckStore, ) from .resource import ( Resource, @@ -51,6 +52,7 @@ from .exceptions import ( NotFound, ExistsAlready, Conflict, + StoreError, IckException, MethodNotAllowed, ClientIdMissing, diff --git a/ick2/apibase.py b/ick2/apibase.py index 3827f6e..46c17cf 100644 --- a/ick2/apibase.py +++ b/ick2/apibase.py @@ -23,7 +23,8 @@ class APIbase: def __init__(self, state): assert (state is None or - isinstance(state, ick2.MemoryStore)) + isinstance(state, ick2.MemoryStore) or + isinstance(state, ick2.MuckStore)) self._trans = ick2.TransactionalState(state) def get_routes(self, path): diff --git a/ick2/exceptions.py b/ick2/exceptions.py index bd394af..8467e7a 100644 --- a/ick2/exceptions.py +++ b/ick2/exceptions.py @@ -40,6 +40,12 @@ class Conflict(IckException): rid, expected, got)) +class StoreError(IckException): + + def __init__(self, msg): + super().__init__('Error accessing persistent store: {}'.format(msg)) + + class BadUpdate(IckException): def __init__(self, how): diff --git a/ick2/store.py b/ick2/store.py index 5c01f89..83a008b 100644 --- a/ick2/store.py +++ b/ick2/store.py @@ -15,9 +15,13 @@ import copy +import json import uuid +import requests + + import ick2 @@ -75,3 +79,82 @@ class MemoryStore(StoreInterface): def delete(self, token, rid): del self._objs[rid] + + +class MuckStore(StoreInterface): # pragma: no cover + + def __init__(self, muck_url): + self._url = muck_url + ick2.log.log('info', msg_text='MuckStore created', muck_url=muck_url) + + def _request(self, func, path, token, headers=None, body=None): + url = '{}{}'.format(self._url, path) + if headers is None: + headers = {} + headers['Authorization'] = 'Bearer {}'.format(token) + r = func(url, headers=headers, data=body) + ick2.log.log( + 'trace', msg_text='Accessing Muck', + func=repr(func), url=url, path=path, headers=headers, data=body, + status=r.status_code, text=r.text) + if not r.ok: + raise ick2.StoreError(r.text) + return r + + def search(self, token, cond): + headers = { + 'Content-Type': 'application/json', + } + cond = { + 'cond': [ + { + 'where': 'meta', + 'field': 'id', + 'op': '>=', + 'pattern': '', + } + ], + } + body = json.dumps(cond) + r = self._request( + requests.get, '/search', token, headers=headers, body=body) + obj = r.json() + return obj['resources'] + + def create(self, token, obj): + headers = { + 'Content-Type': 'application/json', + } + body = json.dumps(obj) + r = self._request( + requests.post, '/res', token, headers=headers, body=body) + rid = r.headers['Muck-Id'] + rev = r.headers['Muck-Revision'] + return rid, rev + + def show(self, token, rid): + headers = { + 'Muck-Id': rid, + } + r = self._request(requests.get, '/res', token, headers=headers) + rev = r.headers['Muck-Revision'] + as_dict = r.json() + return as_dict, rev + + def update(self, token, rid, obj, revision): + headers = { + 'Content-Type': 'application/json', + 'Muck-Id': rid, + 'Muck-Revision': revision, + } + body = json.dumps(obj) + r = self._request( + requests.put, '/res', token, headers=headers, body=body) + rev = r.headers['Muck-Revision'] + return rev + + def delete(self, token, rid): + headers = { + 'Muck-Id': rid, + } + self._request(requests.delete, '/res', token, headers=headers) -- cgit v1.2.1