@@ -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
153165public class SimulationResult
0 commit comments