diff --git a/Launcher/TeslaLauncherAgent.cs b/Launcher/TeslaLauncherAgent.cs index 4bfd73d..789d467 100644 --- a/Launcher/TeslaLauncherAgent.cs +++ b/Launcher/TeslaLauncherAgent.cs @@ -58,16 +58,22 @@ namespace Tesla.Launcher.Agent Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - // First-boot check: if this machine is unconfigured (DHCP adapter), - // show a waiting splash. The Service (Session 0) runs the full - // SecureConfig protocol and applies the static IP. - // When the splash detects configuration is complete it closes itself, - // and we fall through to start the normal Agent with the pipe server. - if (!IsMachineConfigured()) + // First-boot check: show the configuring splash (with the SecureConfig + // Request ID + Passphrase) when the machine is unconfigured OR when + // SecureConfig is actively running. + // + // The second condition is essential: during SecureConfig the Service + // assigns a TEMPORARY static IP to the Ethernet adapter so it can + // broadcast. That makes IsMachineConfigured() report true, so the DHCP + // check ALONE would skip the splash and the codes would never reach the + // screen — they'd only be in the log / on the COM2 plasma display. The + // Service writes configuring.json *before* assigning that temp IP, so its + // presence is the authoritative "SecureConfig in progress" signal. + if (!IsMachineConfigured() || File.Exists(ConfiguringFilePath())) { - ShowConfiguringWait(); // blocks until config detected or form closed + ShowConfiguringWait(); // blocks until config completes or form closed - // If still not configured (user closed the splash manually), exit. + // If still not configured (config failed / user closed splash), exit. if (!IsMachineConfigured()) return; } @@ -109,6 +115,12 @@ namespace Tesla.Launcher.Agent return false; // all Ethernet adapters are DHCP or absent → needs configuration } + /// Shared file the Service writes (before assigning the temp IP) while + /// SecureConfig is in progress; holds the RequestId/Passphrase for the splash. + private static string ConfiguringFilePath() => Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), + "TeslaLauncher", "configuring.json"); + private static bool IsVirtualAdapter(NetworkInterface nic) { var desc = nic.Description ?? ""; @@ -224,22 +236,24 @@ namespace Tesla.Launcher.Agent form.Controls.Add(lblHint); string lastJson = null; - bool codesLoaded = false; - var cfgFile = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), - "TeslaLauncher", "configuring.json"); + bool sawFile = false; + var cfgFile = ConfiguringFilePath(); // Poll every 2 s — read codes from the Service's shared file. // The file lifecycle: // 1. Service deletes stale file on startup - // 2. Service writes fresh file with new codes + // 2. Service writes fresh file with new codes (before the temp IP) // 3. Agent reads and displays codes // 4. Service deletes file when config is complete → splash closes + // If the Agent started before the file appeared, it keeps waiting; it + // closes once the file we saw is gone, or the machine becomes configured + // (covers the case where config finished before we managed to read it). var timer = new System.Windows.Forms.Timer { Interval = 2000 }; timer.Tick += (s, e) => { if (File.Exists(cfgFile)) { + sawFile = true; try { var json = File.ReadAllText(cfgFile); @@ -252,14 +266,14 @@ namespace Tesla.Launcher.Agent lblRequestId.Text = rid.GetString(); if (root.TryGetProperty("Passphrase", out var pp)) lblPassphrase.Text = pp.GetString(); - codesLoaded = true; } } catch { /* file may be mid-write, retry next tick */ } } - else if (codesLoaded) + else if (sawFile || IsMachineConfigured()) { - // Service deleted the file → configuration complete. + // File gone after we saw it, or the machine is now configured → + // SecureConfig is complete. timer.Stop(); form.Close(); }