using System.Net.Http.Json; using CareFix.Core; namespace CareFix.Agent; public static class Setup { public static void Configure() { Console.WriteLine("CareFix Agent setup. Settings are saved to " + AgentConfig.FilePath); Console.WriteLine("Passwords and the agent key are encrypted for this computer only.\n"); AgentConfig existing; try { existing = File.Exists(AgentConfig.FilePath) ? System.Text.Json.JsonSerializer.Deserialize(File.ReadAllText(AgentConfig.FilePath)) ?? new() : new(); } catch { existing = new(); } var c = new AgentConfig { ServerUrl = Ask("CareFix server URL (https://...)", existing.ServerUrl), HospitalCode = Ask("Hospital code (as shown in CareFix)", existing.HospitalCode), SqlServer = Ask("SQL Server name or IP", existing.SqlServer), SqlPort = int.Parse(Ask("SQL Server port", existing.SqlPort.ToString())), Database = Ask("HIS database name", existing.Database), ReadUser = Ask("Read-only login", existing.ReadUser), WriteUser = Ask("Write login", existing.WriteUser), Encrypt = AskBool("Encrypt SQL connection", existing.Encrypt), TrustServerCertificate = AskBool("Trust the SQL Server certificate (usual for local servers)", existing.TrustServerCertificate), MaxRowsPerSelect = existing.MaxRowsPerSelect, SelectTimeoutSeconds = existing.SelectTimeoutSeconds, LockTimeoutMs = existing.LockTimeoutMs, MaxParallelJobs = existing.MaxParallelJobs, AllowInsecureHttp = existing.AllowInsecureHttp, }; c.AgentKeyProtected = Secret("Agent key (from CareFix > Hospitals)", existing.AgentKeyProtected); c.ReadPasswordProtected = Secret("Read-only login password", existing.ReadPasswordProtected); c.WritePasswordProtected = Secret("Write login password", existing.WritePasswordProtected); c.Save(); Console.WriteLine("\nSaved. Run 'CareFix.Agent.exe test' to check the setup, then start the \"CareFix Agent\" service."); } public static async Task TestAsync(AgentConfig cfg) { var failed = false; try { var ops = new SqlOps( SqlOps.BuildConnectionString(cfg.SqlServer, cfg.SqlPort, cfg.Database, cfg.ReadUser, cfg.ReadPassword, cfg.Encrypt, cfg.TrustServerCertificate, "CareFix-Agent-Test"), SqlOps.BuildConnectionString(cfg.SqlServer, cfg.SqlPort, cfg.Database, cfg.WriteUser, cfg.WritePassword, cfg.Encrypt, cfg.TrustServerCertificate, "CareFix-Agent-Test"), new SqlLimits(cfg.MaxRowsPerSelect, cfg.SelectTimeoutSeconds, cfg.LockTimeoutMs)); var r = await ops.TestAsync(CancellationToken.None); Console.WriteLine($"SQL: connected to {r["database"]} (SQL Server {r["sqlServerVersion"]})."); if (r["ready"] is true) Console.WriteLine("SQL: CareFix procedures found."); else { Console.WriteLine("SQL: CareFix procedures missing. Run sql/02_hospital_setup.sql on this database."); failed = true; } } catch (Exception ex) { Console.WriteLine("SQL: FAILED. " + ex.Message); failed = true; } try { using var client = new HttpClient { BaseAddress = new Uri(cfg.ServerUrl.TrimEnd('/') + "/"), Timeout = TimeSpan.FromSeconds(40) }; client.DefaultRequestHeaders.Add(AgentProtocol.HospitalHeader, cfg.HospitalCode); client.DefaultRequestHeaders.Add(AgentProtocol.KeyHeader, cfg.AgentKey); using var resp = await client.PostAsJsonAsync("api/agent/poll", new AgentPoll("test", Environment.MachineName), AgentProtocol.Json); if (resp.IsSuccessStatusCode) Console.WriteLine("Server: agent key accepted."); else { Console.WriteLine($"Server: FAILED ({(int)resp.StatusCode}). Check the URL, hospital code, that the hospital's channel is 'On-prem agent', and the key."); failed = true; } } catch (Exception ex) { Console.WriteLine("Server: FAILED. " + ex.Message); failed = true; } return failed ? 1 : 0; } private static string Ask(string label, string current) { Console.Write(string.IsNullOrEmpty(current) ? $"{label}: " : $"{label} [{current}]: "); var v = Console.ReadLine()?.Trim(); return string.IsNullOrEmpty(v) ? current : v; } private static bool AskBool(string label, bool current) { var v = Ask($"{label} (y/n)", current ? "y" : "n"); return v.StartsWith("y", StringComparison.OrdinalIgnoreCase); } private static string Secret(string label, string currentProtected) { Console.Write(string.IsNullOrEmpty(currentProtected) ? $"{label}: " : $"{label} [keep current]: "); var sb = new System.Text.StringBuilder(); while (true) { var k = Console.ReadKey(intercept: true); if (k.Key == ConsoleKey.Enter) break; if (k.Key == ConsoleKey.Backspace) { if (sb.Length > 0) sb.Length--; continue; } sb.Append(k.KeyChar); } Console.WriteLine(); if (sb.Length == 0) { if (string.IsNullOrEmpty(currentProtected)) throw new InvalidOperationException($"{label} is required."); return currentProtected; } return AgentConfig.Protect(sb.ToString()); } }