Skip to content

Commit a6c6ee5

Browse files
authored
revert: back to single Start Simulation button (server starts/stops automatically) (#55)
- Remove Start/Stop/Run three-button approach - Single StartSimulation does everything in one shot - Server auto-starts before client run, auto-stops after - Keep all fixes: POST endpoint, .csx, PascalCase, i18n, error detection
1 parent 3116604 commit a6c6ee5

4 files changed

Lines changed: 75 additions & 99 deletions

File tree

src/Models/SimulateConfigModel.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,4 @@ public partial class SimulateConfigModel : ObservableObject
1717
[ObservableProperty] private string _productId = "2d974e2a-31e6-4887-9bb1-b4689e98c77a";
1818
[ObservableProperty] private string _outputDirectory = string.Empty;
1919
public int ServerPort { get; set; } = 5000;
20-
public bool ServerRunning { get; set; }
2120
}

src/Services/SimulationService.cs

Lines changed: 66 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -14,60 +14,51 @@ public class SimulationService
1414
{
1515
private readonly ClientGeneratorService _generator = new();
1616
private readonly LocalUpdateServer _server = new();
17+
private readonly StringBuilder _fullLog = new();
1718
private int _timeoutSeconds = 120;
1819

19-
public string ServerBaseUrl => _server.BaseUrl;
20-
21-
/// <summary>
22-
/// Generate scripts and start the local update server. Server stays running until StopServerAsync is called.
23-
/// </summary>
24-
public async Task StartServerAsync(SimulateConfigModel config, IProgress<string>? progress = null)
25-
{
26-
Log("STEP 1: Validating inputs", progress);
27-
Validate(config);
28-
29-
Log("STEP 2: Generating client.csx and upgrade.csx", progress);
30-
await _generator.GenerateAsync(config, config.OutputDirectory);
31-
Log($" client.csx → {config.OutputDirectory}", progress);
32-
Log($" upgrade.csx → {config.OutputDirectory}", progress);
33-
34-
Log("STEP 3: Starting local server", progress);
35-
var serverPatchDir = Path.Combine(config.OutputDirectory, ".server");
36-
Directory.CreateDirectory(serverPatchDir);
37-
var patchName = Path.GetFileName(config.PatchFilePath);
38-
var patchDest = Path.Combine(serverPatchDir, patchName);
39-
File.Copy(config.PatchFilePath, patchDest, true);
40-
41-
var hash = ComputeQuickHash(patchDest);
42-
LocalUpdateServerFiles.Register(patchName, patchDest);
43-
_server.Updates.Add((config.CurrentVersion, config.TargetVersion, hash, patchDest, config.AppType));
44-
45-
await _server.StartAsync(config.ServerPort);
46-
config.ServerPort = _server.Port;
47-
config.ServerRunning = true;
48-
Log($" Server running on {_server.BaseUrl}", progress);
49-
}
50-
51-
/// <summary>
52-
/// Stop the local update server.
53-
/// </summary>
54-
public async Task StopServerAsync()
55-
{
56-
await _server.DisposeAsync();
57-
LocalUpdateServerFiles.Clear();
58-
}
59-
60-
/// <summary>
61-
/// Run the client script and return results. Server must already be running.
62-
/// </summary>
63-
public async Task<SimulationResult> RunClientAsync(SimulateConfigModel config, IProgress<string>? progress = null, CancellationToken ct = default)
20+
public async Task<SimulationResult> RunAsync(
21+
SimulateConfigModel config,
22+
IProgress<string>? progress = null,
23+
CancellationToken ct = default)
6424
{
6525
var result = new SimulationResult();
6626
var sw = Stopwatch.StartNew();
6727

6828
try
6929
{
70-
Log("Running client (dotnet script client.csx)", progress);
30+
// 1. Validate
31+
Log("STEP 1: Validating inputs", progress);
32+
Validate(config);
33+
34+
// 2. Prepare output
35+
Log($"STEP 2: Preparing {config.OutputDirectory}", progress);
36+
Directory.CreateDirectory(config.OutputDirectory);
37+
38+
// 3. Generate scripts
39+
Log("STEP 3: Generating client.csx and upgrade.csx", progress);
40+
await _generator.GenerateAsync(config, config.OutputDirectory);
41+
Log($" client.csx → {config.OutputDirectory}", progress);
42+
Log($" upgrade.csx → {config.OutputDirectory}", progress);
43+
44+
// 4. Start server
45+
Log("STEP 4: Starting local server", progress);
46+
var serverPatchDir = Path.Combine(config.OutputDirectory, ".server");
47+
Directory.CreateDirectory(serverPatchDir);
48+
var patchName = Path.GetFileName(config.PatchFilePath);
49+
var patchDest = Path.Combine(serverPatchDir, patchName);
50+
File.Copy(config.PatchFilePath, patchDest, true);
51+
52+
var hash = ComputeQuickHash(patchDest);
53+
LocalUpdateServerFiles.Register(patchName, patchDest);
54+
_server.Updates.Add((config.CurrentVersion, config.TargetVersion, hash, patchDest, config.AppType));
55+
56+
await _server.StartAsync(config.ServerPort);
57+
Log($" Server running on {_server.BaseUrl}", progress);
58+
config.ServerPort = _server.Port;
59+
60+
// 5. Run client
61+
Log("STEP 5: Running client (dotnet script client.csx)", progress);
7162
var clientResult = await RunDotNetScript(config.OutputDirectory, "client.csx", ct);
7263
Log(clientResult.Output, progress);
7364

@@ -78,24 +69,30 @@ public async Task<SimulationResult> RunClientAsync(SimulateConfigModel config, I
7869
return result;
7970
}
8071

81-
Log("Client completed", progress);
82-
await Task.Delay(2000, ct);
72+
Log(" Client completed successfully", progress);
8373

84-
var fileCount = Directory.GetFiles(config.AppDirectory, "*", SearchOption.AllDirectories).Length;
85-
result.Notes.Add($"Files in app directory after update: {fileCount}");
74+
// 6. Verify
75+
Log("STEP 6: Verifying update result", progress);
76+
await Task.Delay(2000, ct);
77+
VerifyUpdateResult(config, result);
8678

8779
result.Success = true;
8880
result.Elapsed = sw.Elapsed;
89-
Log($"Simulation complete ({sw.Elapsed.TotalSeconds:F1}s)", progress);
81+
Log($"Simulation complete ({sw.Elapsed.TotalSeconds:F1}s)", progress);
9082
}
9183
catch (Exception ex)
9284
{
9385
result.Success = false;
9486
result.ErrorMessage = ex.Message;
95-
Log($"Simulation failed: {ex.Message}", progress);
87+
Log($"❌ Simulation failed: {ex.Message}", progress);
88+
}
89+
finally
90+
{
91+
try { await _server.DisposeAsync(); } catch { }
92+
LocalUpdateServerFiles.Clear();
93+
result.FullLog = _fullLog.ToString();
9694
}
9795

98-
result.FullLog = "";
9996
return result;
10097
}
10198

@@ -140,14 +137,29 @@ private void Validate(SimulateConfigModel config)
140137
return (!hasError && p.ExitCode == 0, outputStr);
141138
}
142139

