mirror of
https://github.com/saphid/frame-control.git
synced 2026-10-06 06:00:33 +02:00
Tabs, one offline banner, background installs, drop anywhere
The page was one 6,800px scroll with nine nav links (hidden below 1150px). It is now four tabs, Home, Games, Android and Tools, switched with 1-4; old section links still land on the right tab. When the Frame can't be reached, the server turns ssh's connection errors into one plain message (503, offline: true), the page shows a single banner with Retry and Set Up Connection, retries every 8 s, and reloads every panel when the Frame answers. Panels say "Waiting for the Frame" instead of raw ssh text. Flatpak and Android catalogue installs run as background jobs the page polls, so a slow install no longer holds a request for up to 15 minutes or reports a false failure; the bottom bar counts running installs. Files can be dropped anywhere in the window, as the README already said. Recent reports show the newest five, with Show all. Android display explains an empty or failed read. A topped-up headset on a charger reads as not charging rather than "still draining, using 0.0 W". Fixes a race where the catalogue and reports loads wrote the compat-db mirror's .tmp file at once and one failed with a 500. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
d7fc0189b5
commit
0f770dc88a
9 files changed
+512
-141
No files matched your search
+28
-16
@@ -24,6 +24,7 @@ FIELDS = ('package', 'version', 'result', 'rating', 'notes', 'via', 'date', 'ste
|
||||
'label', 'source')
|
||||
TTL = 60 # seconds a fetched copy is reused
|
||||
_lock = threading.Lock()
|
||||
_load_lock = threading.Lock() # refreshing the cached reports (load); separate from _lock, which flush takes
|
||||
_mem = {'at': 0, 'reports': None, 'source': None}
|
||||
|
||||
|
||||
@@ -179,25 +180,36 @@ def _read_mirror():
|
||||
return []
|
||||
|
||||
|
||||
def _save_mirror(reports):
|
||||
"""Keep a copy for offline use. Failing to write it mustn't fail the read."""
|
||||
try:
|
||||
os.makedirs(STATE, exist_ok=True)
|
||||
with open(MIRROR + '.tmp', 'w') as f:
|
||||
json.dump({'fetched': time.strftime('%Y-%m-%dT%H:%M:%S'), 'reports': reports}, f)
|
||||
os.replace(MIRROR + '.tmp', MIRROR)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def load():
|
||||
"""All reports: the database (cached for TTL s), else the offline mirror; plus unsent ones."""
|
||||
now = time.time()
|
||||
if _mem['reports'] is None or now - _mem['at'] > TTL:
|
||||
try:
|
||||
if not shared():
|
||||
raise DBError('no key')
|
||||
# The page asks for the catalogue and the reports at once: one refresh at a
|
||||
# time, so they share a fetch and never write the mirror's .tmp together.
|
||||
with _load_lock:
|
||||
now = time.time()
|
||||
if _mem['reports'] is None or now - _mem['at'] > TTL:
|
||||
try:
|
||||
flush()
|
||||
except Exception:
|
||||
pass # sending can fail for any reason; reading must still work
|
||||
reports, source = fetch_all(), 'lakebed'
|
||||
os.makedirs(STATE, exist_ok=True)
|
||||
with open(MIRROR + '.tmp', 'w') as f:
|
||||
json.dump({'fetched': time.strftime('%Y-%m-%dT%H:%M:%S'), 'reports': reports}, f)
|
||||
os.replace(MIRROR + '.tmp', MIRROR)
|
||||
except DBError:
|
||||
reports, source = _read_mirror(), 'mirror'
|
||||
_mem.update(at=now, reports=reports, source=source)
|
||||
if not shared():
|
||||
raise DBError('no key')
|
||||
try:
|
||||
flush()
|
||||
except Exception:
|
||||
pass # sending can fail for any reason; reading must still work
|
||||
reports, source = fetch_all(), 'lakebed'
|
||||
_save_mirror(reports)
|
||||
except DBError:
|
||||
reports, source = _read_mirror(), 'mirror'
|
||||
_mem.update(at=now, reports=reports, source=source)
|
||||
sent = {r.get('id') for r in _mem['reports']}
|
||||
return _mem['reports'] + [r for r in _outbox() if r['id'] not in sent]
|
||||
|
||||
|
||||
Reference in new issue
Block a user