From a8784eec9cdda6cbff1417e5b01857ee013dddcf Mon Sep 17 00:00:00 2001 From: Stefano Bertelli Date: Mon, 30 Mar 2026 23:24:51 -0500 Subject: [PATCH] fix: show config dialog immediately, run WG/firewall setup in background In production (WG_WG_ENABLED=true), on_device_created() runs multiple WG and nftables subprocess calls that take seconds. The UI handler was awaiting all of them before showing the config dialog, causing WebSocket timeouts and page reloads. Now the dialog/QR/download appears right after DB commit, and WG peer + firewall configuration runs as a background task via asyncio.create_task. --- wiregui/pages/admin/devices.py | 20 +++++++++----------- wiregui/pages/devices.py | 19 +++++++++---------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/wiregui/pages/admin/devices.py b/wiregui/pages/admin/devices.py index 7a15044..8d052a2 100644 --- a/wiregui/pages/admin/devices.py +++ b/wiregui/pages/admin/devices.py @@ -1,5 +1,6 @@ """Admin device management — view and manage all devices across all users.""" +import asyncio import io from uuid import UUID @@ -123,22 +124,19 @@ async def admin_devices_page(): await session.refresh(device) logger.info("Admin created device: {} for {}", device.name, user_map.get(owner_id)) - await on_device_created(device) - # Show config + # Build config and show dialog immediately — don't wait for WG/firewall server_pubkey = await get_server_public_key() config_text = build_client_config(device, private_key, server_pubkey) - try: - create_dialog.close() - _reset_create_form() - await refresh_table() - _show_config_dialog(device.name, config_text) - except RuntimeError: - pass # Client navigated away during async work + create_dialog.close() + _reset_create_form() + await refresh_table() + _show_config_dialog(device.name, config_text) + + # Configure WG peer and firewall in background + asyncio.create_task(on_device_created(device)) - except RuntimeError: - pass # Client disconnected except Exception as e: logger.error("Failed to create device: {}", e) try: diff --git a/wiregui/pages/devices.py b/wiregui/pages/devices.py index 93746d4..6790a98 100644 --- a/wiregui/pages/devices.py +++ b/wiregui/pages/devices.py @@ -1,5 +1,6 @@ """User-facing device management pages.""" +import asyncio import io from uuid import UUID @@ -108,21 +109,19 @@ async def devices_page(): await session.refresh(device) logger.info("Device created: {} ({})", device.name, device.ipv4) - await on_device_created(device) + # Build config and show dialog immediately — don't wait for WG/firewall server_pubkey = await get_server_public_key() config_text = build_client_config(device, private_key, server_pubkey) - try: - create_dialog.close() - _reset_create_form() - await refresh_table() - _show_config_dialog(device.name, config_text) - except RuntimeError: - pass # Client navigated away during async work + create_dialog.close() + _reset_create_form() + await refresh_table() + _show_config_dialog(device.name, config_text) + + # Configure WG peer and firewall in background (don't block the UI) + asyncio.create_task(on_device_created(device)) - except RuntimeError: - pass # Client disconnected except Exception as e: logger.error("Failed to create device: {}", e) try: