back to using marshal, and a filelock

This commit is contained in:
holger krekel
2024-03-27 17:25:29 +01:00
parent 15e7458666
commit 888fa88aa3
2 changed files with 26 additions and 38 deletions

View File

@@ -64,44 +64,31 @@ class Notifier:
self.vmail_dir = vmail_dir self.vmail_dir = vmail_dir
self.to_notify_queue = Queue() self.to_notify_queue = Queue()
def get_metadata_dir(self, mbox): def get_metadata_dict(self, mbox):
"get metadata directory inside mailbox directory"
mbox_path = self.vmail_dir.joinpath(mbox) mbox_path = self.vmail_dir.joinpath(mbox)
if not mbox_path.exists(): if not mbox_path.exists():
mbox_path.mkdir() mbox_path.mkdir()
metadata_dir = mbox_path / "metadata" return PersistentDict(mbox_path / "metadata.marshalled")
if not metadata_dir.exists():
metadata_dir.mkdir()
return metadata_dir
def set_token(self, mbox, token): def add_token(self, mbox, token):
metadata_dir = self.get_metadata_dir(mbox) with self.get_metadata_dict(mbox).modify() as data:
token_path = metadata_dir / METADATA_TOKEN_KEY tokens = data.get(METADATA_TOKEN_KEY)
write_path = token_path.with_suffix(".tmp") if tokens is None:
tokens = [] data[METADATA_TOKEN_KEY] = tokens = []
if token_path.exists(): if token not in tokens:
tokens = token_path.read_text().split() + [token] tokens.append(token)
if token not in tokens:
tokens.append(token)
write_path.write_text(" ".join(tokens))
write_path.rename(token_path)
def del_token(self, mbox, token): def del_token(self, mbox, token):
tokens = self.get_tokens(mbox) with self.get_metadata_dict(mbox).modify() as data:
if token in tokens: tokens = data.get(METADATA_TOKEN_KEY)
tokens.remove(token) if tokens:
token_path = self.get_metadata_dir(mbox) / METADATA_TOKEN_KEY try:
write_path = token_path.with_suffix(".tmp") tokens.remove(token)
write_path.write_text(" ".join(tokens)) except KeyError:
write_path.rename(token_path) pass
def get_tokens(self, mbox): def get_tokens(self, mbox):
metadata_dir = self.get_metadata_dir(mbox) return self.get_metadata_dict(mbox).get().get(METADATA_TOKEN_KEY, [])
if metadata_dir is not None:
token_path = metadata_dir / METADATA_TOKEN_KEY
if token_path.exists():
return token_path.read_text().split()
return []
def new_message_for_mbox(self, mbox): def new_message_for_mbox(self, mbox):
self.to_notify_queue.put(mbox) self.to_notify_queue.put(mbox)
@@ -181,7 +168,7 @@ def handle_dovecot_request(msg, transactions, notifier):
value = parts[2] if len(parts) > 2 else "" value = parts[2] if len(parts) > 2 else ""
mbox = transactions[transaction_id]["mbox"] mbox = transactions[transaction_id]["mbox"]
if keyname[0] == "priv" and keyname[2] == METADATA_TOKEN_KEY: if keyname[0] == "priv" and keyname[2] == METADATA_TOKEN_KEY:
notifier.set_token(mbox, value) notifier.add_token(mbox, value)
elif keyname[0] == "priv" and keyname[2] == "messagenew": elif keyname[0] == "priv" and keyname[2] == "messagenew":
notifier.new_message_for_mbox(mbox) notifier.new_message_for_mbox(mbox)
else: else:

View File

@@ -26,8 +26,8 @@ def test_notifier_persistence(tmp_path):
assert not notifier1.get_tokens("user1@example.org") assert not notifier1.get_tokens("user1@example.org")
assert not notifier2.get_tokens("user1@example.org") assert not notifier2.get_tokens("user1@example.org")
notifier1.set_token("user1@example.org", "01234") notifier1.add_token("user1@example.org", "01234")
notifier1.set_token("user3@example.org", "456") notifier1.add_token("user3@example.org", "456")
assert notifier2.get_tokens("user1@example.org") == ["01234"] assert notifier2.get_tokens("user1@example.org") == ["01234"]
assert notifier2.get_tokens("user3@example.org") == ["456"] assert notifier2.get_tokens("user3@example.org") == ["456"]
notifier2.del_token("user1@example.org", "01234") notifier2.del_token("user1@example.org", "01234")
@@ -164,7 +164,7 @@ def test_notifier_thread_run(notifier):
return Result() return Result()
notifier.set_token("user@example.org", "01234") notifier.add_token("user@example.org", "01234")
notifier.new_message_for_mbox("user@example.org") notifier.new_message_for_mbox("user@example.org")
notifier.thread_run_one(ReqMock()) notifier.thread_run_one(ReqMock())
url, data, timeout = requests[0] url, data, timeout = requests[0]
@@ -184,14 +184,15 @@ def test_multi_device_notifier(notifier):
return Result() return Result()
notifier.set_token("user@example.org", "01234") notifier.add_token("user@example.org", "01234")
notifier.set_token("user@example.org", "56789") notifier.add_token("user@example.org", "56789")
notifier.new_message_for_mbox("user@example.org") notifier.new_message_for_mbox("user@example.org")
notifier.thread_run_one(ReqMock()) notifier.thread_run_one(ReqMock())
url, data, timeout = requests[0] url, data, timeout = requests[0]
assert data == "01234" assert data == "01234"
url, data, timeout = requests[1] url, data, timeout = requests[1]
assert data == "56789" assert data == "56789"
assert notifier.get_tokens("user@example.org") == ["01234", "56789"]
def test_notifier_thread_run_gone_removes_token(notifier): def test_notifier_thread_run_gone_removes_token(notifier):
@@ -206,10 +207,10 @@ def test_notifier_thread_run_gone_removes_token(notifier):
return Result() return Result()
notifier.set_token("user@example.org", "01234") notifier.add_token("user@example.org", "01234")
notifier.new_message_for_mbox("user@example.org") notifier.new_message_for_mbox("user@example.org")
assert notifier.get_tokens("user@example.org") == ["01234"] assert notifier.get_tokens("user@example.org") == ["01234"]
notifier.set_token("user@example.org", "45678") notifier.add_token("user@example.org", "45678")
notifier.thread_run_one(ReqMock()) notifier.thread_run_one(ReqMock())
url, data, timeout = requests[0] url, data, timeout = requests[0]
assert data == "01234" assert data == "01234"