diff --git a/README.rst b/README.rst index f7abae2..07460e0 100644 --- a/README.rst +++ b/README.rst @@ -16,7 +16,7 @@ Software stack * python2 * gevent as an async framework * flask to provide web interface and rpc -* ejdb as an embedded database +* tinydb as an embedded database Why? (aka design features) -------------------------- diff --git a/larigira/event.py b/larigira/event.py index baddf9b..c9e750c 100644 --- a/larigira/event.py +++ b/larigira/event.py @@ -12,21 +12,50 @@ from datetime import datetime, timedelta import gevent from gevent.queue import Queue +from tinydb import TinyDB from eventutils import ParentedLet from timegen import timegenerate from audiogen import audiogenerate +class EventModel(object): + def __init__(self, uri): + self.uri = uri + self.db = TinyDB(uri) + self.actions = self.db.table('actions') + self.alarms = self.db.table('alarms') + + def get_action_by_id(self, action_id): + return self.actions.get(eid=action_id) + + def get_alarm_by_id(self, alarm_id): + return self.alarms.get(eid=alarm_id) + + def get_actions_by_alarm(self, alarm): + for action_id in alarm.get('actions', []): + yield self.get_action_by_id(action_id) + + def get_all_alarms(self): + return self.alarms.all() + + def get_all_alarms_expanded(self): + for alarm in self.get_all_alarms(): + for action in self.get_actions_by_alarm(alarm): + yield alarm, action + + def add_event(self, alarm, actions): + action_ids = [self.actions.insert(a) for a in actions] + alarm['actions'] = action_ids + return self.alarms.insert(alarm) + + class EventSource(ParentedLet): def __init__(self, queue, uri): ParentedLet.__init__(self, queue) - import pyejdb self.log = logging.getLogger(self.__class__.__name__) self.log.debug('uri is %s' % uri) - self.ejdb = pyejdb.EJDB(uri, - pyejdb.JBOREADER | pyejdb.JBOLCKNB | - pyejdb.JBOTRUNC) + self.model = EventModel(uri) self.log.debug('opened %s' % uri) def parent_msg(self, kind, *args): @@ -38,40 +67,16 @@ class EventSource(ParentedLet): msg = ParentedLet.parent_msg(self, kind, *args) return msg - def _get_actions_by_alarm(self, alarm): - if 'actions' not in alarm: - return - for action_id in alarm['actions']: - with self.ejdb.find('actions', - {'_id': action_id}) as subcur: - for action in subcur: - yield action - - def _get_by_alarmid(self, alarmid): - with self.ejdb.find('alarms', {'_id': alarmid}) as cur: - if len(cur) > 1: - self.log.warn("Found more than one alarm with given id") - for alarm in cur: - for action in self._get_actions_by_alarm(alarm): - yield alarm, action - - def reload(self): - with self.ejdb.find('alarms', {}) as cur: - for alarm in cur: - self.log.info('%s\t%s' % (alarm['kind'], - ', '.join(alarm.keys()))) - for action in self._get_actions_by_alarm(alarm): - yield alarm, action - - def reload_id(self, event_id): + def reload_id(self, alarm_id): ''' Check if the event is still valid, and put "add" messages on queue ''' - for alarm, action in self._get_by_alarmid(event_id): + alarm = self.model.get_alarm_by_id(alarm_id) + for action in self.model.get_actions_by_alarm(alarm): self.send_to_parent('add', alarm, action) def do_business(self): - for alarm, action in self.reload(): + for alarm, action in self.model.get_all_alarms_expanded(): yield ('add', alarm, action) diff --git a/larigira/tests/test_db.py b/larigira/tests/test_db.py new file mode 100644 index 0000000..7be59a4 --- /dev/null +++ b/larigira/tests/test_db.py @@ -0,0 +1,43 @@ +from __future__ import print_function +import tempfile +import os + +from gevent import monkey +monkey.patch_all(subprocess=True) + +import pytest + +from larigira.event import EventModel + + +@pytest.yield_fixture +def db(): + fname = tempfile.mktemp(suffix='.json', prefix='larigira-test') + yield EventModel(uri=fname) + os.unlink(fname) + + +def test_empty(db): + assert len(db.get_all_alarms()) == 0 + + +def test_add_basic(db): + assert len(db.get_all_alarms()) == 0 + alarm_id = db.add_event(dict(kind='frequency', interval=60*3, start=1), + [dict(kind='mpd', paths=['foo.mp3'], howmany=1)]) + assert len(db.get_all_alarms()) == 1 + assert db.get_alarm_by_id(alarm_id) is not None + assert len(tuple(db.get_actions_by_alarm( + db.get_alarm_by_id(alarm_id)))) == 1 + + +def test_add_multiple_alarms(db): + assert len(db.get_all_alarms()) == 0 + alarm_id = db.add_event(dict(kind='frequency', interval=60*3, start=1), + [dict(kind='mpd', paths=['foo.mp3'], howmany=1), + dict(kind='foo', a=3)]) + assert len(db.get_all_alarms()) == 1 + assert db.get_alarm_by_id(alarm_id) is not None + assert len(db.actions.all()) == 2 + assert len(tuple(db.get_actions_by_alarm( + db.get_alarm_by_id(alarm_id)))) == 2 diff --git a/setup.py b/setup.py index ae0ff29..d067dbd 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ setup(name='larigira', 'gevent', 'flask', 'python-mpd2', - 'pyejdb' + 'tinydb' ], tests_require=['pytest', 'pytest-timeout'], cmdclass={'test': PyTest},