using System.Text.Json; using Nonemm.Core; namespace Nonemm.App.Configuration; /// What the program remembers between runs. public sealed record Settings { public string DatabasePath { get; init; } = ""; public int ContestNumber { get; init; } public StoredStation Station { get; init; } = new(); public string ClusterHost { get; init; } = ""; public int ClusterPort { get; init; } = 7373; public IReadOnlyList ClusterCommands { get; init; } = []; public string RigctldHost { get; init; } = "127.0.0.1"; public int RigctldPort { get; init; } = 4532; public bool RadioEnabled { get; init; } public bool ClusterEnabled { get; init; } public string NetworkStationName { get; init; } = ""; public int NetworkPort { get; init; } = 12060; public bool NetworkEnabled { get; init; } public IReadOnlyList NetworkPeers { get; init; } = []; /// `none`, `cwdaemon` or `winkeyer`. public string KeyerKind { get; init; } = "none"; public string KeyerHost { get; init; } = "127.0.0.1"; public int KeyerPort { get; init; } = 6789; public string KeyerSerialPort { get; init; } = ""; public int KeyerSpeed { get; init; } = 28; /// The twelve function key messages, keyed F1 to F12. public IReadOnlyList CwMessages { get; init; } = []; public IReadOnlyList PhoneMessages { get; init; } = []; /// Reflection rather than a generated serializer: the generated one hands /// back null for every property the file leaves out instead of the value /// the property is declared with. private static readonly JsonSerializerOptions Json = new() { WriteIndented = true }; public static Settings Load(string path) { if (!File.Exists(path)) { return new Settings(); } try { return JsonSerializer.Deserialize(File.ReadAllText(path), Json) ?? new Settings(); } catch (JsonException) { // a settings file that will not parse is replaced rather than // stopping the program before a contest return new Settings(); } } public void Save(string path) => File.WriteAllText(path, JsonSerializer.Serialize(this, Json)); } /// The operator's station as it is stored, kept separate from `StationInfo` so /// the file format does not follow every change to the domain type. public sealed record StoredStation { public string Callsign { get; init; } = ""; public int CqZone { get; init; } public int ItuZone { get; init; } public string Continent { get; init; } = ""; public string CountryPrefix { get; init; } = ""; public string State { get; init; } = ""; public string Province { get; init; } = ""; public string ArrlSection { get; init; } = ""; public string GridSquare { get; init; } = ""; public string County { get; init; } = ""; public string Name { get; init; } = ""; public string Power { get; init; } = ""; public string Club { get; init; } = ""; public int Check { get; init; } public string Precedence { get; init; } = "A"; public StationInfo ToStationInfo() => new() { Callsign = Callsign, CqZone = CqZone, ItuZone = ItuZone, Continent = Continent, CountryPrefix = CountryPrefix, State = State, Province = Province, ArrlSection = ArrlSection, GridSquare = GridSquare, County = County, Name = Name, Power = Power, Club = Club, Check = Check, Precedence = Precedence, }; }