Files
Predictalytics/src/Predictalytics.WinFormsHost/AppSettings.cs
T
RichardandClaude Fable 5 725746d204 Watchdog-Integration gegen Produktivserver verifiziert und korrigiert
- Shutdown-Event sendet stopped_graceful statt stopping: der Server
  kennt "stopping" im Router, aber event_log.kind ist ein ENUM ohne
  diesen Wert. Folge war HTTP 500 nach dem Zustandswechsel, das Event
  fehlte in der Historie.
- Default-Source auf "Predictalytics" korrigiert (Schreibweise des
  bereits angelegten Monitors auf dem Server).

Heartbeat, Metrics-Payload, Lizenzvalidierung und der Startpfad ueber
den Cache sind end-to-end gegen die Produktivserver getestet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 17:42:02 +02:00

138 lines
5.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.ComponentModel;
using System.Text.Json;
namespace Predictalytics.WinFormsHost;
public class AppSettings
{
private const string FileName = "settings.json";
[Category("Webserver")]
[DisplayName("Port")]
[Description("Der Port, über den die WebUI und API erreichbar sind.")]
[DefaultValue(5000)]
public int WebserverPort { get; set; } = 5000;
[Category("Webserver")]
[DisplayName("Database Debug")]
[Description("Wenn aktiv, werden detaillierte Verbindungsinformationen im Terminal angezeigt.")]
[DefaultValue(false)]
public bool DbConnectionDebug { get; set; } = false;
private string _egressChannelsText = "";
[Category("Egress (Proxy/IP)")]
[DisplayName("Egress Channels")]
[Description("Liste der Egress-Kanäle im Format: id|type|value (Zeilengetrennt). Beispiel: prox-1|Proxy|http://user:pass@proxy:8080\nip-1|SourceIp|192.168.1.100")]
[Editor("System.ComponentModel.Design.MultilineStringEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(System.Drawing.Design.UITypeEditor))]
public string EgressChannelsText { get => _egressChannelsText; set => _egressChannelsText = value ?? ""; }
[Category("Watchdog")]
[DisplayName("Enabled")]
[Description("Sendet periodische Heartbeats an den externen Watchdog-Server (Dead-Man's-Switch). Benötigt einen API Key.")]
[DefaultValue(true)]
public bool WatchdogEnabled { get; set; } = true;
[Category("Watchdog")]
[DisplayName("Server URL")]
[Description("Basis-URL des Watchdog-Servers.")]
[DefaultValue("https://watchdog.mhdf.de")]
public string WatchdogUrl { get; set; } = "https://watchdog.mhdf.de";
[Category("Watchdog")]
[DisplayName("API Key")]
[Description("Shared Key oder Agent-Token des Watchdog-Servers (X-Watchdog-Key). Ohne Key werden keine Heartbeats gesendet.")]
[PasswordPropertyText(true)]
public string WatchdogApiKey { get; set; } = "";
[Category("Watchdog")]
[DisplayName("Source")]
[Description("Eindeutiger Monitor-Name dieses Dienstes im Watchdog-Dashboard.")]
[DefaultValue("Predictalytics")]
public string WatchdogSource { get; set; } = "Predictalytics";
[Category("Watchdog")]
[DisplayName("Instance")]
[Description("Instanz-Kennung, falls mehrere Predictalytics-Instanzen laufen.")]
[DefaultValue("default")]
public string WatchdogInstance { get; set; } = "default";
[Category("Watchdog")]
[DisplayName("Interval (Sekunden)")]
[Description("Sende-Takt der Heartbeats. Der Watchdog alarmiert, wenn ~1,5× dieses Intervall + 30 s ohne Heartbeat vergehen.")]
[DefaultValue(60)]
public int WatchdogIntervalSeconds { get; set; } = 60;
private string _dbServer = "localhost";
private string _dbName = "";
private string _dbUser = "";
private string _dbPassword = "";
[Category("Database")]
[DisplayName("Server")]
public string DbServer { get => _dbServer; set => _dbServer = string.IsNullOrWhiteSpace(value) ? _dbServer : value.Trim(); }
[Category("Database")]
[DisplayName("Database")]
public string DbName { get => _dbName; set => _dbName = string.IsNullOrWhiteSpace(value) ? _dbName : value.Trim(); }
[Category("Database")]
[DisplayName("User")]
public string DbUser { get => _dbUser; set => _dbUser = string.IsNullOrWhiteSpace(value) ? _dbUser : value.Trim(); }
[Category("Database")]
[DisplayName("Password")]
[PasswordPropertyText(true)]
public string DbPassword { get => _dbPassword; set => _dbPassword = string.IsNullOrWhiteSpace(value) ? _dbPassword : value.Trim(); }
[Browsable(false)]
public string ConnectionString
{
get
{
var builder = new MySqlConnector.MySqlConnectionStringBuilder
{
Server = DbServer?.Trim(),
Database = DbName?.Trim(),
UserID = DbUser?.Trim(),
Password = DbPassword?.Trim(),
AllowPublicKeyRetrieval = true,
SslMode = MySqlConnector.MySqlSslMode.None,
Pooling = true,
MinimumPoolSize = 0,
MaximumPoolSize = 100
};
return builder.ConnectionString;
}
}
public static AppSettings Load()
{
var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FileName);
if (!File.Exists(filePath))
{
var settings = new AppSettings();
settings.Save();
return settings;
}
try
{
var json = File.ReadAllText(filePath);
return JsonSerializer.Deserialize<AppSettings>(json) ?? new AppSettings();
}
catch
{
return new AppSettings();
}
}
public void Save()
{
var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FileName);
var options = new JsonSerializerOptions { WriteIndented = true };
var json = JsonSerializer.Serialize(this, options);
File.WriteAllText(filePath, json);
}
}