aboutsummaryrefslogtreecommitdiffstats
path: root/femtoqueue.py
diff options
context:
space:
mode:
authorJan Tuomi <jan@jantuomi.fi>2025-05-16 09:52:03 +0300
committerJan Tuomi <jan@jantuomi.fi>2025-05-16 10:03:59 +0300
commit2ce3a78eb131a306ac0d3e30be89097d8b1213b4 (patch)
tree4a7fb42f637d9a66c281cfecdf4c43d49d276fd9 /femtoqueue.py
parentc7c9e67a6d6f2874f104df2881f4171b1664b834 (diff)
Add V1 header for data integrity checking
Diffstat (limited to 'femtoqueue.py')
-rw-r--r--femtoqueue.py43
1 files changed, 40 insertions, 3 deletions
diff --git a/femtoqueue.py b/femtoqueue.py
index 500115b..0badb1d 100644
--- a/femtoqueue.py
+++ b/femtoqueue.py
@@ -2,6 +2,8 @@ from os import makedirs, path, listdir, rename, urandom, fsync
from dataclasses import dataclass
import time
from typing import Generator
+from io import BufferedReader, BufferedWriter
+from hashlib import md5
@dataclass
@@ -72,6 +74,38 @@ class FemtoQueue:
rand_bytes = urandom(8)
return f"{str(time_us)}_{rand_bytes.hex}"
+ def _write_v1(self, f: BufferedWriter, data: bytes):
+ version = (1).to_bytes(1, "little") # 1 byte
+ padding = (0).to_bytes(7, "little") # 7 bytes
+ hash = md5(data).digest()
+ header = version + padding + hash
+ f.write(header)
+ f.write(data)
+
+ def _read_v1(self, f: BufferedReader) -> bytes | None:
+ version_bytes = f.read(1)
+ if version_bytes is None or len(version_bytes) == 0:
+ return None
+
+ version = version_bytes[0]
+ if version != 1:
+ return None
+
+ f.seek(8)
+ stored_hash = f.read(16)
+ if stored_hash is None or len(stored_hash) != 16:
+ return None
+
+ data = f.read()
+ if data is None:
+ return None
+
+ data_hash = md5(data).digest()
+ if data_hash != stored_hash:
+ return None
+
+ return data
+
def push(self, data: bytes, time_us: int | None = None) -> str:
"""
Push a new task into the queue.
@@ -94,7 +128,7 @@ class FemtoQueue:
pending_path = path.join(self.dir_pending, id)
with open(creating_path, "wb") as f:
- f.write(data)
+ self._write_v1(f, data)
if self.sync_after_write:
fsync(f)
@@ -201,8 +235,11 @@ class FemtoQueue:
continue
with open(in_progress_path, "rb") as f:
- content = f.read()
- return FemtoTask(id=id, data=content)
+ data = self._read_v1(f)
+ if data is None:
+ # Data was corrupted, skip
+ continue
+ return FemtoTask(id=id, data=data)
def done(self, task: FemtoTask):
"""