namespace ClawdDotNet.App.Services; /// /// Wie der mit dem Benutzer spricht. /// /// Vorher rief er unmittelbar MessageBox.Show und einen WinForms-Dialog. /// Das band die Lizenzprüfung an WinForms — und wäre im kopflosen Betrieb fatal /// gewesen: Ein Dienst, der beim Start ein Fenster öffnet und auf eine Eingabe wartet, /// hängt für immer, ohne dass jemand die Meldung je zu sehen bekäme. /// /// Es gibt drei Umsetzungen: /// /// AvaloniaLicensePrompt — Dialoge im Fenster (Desktop). /// — Eingabe über die Konsole (Kommandozeile). /// — antwortet nie (systemd-Dienst). /// /// public interface ILicensePrompt { /// /// Fragt einen Lizenzschlüssel ab. null heißt Abbruch — der Aufrufer beendet /// die Anwendung. /// /// Wird angezeigt, damit der Nutzer ihn an den Support geben kann. /// Warum der bisherige Schlüssel nicht taugt; null beim ersten Fragen. /// Vorbelegung des Eingabefelds. Task RequestKeyAsync(string hardwareId, string? problem, string? currentKey); /// Eine Meldung, die keine Antwort braucht (etwa „offline gültig bis …"). Task ShowInfoAsync(string title, string message); /// Ein Fehler, nach dem die Anwendung nicht weiterläuft. Task ShowErrorAsync(string title, string message); } /// /// Für den kopflosen Betrieb: fragt nicht, sondern lehnt ab. /// /// Ein Dienst ohne Sitzung kann keinen Schlüssel entgegennehmen. Statt zu blockieren /// meldet er, was zu tun ist — der Schlüssel wird vorab über die Kommandozeile /// hinterlegt (--license-set-key). /// public sealed class NonInteractiveLicensePrompt(Action log) : ILicensePrompt { public Task RequestKeyAsync(string hardwareId, string? problem, string? currentKey) { log($"Lizenz erforderlich, aber kein Eingabeweg vorhanden. Hardware-ID: {hardwareId}. " + (problem is null ? "" : $"Grund: {problem}. ") + "Schlüssel mit '--license-set-key ' hinterlegen."); return Task.FromResult(null); } public Task ShowInfoAsync(string title, string message) { log($"{title}: {message}"); return Task.CompletedTask; } public Task ShowErrorAsync(string title, string message) { log($"{title}: {message}"); return Task.CompletedTask; } } /// Eingabe über die Konsole — für Kommandozeilenaufrufe. public sealed class ConsoleLicensePrompt : ILicensePrompt { public Task RequestKeyAsync(string hardwareId, string? problem, string? currentKey) { if (problem is not null) Console.Error.WriteLine($"Lizenz: {problem}"); Console.WriteLine($"Hardware-ID: {hardwareId}"); Console.Write("Lizenzschlüssel: "); var input = Console.ReadLine()?.Trim(); return Task.FromResult(string.IsNullOrWhiteSpace(input) ? null : input); } public Task ShowInfoAsync(string title, string message) { Console.WriteLine($"{title}: {message}"); return Task.CompletedTask; } public Task ShowErrorAsync(string title, string message) { Console.Error.WriteLine($"{title}: {message}"); return Task.CompletedTask; } }