140+
private void VerifyUpdateResult(SimulateConfigModel config, SimulationResult result)
141+
{
142+
var deleteFile = Path.Combine(config.AppDirectory, "delete_files.json");
143+
if (File.Exists(deleteFile))
144+
result.Notes.Add("delete_files.json still present - HandleDeleteList may not have run");
145+
146+
var fileCount = Directory.GetFiles(config.AppDirectory, "*", SearchOption.AllDirectories).Length;
147+
result.Notes.Add($"Files in app directory after update: {fileCount}");
148+
}
149+
143150
private static string ComputeQuickHash(string filePath)
144151
{
145152
using var sha = System.Security.Cryptography.SHA256.Create();
146153
using var fs = File.OpenRead(filePath);
147154
return BitConverter.ToString(sha.ComputeHash(fs)).Replace("-", "").ToLowerInvariant();
148155
}
149156

150-
private static void Log(string msg, IProgress<string>? progress) => progress?.Report($"[{DateTime.Now:HH:mm:ss}] {msg}");
157+
private void Log(string msg, IProgress<string>? progress)
158+
{
159+
var line = $"[{DateTime.Now:HH:mm:ss}] {msg}";
160+
_fullLog.AppendLine(line);
161+
progress?.Report(line);
162+
}
151163
}
152164

