friwall/web/db.py
Timotej Lazar 22cec64bef Simplify database locking
Use a single lock for everything to ensure we don’t go inconsistent.
One exception is the firewall nodes table which is only accessed when
pushing updated config.
2023-05-19 09:30:28 +02:00

45 lines
1 KiB
Python

import contextlib
import json
import pathlib
import time
def lock(name, timeout=5):
lockfile = pathlib.Path.home() / f'{name}.lock'
for i in range(timeout):
try:
lockfile.symlink_to('/dev/null')
return
except FileExistsError:
time.sleep(1)
raise TimeoutError(f'could not lock {name}')
def unlock(name='db'):
lockfile = pathlib.Path.home() / f'{name}.lock'
lockfile.unlink(missing_ok=True)
@contextlib.contextmanager
def locked(name='db'):
lock(name)
try:
yield name
finally:
unlock(name)
def read(name):
with open(pathlib.Path.home() / f'{name}.json', 'a+', encoding='utf-8') as f:
f.seek(0)
return json.loads(f.read() or '{}')
def write(name, data):
with open(pathlib.Path.home() / f'{name}.json', 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2)
f.close()
def load(name):
with locked():
return read(name)
def save(name, data):
with locked():
write(name, data)