fime/data.py
2020-02-19 23:12:56 +01:00

104 lines
2.8 KiB
Python

import os
import json
import atexit
from threading import Thread, Event
from collections.abc import MutableMapping
from PySide2 import QtCore
data_dir_path = os.path.join(QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.AppDataLocation),
"fimefracking")
tasks_path = os.path.join(data_dir_path, "tasks.json")
data_path = os.path.join(data_dir_path, "data_{}.json")
save_delay = 3 * 60
class Tasks:
def __init__(self):
if not os.path.exists(data_dir_path):
os.mkdir(data_dir_path)
if os.path.exists(tasks_path):
with open(tasks_path, "r") as f:
self._tasks = json.loads(f.read())
else:
self._tasks = []
@property
def tasks(self):
return self._tasks
@tasks.setter
def tasks(self, tasks):
self._tasks = tasks
self._save()
def _save(self):
print("...saving tasks...")
with open(tasks_path, "w+") as f:
f.write(json.dumps(self._tasks))
class Data(MutableMapping):
def __init__(self):
if not os.path.exists(data_dir_path):
os.mkdir(data_dir_path)
self._cache = {}
self._hot_keys = []
self._running = False
self._tevent = Event()
self._thread = None
def cleanup():
self._running = False
self._tevent.set()
if self._thread:
self._thread.join()
atexit.register(cleanup)
def __getitem__(self, key):
dpath = data_path.format(key)
if key not in self._cache and os.path.exists(dpath):
with open(dpath, "r") as f:
self._cache[key] = f.read()
return self._cache[key]
def __setitem__(self, key, value):
self._cache[key] = value
self._hot_keys.append(key)
self._schedule_save()
def _schedule_save(self):
if self._running:
return
self._running = True
self._thread = Thread(target=self._executor, daemon=True)
self._thread.start()
def _executor(self):
while self._running:
self._tevent.wait(save_delay)
self._save()
def _save(self):
for key in self._hot_keys:
print(f"... saving dict {key} ...")
to_write = self._cache[key] # apparently thread-safe
with open(data_path.format(key), "w+") as f:
f.write(json.dumps(to_write))
self._hot_keys = []
self._saving = False
def __delitem__(self, key):
print("WARNING: deletion of items not supported")
def __iter__(self):
return iter(self._cache)
def __len__(self):
return len(self._cache)
def __repr__(self):
return f"{type(self).__name__}({self._cache})"