Codebase review: stability, performance, usability, and i18n fixes
Stability: - Fix race condition: set _is_running before create_task in target processors - Await probe task after cancel in wled_target_processor - Replace raw fetch() with fetchWithAuth() across devices, kc-targets, pattern-templates - Add try/catch to showTestTemplateModal in streams.js - Wrap blocking I/O in asyncio.to_thread (picture_targets, system restore) - Fix dashboardStopAll to filter only running targets with ok guard Performance: - Vectorize fire effect spark loop with numpy in effect_stream - Vectorize FFT band binning with cumulative sum in analysis.py - Rewrite pixel_processor with vectorized numpy (accept ndarray or list) - Add httpx.AsyncClient connection pooling with lock in wled_provider - Optimize _send_pixels_http to avoid np.hstack allocation in wled_client - Mutate chart arrays in-place in dashboard, perf-charts, targets - Merge dashboard 2-batch fetch into single Promise.all - Hoist frame_time outside loop in mapped_stream Usability: - Fix health check interval load/save in device settings - Swap confirm modal button classes (No=secondary, Yes=danger) - Add aria-modal to audio/value source editors, fix close button aria-labels - Add modal footer close button to settings modal - Add dedicated calibration LED count validation error keys i18n: - Replace ~50 hardcoded English strings with t() calls across 12 JS files - Add 50 new keys to en.json, ru.json, zh.json - Localize inline toasts in index.html with window.t fallback - Add data-i18n to command palette footer - Add localization policy to CLAUDE.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
"""System routes: health, version, displays, performance, backup/restore, ADB."""
|
||||
|
||||
import asyncio
|
||||
import io
|
||||
import json
|
||||
import platform
|
||||
@@ -372,15 +373,20 @@ async def restore_config(
|
||||
if not isinstance(stores[key], dict):
|
||||
raise HTTPException(status_code=400, detail=f"Store '{key}' in backup is not a valid JSON object")
|
||||
|
||||
# Write store files atomically
|
||||
# Write store files atomically (in thread to avoid blocking event loop)
|
||||
config = get_config()
|
||||
written = 0
|
||||
for store_key, config_attr in STORE_MAP.items():
|
||||
if store_key in stores:
|
||||
file_path = Path(getattr(config.storage, config_attr))
|
||||
atomic_write_json(file_path, stores[store_key])
|
||||
written += 1
|
||||
logger.info(f"Restored store: {store_key} -> {file_path}")
|
||||
|
||||
def _write_stores():
|
||||
count = 0
|
||||
for store_key, config_attr in STORE_MAP.items():
|
||||
if store_key in stores:
|
||||
file_path = Path(getattr(config.storage, config_attr))
|
||||
atomic_write_json(file_path, stores[store_key])
|
||||
count += 1
|
||||
logger.info(f"Restored store: {store_key} -> {file_path}")
|
||||
return count
|
||||
|
||||
written = await asyncio.to_thread(_write_stores)
|
||||
|
||||
logger.info(f"Restore complete: {written}/{len(STORE_MAP)} stores written. Scheduling restart...")
|
||||
_schedule_restart()
|
||||
|
||||
Reference in New Issue
Block a user