using System; using System.Diagnostics; using System.IO; using System.Net.Http; using System.Text; using System.Threading.Tasks; namespace Sln.Wcs.UI.Services; public interface IEngineProcessService { bool IsRunning { get; } string StatusText { get; } string? LastError { get; } event Action? OutputReceived; event Action? StateChanged; Task StartAsync(); void Stop(); } public class EngineProcessService : IEngineProcessService { private Process? _process; private readonly HttpClient _http = new() { Timeout = TimeSpan.FromSeconds(3) }; private const string BaseUrl = "http://localhost:5100"; private readonly StringBuilder _outputBuffer = new(); public bool IsRunning { get; private set; } public string StatusText => IsRunning ? "运行中" : "已停止"; public string? LastError { get; private set; } public event Action? OutputReceived; public event Action? StateChanged; public async Task StartAsync() { if (IsRunning) return; LastError = null; _outputBuffer.Clear(); var dllPath = Path.Combine(AppContext.BaseDirectory, "Sln.Wcs.HoistServer.dll"); if (!File.Exists(dllPath)) throw new InvalidOperationException($"找不到 {dllPath}"); _process = new Process { StartInfo = new ProcessStartInfo { FileName = "dotnet", Arguments = $"\"{dllPath}\" --urls {BaseUrl}", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true, }, EnableRaisingEvents = true, }; _process.OutputDataReceived += (_, e) => { if (e.Data != null) { _outputBuffer.AppendLine(e.Data); OutputReceived?.Invoke(e.Data); } }; _process.ErrorDataReceived += (_, e) => { if (e.Data != null) { _outputBuffer.AppendLine(e.Data); OutputReceived?.Invoke(e.Data); } }; _process.Exited += (_, _) => { IsRunning = false; StateChanged?.Invoke(); _process?.Dispose(); _process = null; }; _process.Start(); _process.BeginOutputReadLine(); _process.BeginErrorReadLine(); // 等待健康检查,最多 20 秒 for (int i = 0; i < 40; i++) { await Task.Delay(500); if (_process.HasExited) { LastError = _outputBuffer.ToString(); _process.Dispose(); _process = null; throw new InvalidOperationException($"进程异常退出:\n{LastError}"); } if (await HealthCheckAsync()) { IsRunning = true; StateChanged?.Invoke(); return; } } LastError = _outputBuffer.ToString(); Stop(); throw new InvalidOperationException($"启动超时 (20s):\n{LastError}"); } public void Stop() { if (_process == null) return; IsRunning = false; try { if (!_process.HasExited) { _process.Kill(); _process.WaitForExit(3000); } _process.Dispose(); } catch { } finally { _process = null; } StateChanged?.Invoke(); } private async Task HealthCheckAsync() { try { var res = await _http.GetAsync($"{BaseUrl}/api/health"); return res.IsSuccessStatusCode; } catch { return false; } } }