153165
public class SimulationResult

src/ViewModels/SimulateViewModel.cs

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public int AppTypeIndex
8484
[RelayCommand] async Task SelectOutputDir() { var p = await PickFolder(_loc["Sim.SelectOutput"]); if (p != null) Config.OutputDirectory = p; }
8585

8686
[RelayCommand]
87-
async Task StartServer()
87+
async Task StartSimulation()
8888
{
8989
if (string.IsNullOrWhiteSpace(Config.AppDirectory)) { Status = _loc["Sim.ValidateDirs"]; return; }
9090
if (string.IsNullOrWhiteSpace(Config.PatchFilePath)) { Status = _loc["Sim.ValidateDirs"]; return; }
@@ -93,34 +93,13 @@ async Task StartServer()
9393
IsRunning = true; Log.Clear(); Status = _loc["Sim.Starting"];
9494
try
9595
{
96-
await _sim.StartServerAsync(Config, new Progress<string>(L));
97-
Status = $"Server: {_sim.ServerBaseUrl}";
98-
L($"Server running on {_sim.ServerBaseUrl}");
99-
L($"Manual: dotnet script client.csx");
100-
}
101-
catch (Exception ex) { Status = $"Error: {ex.Message}"; L($"FATAL: {ex}"); }
102-
finally { IsRunning = false; }
103-
}
104-
105-
[RelayCommand]
106-
async Task StopServer()
107-
{
108-
await _sim.StopServerAsync();
109-
Status = _loc["Patch.Ready"];
110-
L("Server stopped");
111-
}
112-
113-
[RelayCommand]
114-
async Task RunClient()
115-
{
116-
if (!Config.ServerRunning) { Status = "Server not running"; return; }
117-
IsRunning = true; Status = "Running client...";
118-
try
119-
{
120-
var result = await _sim.RunClientAsync(Config, new Progress<string>(L));
96+
var progress = new Progress<string>(L);
97+
var result = await _sim.RunAsync(Config, progress);
12198
if (result.Success)
12299
{
123100
Status = _loc.T("Sim.Completed", result.Elapsed.TotalSeconds);
101+
L($"Result: {(result.Success ? "PASS" : "FAIL")}");
102+
foreach (var note in result.Notes) L($" Note: {note}");
124103
var reportPath = await _report.GenerateAsync(Config, result, Config.OutputDirectory);
125104
L(_loc.T("Sim.Report", reportPath));
126105
}

src/Views/SimulateView.axaml

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -81,24 +81,10 @@
8181
</StackPanel>
8282
</Border>
8383

84-
<!-- Server Controls -->
85-
<Grid ColumnDefinitions="*,*,Auto" Margin="0,4,0,0">
86-
<Button Grid.Column="0" Content="🚀 Start Server"
87-
Command="{Binding StartServerCommand}"
88-
IsEnabled="{Binding !Config.ServerRunning}"
89-
Height="40" FontSize="14"
90-
Margin="0,0,4,0"/>
91-
<Button Grid.Column="1" Content="⏹ Stop Server"
92-
Command="{Binding StopServerCommand}"
93-
IsEnabled="{Binding Config.ServerRunning}"
94-
Height="40" FontSize="14"
95-
Margin="4,0"/>
96-
<Button Grid.Column="2" Content="▶ Run Client"
97-
Command="{Binding RunClientCommand}"
98-
IsEnabled="{Binding Config.ServerRunning}"
99-
Height="40" FontSize="14" MinWidth="110"
100-
Margin="4,0,0,0"/>
101-
</Grid>
84+
<!-- Run -->
85+
<Button Content="{Binding Source={x:Static svc:LocalizationService.Instance}, Path=[Sim.Start]}"
86+
Command="{Binding StartSimulationCommand}"
87+
IsEnabled="{Binding !IsRunning}" Height="40" FontSize="14" HorizontalAlignment="Stretch"/>
10288
<TextBlock Text="{Binding Status}" FontSize="13"/>
10389

10490
<!-- Log -->

0 commit comments

Comments
 (0)