From ff35e5bfc58fd07128cdff451bfb319b2a40090a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 16 Jul 2019 13:52:54 +1000 Subject: [PATCH] Cache the json files to disentangle them from Tuhi Tuhi caches the json data but has no guarantee about storage. So we cache the json we get from Tuhi and store it in our settings dir through our Config backend. Then we use those cached values to generate the SVG files. --- tuhigui/config.py | 31 ++++++++++++++++++++++++ tuhigui/drawing.py | 1 + tuhigui/drawingperspective.py | 45 +++++++++++++++++++++++++++-------- 3 files changed, 67 insertions(+), 10 deletions(-) diff --git a/tuhigui/config.py b/tuhigui/config.py index df3d864..ef3d621 100644 --- a/tuhigui/config.py +++ b/tuhigui/config.py @@ -17,6 +17,7 @@ from gi.repository import GObject import xdg.BaseDirectory import configparser import logging +import json from pathlib import Path logger = logging.getLogger('config') @@ -33,7 +34,9 @@ class Config(GObject.Object): self.config = configparser.ConfigParser() # Don't lowercase options self.config.optionxform = str + self._drawings = [] self._load() + self._load_cached_drawings() def _load(self): if not self.path.exists(): @@ -42,6 +45,15 @@ class Config(GObject.Object): logger.debug(f'configuration found') self.config.read(self.path) + def _load_cached_drawings(self): + if not ROOT_PATH.exists(): + return + + for filename in ROOT_PATH.glob('*.json'): + with open(filename) as fd: + self._drawings.append(json.load(fd)) + self.notify('drawings') + def _write(self): self.path.resolve().parent.mkdir(parents=True, exist_ok=True) with open(self.path, 'w') as fd: @@ -65,6 +77,25 @@ class Config(GObject.Object): assert(orientation in ['landscape', 'portrait']) self._add_key('Device', 'Orientation', orientation) + @GObject.property + def drawings(self): + return self._drawings + + def add_drawing(self, timestamp, json_string): + '''Add a drawing JSON with the given timestamp to the backend + storage. This will update self.drawings.''' + ROOT_PATH.mkdir(parents=True, exist_ok=True) + + path = Path(ROOT_PATH, f'{timestamp}.json') + if path.exists(): + return + + with open(path, 'w') as fd: + fd.write(json_string) + + self._drawings.append(json.loads(json_string)) + self.notify('drawings') + @classmethod def load(cls): if cls._config_obj is None: diff --git a/tuhigui/drawing.py b/tuhigui/drawing.py index 2c2cd37..c867164 100644 --- a/tuhigui/drawing.py +++ b/tuhigui/drawing.py @@ -51,6 +51,7 @@ class Drawing(Gtk.Box): self.label_timestamp.set_text(f'{day} {hour}') self.image_svg.set_from_file(svg.filename) self.image_completed.set_visible(False) + self.timestamp = svg.timestamp @GObject.Property def name(self): diff --git a/tuhigui/drawingperspective.py b/tuhigui/drawingperspective.py index 30ad97b..4dc82bf 100644 --- a/tuhigui/drawingperspective.py +++ b/tuhigui/drawingperspective.py @@ -16,7 +16,6 @@ from .drawing import Drawing from .svg import JsonSvg from .config import Config -import json import time import gi import logging @@ -73,18 +72,35 @@ class DrawingPerspective(Gtk.Stack): self.flowbox_drawings.remove(child) child = self.flowbox_drawings.get_child_at_index(0) - self._update_drawings(self.device, None) + self._update_drawings(Config.load(), None) - def _update_drawings(self, device, pspec): - for ts in reversed(sorted(self.device.drawings_available)): - if ts in self.known_drawings: + def _cache_drawings(self, device, pspec): + # The config backend filters duplicates anyway, so don't care here + for ts in self.device.drawings_available: + json_string = self.device.json(ts) + Config.load().add_drawing(ts, json_string) + + def _update_drawings(self, config, pspec): + for js in config.drawings: + if js in self.known_drawings: continue - self.known_drawings.append(ts) - js = json.loads(self.device.json(ts)) + self.known_drawings.append(js) + svg = JsonSvg(js) drawing = Drawing(svg) - self.flowbox_drawings.add(drawing) + + # We don't know which order we get drawings from the device, so + # let's do a sorted insert here + index = 0 + child = self.flowbox_drawings.get_child_at_index(index) + while child is not None: + if child.get_child().timestamp < drawing.timestamp: + break + index += 1 + child = self.flowbox_drawings.get_child_at_index(index) + + self.flowbox_drawings.insert(drawing, index) @GObject.Property def device(self): @@ -99,11 +115,20 @@ class DrawingPerspective(Gtk.Stack): device.connect('notify::sync-state', self._on_sync_state) device.connect('notify::battery-percent', self._on_battery_changed) device.connect('notify::battery-state', self._on_battery_changed) - device.connect('notify::drawings-available', self._update_drawings) + + # This is a bit convoluted. We need to cache all drawings + # because Tuhi doesn't have guaranteed storage. So any json that + # comes in from Tuhi, we pass to our config backend to save + # somewhere. + # The config backend adds the json file and emits a notify for the + # json itself (once cached) that we then actually use for SVG + # generation. + device.connect('notify::drawings-available', self._cache_drawings) + Config.load().connect('notify::drawings', self._update_drawings) self._on_battery_changed(device, None) - self._update_drawings(self.device, None) + self._update_drawings(Config.load(), None) # We always want to sync on startup logger.debug(f'{device.name} - starting to listen')