using System; using System.Diagnostics; using System.IO; namespace CommonwealthOnline.Host.Services; // Launches the CommonwealthOnline.Server process, preferring a published // apphost, then a framework-dependent DLL, then a source-tree dotnet run. public sealed class ServerController { private Process? _process; public bool IsRunning => _process is { HasExited: false }; public event Action? LogReceived; public event Action? RunningChanged; public void Start(string serverDir, string configPath) { if (IsRunning) { return; } var startInfo = ResolveLaunch(serverDir, configPath); var process = new Process { StartInfo = startInfo, EnableRaisingEvents = true }; process.OutputDataReceived += (_, e) => Emit(e.Data); process.ErrorDataReceived += (_, e) => Emit(e.Data); process.Exited += (_, _) => RunningChanged?.Invoke(false); _process = process; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); RunningChanged?.Invoke(true); } public void Stop() { if (_process is { HasExited: false } process) { try { process.Kill(entireProcessTree: true); } catch (Exception) { // Process already gone or not killable; RunningChanged fires on Exited. } } } private void Emit(string? line) { if (!string.IsNullOrEmpty(line)) { LogReceived?.Invoke(line); } } private static ProcessStartInfo ResolveLaunch(string serverDir, string configPath) { var exeName = OperatingSystem.IsWindows() ? "CommonwealthOnline.Server.exe" : "CommonwealthOnline.Server"; var apphost = Path.Combine(serverDir, exeName); var dll = Path.Combine(serverDir, "CommonwealthOnline.Server.dll"); var project = Path.Combine(serverDir, "CommonwealthOnline.Server.csproj"); var info = new ProcessStartInfo { WorkingDirectory = serverDir, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true, }; if (File.Exists(apphost)) { info.FileName = apphost; info.ArgumentList.Add("serve"); } else if (File.Exists(dll)) { info.FileName = "dotnet"; info.ArgumentList.Add(dll); info.ArgumentList.Add("serve"); } else { info.FileName = "dotnet"; info.ArgumentList.Add("run"); info.ArgumentList.Add("--project"); info.ArgumentList.Add(project); info.ArgumentList.Add("-c"); info.ArgumentList.Add("Release"); info.ArgumentList.Add("--"); info.ArgumentList.Add("serve"); } info.ArgumentList.Add("--config"); info.ArgumentList.Add(configPath); return info; } }