db.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. from logging import getLogger
  2. from tinydb import TinyDB
  3. from tinydb.storages import JSONStorage
  4. from tinydb.middlewares import Middleware
  5. from pathlib import Path
  6. class ReadOnlyMiddleware(Middleware):
  7. """
  8. Make sure no write ever occurs
  9. """
  10. def __init__(self, storage_cls=TinyDB.DEFAULT_STORAGE):
  11. super().__init__(storage_cls)
  12. def write(self, data):
  13. raise ReadOnlyException('You cannot write to a readonly db')
  14. class ReadOnlyException(ValueError):
  15. pass
  16. class EventModel(object):
  17. def __init__(self, uri, additional_db_dir=None):
  18. self.uri = uri
  19. self.additional_db_dir = Path(additional_db_dir) if additional_db_dir else None
  20. self._dbs = {}
  21. self.log = getLogger(self.__class__.__name__)
  22. self.reload()
  23. def reload(self):
  24. for db in self._dbs.values():
  25. db.close()
  26. self._dbs['main'] = TinyDB(self.uri, indent=2)
  27. if self.additional_db_dir is not None:
  28. if self.additional_db_dir.is_dir():
  29. for db_file in self.additional_db_dir.glob('*.db.json'):
  30. name = db_file.name[:-8]
  31. if name == 'main':
  32. self.log.warning("%s db file name is not valid (any other name.db.json would have been ok!", str(db_file.name))
  33. continue
  34. if not name.isalpha():
  35. self.log.warning("%s db file name is not valid: it must be alphabetic only", str(db_file.name))
  36. continue
  37. self._dbs[name] = TinyDB(
  38. str(db_file),
  39. storage=ReadOnlyMiddleware(JSONStorage),
  40. default_table='actions'
  41. )
  42. self.log.debug('Loaded %d databases: %s', len(self._dbs), ','.join(self._dbs.keys()))
  43. self._actions = self._dbs['main'].table("actions")
  44. self._alarms = self._dbs['main'].table("alarms")
  45. def canonicalize(self, eid_or_aid):
  46. try:
  47. int(eid_or_aid)
  48. except ValueError:
  49. return eid_or_aid
  50. return 'main:%d' % eid_or_aid
  51. def parse_id(self, eid_or_aid):
  52. try:
  53. int(eid_or_aid)
  54. except ValueError:
  55. pass
  56. else:
  57. return ('main', eid_or_aid)
  58. dbname, num = eid_or_aid.split(':')
  59. return (dbname, int(num))
  60. def get_action_by_id(self, action_id):
  61. db, action_id = self.parse_id(action_id)
  62. return self._dbs[db].table('actions').get(eid=action_id)
  63. def get_alarm_by_id(self, alarm_id):
  64. db, alarm_id = self.parse_id(alarm_id)
  65. return self._dbs[db].table('alarms').get(eid=alarm_id)
  66. def get_actions_by_alarm(self, alarm):
  67. for action_id in alarm.get("actions", []):
  68. action = self.get_action_by_id(action_id)
  69. if action is None:
  70. continue
  71. yield action
  72. def get_all_alarms(self) -> list:
  73. out = []
  74. for db in self._dbs:
  75. out.extend(self._dbs[db].table('alarms').all())
  76. return out
  77. def get_all_actions(self) -> list:
  78. out = []
  79. for db in self._dbs:
  80. out.extend(self._dbs[db].table('actions').all())
  81. return out
  82. def get_all_alarms_expanded(self):
  83. for alarm in self.get_all_alarms():
  84. for action in self.get_actions_by_alarm(alarm):
  85. yield alarm, action
  86. def add_event(self, alarm, actions):
  87. action_ids = [self.add_action(a) for a in actions]
  88. alarm["actions"] = action_ids
  89. return self._alarms.insert(alarm)
  90. def add_action(self, action):
  91. return self._actions.insert(action)
  92. def add_alarm(self, alarm):
  93. return self.add_event(alarm, [])
  94. def update_alarm(self, alarmid, new_fields={}):
  95. return self._alarms.update(new_fields, eids=[alarmid])
  96. def update_action(self, actionid, new_fields={}):
  97. return self._actions.update(new_fields, eids=[actionid])
  98. def delete_alarm(self, alarmid):
  99. return self._alarms.remove(eids=[alarmid])
  100. def delete_action(self, actionid):
  101. return self._actions.remove(eids=[actionid])