Timotej Lazar
22cec64bef
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.
45 lines
1 KiB
Python
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)
|