Implement write auto-persist file storage
Closes https://git.autonomic.zone/decentral1se/xbotlib/issues/39.
This commit is contained in:
parent
b1f4d6112f
commit
2e8c9e739e
|
@ -1,5 +1,9 @@
|
|||
# xbotlib x.x.x (UNRELEASED)
|
||||
|
||||
# xbotlib 0.15.1 (2021-01-24)
|
||||
|
||||
- Save to file based storage on all writes ([#39](https://git.autonomic.zone/decentral1se/xbotlib/issues/39))
|
||||
|
||||
# xbotlib 0.15.0 (2021-01-23)
|
||||
|
||||
- Fix configuration generation to cover mandatory options ([#1](https://git.vvvvvvaria.org/decentral1se/xbotlib/issues/1))
|
||||
|
|
|
@ -4,7 +4,7 @@ build-backend = "poetry.masonry.api"
|
|||
|
||||
[tool.poetry]
|
||||
name = "xbotlib"
|
||||
version = "0.15.0"
|
||||
version = "0.15.1"
|
||||
description = "XMPP bots for humans"
|
||||
authors = ["decentral1se <lukewm@riseup.net>"]
|
||||
maintainers = ["decentral1se <lukewm@riseup.net>"]
|
||||
|
|
91
xbotlib.py
91
xbotlib.py
|
@ -18,6 +18,59 @@ from humanize import naturaldelta
|
|||
from slixmpp import ClientXMPP
|
||||
|
||||
|
||||
class SimpleDatabase(dict):
|
||||
"""A simple database.
|
||||
|
||||
It is a dictionary which saves to disk on all writes. It is optimised for
|
||||
ease of hacking and accessibility and not for performance or efficiency.
|
||||
"""
|
||||
|
||||
def __init__(self, filename, *args, **kwargs):
|
||||
"""Initialise the object."""
|
||||
self.filename = Path(filename).absolute()
|
||||
self._loads()
|
||||
self.update(*args, **kwargs)
|
||||
|
||||
def _loads(self):
|
||||
"""Load the database."""
|
||||
if not exists(self.filename):
|
||||
return
|
||||
|
||||
try:
|
||||
with open(self.filename, "r") as handle:
|
||||
self.update(loads(handle.read()))
|
||||
except Exception as exception:
|
||||
message = f"Loading file storage failed: {exception}"
|
||||
self.log.debug(message)
|
||||
exit(1)
|
||||
|
||||
def _dumps(self):
|
||||
"""Save the databse to disk."""
|
||||
try:
|
||||
with open(self.filename, "w") as handle:
|
||||
handle.write(dumps(self))
|
||||
except Exception as exception:
|
||||
message = f"Saving file storage failed: {exception}"
|
||||
self.log.debug(message)
|
||||
exit(1)
|
||||
|
||||
def __setitem__(self, key, val):
|
||||
"""Write data to the database."""
|
||||
dict.__setitem__(self, key, val)
|
||||
self._dumps()
|
||||
|
||||
def __delitem__(self, key):
|
||||
"""Remove data from the database."""
|
||||
dict.__delitem__(key)
|
||||
self._dumps()
|
||||
|
||||
def update(self, *args, **kwargs):
|
||||
"""Update the database."""
|
||||
for k, v in dict(*args, **kwargs).items():
|
||||
self[k] = v
|
||||
self._dumps()
|
||||
|
||||
|
||||
class SimpleMessage:
|
||||
"""A simple message interface."""
|
||||
|
||||
|
@ -478,10 +531,17 @@ class Bot(ClientXMPP):
|
|||
if self.command(message, to=message.sender):
|
||||
return
|
||||
|
||||
if not hasattr(self, "direct"):
|
||||
self.log.info(f"Bot.direct not implemented for {self.nick}")
|
||||
return
|
||||
|
||||
try:
|
||||
self.direct(message)
|
||||
except AttributeError:
|
||||
self.log.info(f"Bot.direct not implemented for {self.nick}")
|
||||
except Exception as exception:
|
||||
self.log.info(f"Bot.direct threw exception {exception}")
|
||||
|
||||
if self.storage == "file":
|
||||
self.db._dumps()
|
||||
|
||||
def session_start(self, message):
|
||||
"""Handle session_start event."""
|
||||
|
@ -548,10 +608,17 @@ class Bot(ClientXMPP):
|
|||
if self.command(message, room=message.room):
|
||||
return
|
||||
|
||||
if not hasattr(self, "group"):
|
||||
self.log.info(f"Bot.group not implemented for {self.nick}")
|
||||
return
|
||||
|
||||
try:
|
||||
self.group(message)
|
||||
except AttributeError:
|
||||
self.log.info(f"Bot.group not implemented for {self.nick}")
|
||||
except Exception as exception:
|
||||
self.log.info(f"Bot.group threw exception: {exception}")
|
||||
|
||||
if self.storage == "file":
|
||||
self.db._dumps()
|
||||
|
||||
def register_xmpp_plugins(self):
|
||||
"""Register XMPP plugins that the bot supports."""
|
||||
|
@ -572,9 +639,7 @@ class Bot(ClientXMPP):
|
|||
"""Initialise the storage back-end."""
|
||||
if self.storage == "file":
|
||||
try:
|
||||
self.db = {}
|
||||
if exists(self.storage_file):
|
||||
self.db = loads(open(self.storage_file, "r").read())
|
||||
self.db = SimpleDatabase(self.storage_file)
|
||||
self.log.info("Successfully loaded file storage")
|
||||
except Exception as exception:
|
||||
message = f"Failed to load {self.storage_file}: {exception}"
|
||||
|
@ -605,17 +670,7 @@ class Bot(ClientXMPP):
|
|||
self.serve_web()
|
||||
self.process(forever=False)
|
||||
except (KeyboardInterrupt, RuntimeError):
|
||||
if self.storage != "file":
|
||||
exit(0)
|
||||
|
||||
try:
|
||||
with open(self.storage_file, "w") as handle:
|
||||
handle.write(dumps(self.db))
|
||||
self.log.info("Successfully saved file storage")
|
||||
except Exception as exception:
|
||||
message = f"Failed to save file storage: {exception}"
|
||||
self.log.info(message)
|
||||
exit(1)
|
||||
pass
|
||||
|
||||
def serve_web(self):
|
||||
"""Serve the web."""
|
||||
|
|
Loading…
Reference in New Issue