mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-18 04:49:13 +00:00
fix(core): unique snapshot temp name, honour on-demand requests, skip empty starlark
The preview snapshot wrote through a fixed "<snapshot>.tmp". /tmp is world-writable and sticky, and the display service runs as a different user from the tooling, so a leftover temp owned by anyone else became unopenable even by root -- fs.protected_regular refuses O_CREAT on a foreign file in a sticky directory. The preview and the health check's liveness proxy then froze until someone deleted the file by hand; on the test rig that meant 23 hours of a healthy display reporting "hardware: stale". Now uses tempfile.mkstemp with cleanup on failure, matching the hardware-status write a few hundred lines above. Closes #528. _poll_on_demand_requests read its mailbox with max_age=3600, and get() defaults the in-memory TTL to max_age -- so the first request was pinned in memory for an hour and every later poll returned that stale copy. No second on-demand request was honoured until the service restarted, while the API kept returning 200. get() already documents memory_ttl=0 for exactly this cross-process case. The consumed request is also now deleted: leaving it on disk meant a restart replayed the previous request, activated it, and ignored the one the caller had just made. Closes #530. starlark-apps returned None from display() when it has no app to show, which is the state of every install without Pixlet and of a fresh one before any app is added. The controller only skips on a boolean False, so that held a black panel for the full display_duration instead of rotating on. Closes #456 (core side). Verified on the rig: two consecutive on-demand requests with no restart between them are both activated, where the second was previously dropped in silence.
This commit is contained in:
@@ -681,12 +681,18 @@ class StarlarkAppsPlugin(BasePlugin):
|
||||
if app.is_enabled() and app.should_render(current_time):
|
||||
self._render_app(app, force=False)
|
||||
|
||||
def display(self, force_clear: bool = False) -> None:
|
||||
def display(self, force_clear: bool = False) -> bool:
|
||||
"""
|
||||
Display current Starlark app.
|
||||
|
||||
This method is called during the display rotation.
|
||||
Displays frames from the currently active app.
|
||||
|
||||
Returns False when there is no app to show -- which is the state of
|
||||
every install without Pixlet, and of a fresh one before any app is
|
||||
added. The display controller only skips a mode on a boolean False
|
||||
(it checks isinstance(result, bool)), so returning None held a black
|
||||
panel for the full display_duration instead of rotating on.
|
||||
"""
|
||||
try:
|
||||
if force_clear:
|
||||
@@ -699,20 +705,22 @@ class StarlarkAppsPlugin(BasePlugin):
|
||||
if not self.current_app:
|
||||
# No apps available
|
||||
self.logger.debug("No Starlark apps to display")
|
||||
return
|
||||
return False
|
||||
|
||||
# Render app if needed
|
||||
if not self.current_app.frames:
|
||||
success = self._render_app(self.current_app, force=True)
|
||||
if not success:
|
||||
self.logger.error(f"Failed to render app: {self.current_app.app_id}")
|
||||
return
|
||||
return False
|
||||
|
||||
# Display current frame
|
||||
self._display_frame()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error displaying Starlark app: {e}")
|
||||
return False
|
||||
|
||||
def _select_next_app(self) -> None:
|
||||
"""Select the next enabled app for display."""
|
||||
|
||||
Reference in New Issue
Block a user