94 lines
3.6 KiB
C#
94 lines
3.6 KiB
C#
namespace ClawdDotNet.App.Services;
|
|
|
|
/// <summary>
|
|
/// Wie der <see cref="LicenseGate"/> mit dem Benutzer spricht.
|
|
///
|
|
/// Vorher rief er unmittelbar <c>MessageBox.Show</c> 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:
|
|
/// <list type="bullet">
|
|
/// <item><c>AvaloniaLicensePrompt</c> — Dialoge im Fenster (Desktop).</item>
|
|
/// <item><see cref="ConsoleLicensePrompt"/> — Eingabe über die Konsole (Kommandozeile).</item>
|
|
/// <item><see cref="NonInteractiveLicensePrompt"/> — antwortet nie (systemd-Dienst).</item>
|
|
/// </list>
|
|
/// </summary>
|
|
public interface ILicensePrompt
|
|
{
|
|
/// <summary>
|
|
/// Fragt einen Lizenzschlüssel ab. <c>null</c> heißt Abbruch — der Aufrufer beendet
|
|
/// die Anwendung.
|
|
/// </summary>
|
|
/// <param name="hardwareId">Wird angezeigt, damit der Nutzer ihn an den Support geben kann.</param>
|
|
/// <param name="problem">Warum der bisherige Schlüssel nicht taugt; <c>null</c> beim ersten Fragen.</param>
|
|
/// <param name="currentKey">Vorbelegung des Eingabefelds.</param>
|
|
Task<string?> RequestKeyAsync(string hardwareId, string? problem, string? currentKey);
|
|
|
|
/// <summary>Eine Meldung, die keine Antwort braucht (etwa „offline gültig bis …").</summary>
|
|
Task ShowInfoAsync(string title, string message);
|
|
|
|
/// <summary>Ein Fehler, nach dem die Anwendung nicht weiterläuft.</summary>
|
|
Task ShowErrorAsync(string title, string message);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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 (<c>--license-set-key</c>).
|
|
/// </summary>
|
|
public sealed class NonInteractiveLicensePrompt(Action<string> log) : ILicensePrompt
|
|
{
|
|
public Task<string?> 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 <SCHLÜSSEL>' hinterlegen.");
|
|
|
|
return Task.FromResult<string?>(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;
|
|
}
|
|
}
|
|
|
|
/// <summary>Eingabe über die Konsole — für Kommandozeilenaufrufe.</summary>
|
|
public sealed class ConsoleLicensePrompt : ILicensePrompt
|
|
{
|
|
public Task<string?> 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;
|
|
}
|
|
}
|