Files
ClawdDotNet/src/ClawdDotNet.Licensing/ILicenseStore.cs
T
RichardandClaude Opus 5 cb56175d20 Instanzmanager: Lizenz und Sub-Token wandern in den Manager (#528, E-M3)
Neues Projekt ClawdDotNet.Licensing. LicenseGate, LicenseWatch, LicenseInfo
und ILicensePrompt sind aus ClawdDotNet.App dorthin gezogen, weil zwei
Prozesse dieselbe Lizenzpruefung brauchen und keiner von beiden den anderen
kennen darf. In Core konnte es nicht landen - dann zoege jedes der sechzehn
Werkzeugprojekte das Deploymentcenter-SDK mit.

Dabei ist die Kopplung an SettingsManager verschwunden. LicenseGate kennt
jetzt nur ILicenseStore: Serveradresse lesen, Schluessel lesen und
schreiben, speichern. Die Anwendung fuehrt ihn in Settings.json, der
Manager in manager.json. Der Torwaechter prueft Schluessel; Dateien
verwaltet er nicht. Auch die Anwendungsversion kommt als Parameter statt
aus einem globalen Zugriff - diese Schicht weiss nicht, welche Anwendung
sie benutzt.

ManagerCore ist die Klammer: eigene Einstellungen, Lizenz, Register,
Meldeweg. Drei Regeln:

- Ohne gueltige Lizenz startet er keine Instanz. Laufende werden trotzdem
  in die Liste genommen - man soll sie sehen und anhalten koennen.
- Ein Widerruf haelt alle an. Der einzige Fall, in dem der Manager das von
  sich aus tut. Ein Serverausfall gehoert ausdruecklich nicht dazu; das SDK
  trennt Urteil und gescheiterten Versuch, und nur das Urteil kommt hier
  an. Sonst naehme ein Netzproblem saemtliche Installationen mit.
- Ohne hinterlegte Lizenzpruefung sperrt er nichts, sonst gaebe es eine
  Henne-Ei-Sperre, bevor jemand einen Schluessel eintragen kann.

Sub-Token je Instanz: Der Manager haelt das Master-Token und tauscht es
beim ANLEGEN einer Instanz gegen ein eigenes (watchdog:ping,
bugtracker:report, einzeln widerrufbar). Beim Anlegen und nicht beim ersten
Start, weil die Instanzdatei dann zweifelsfrei niemandem gehoert - sie
spaeter zu schreiben, waehrend der Instanzprozess laeuft, hiesse zwei
Schreiber auf einer Datei. Fuer Instanzen, die es vor dem Manager schon
gab, wird es vor dem Start nachgeholt. Danach fragt er ueber whoami nach,
ob das Token an ein Projekt gebunden ist (SDK 2.8.1). Ein
fehlgeschlagener Tokenbezug haelt die Instanz nicht auf.

NOCH NICHT VOLLSTAENDIG: Die Instanzen pruefen die Lizenz weiterhin selbst.
Das laesst sich erst abschalten, wenn eine Instanz feststellen kann, ob ein
Manager da ist - vorher entstuende eine Fassung ganz ohne Durchsetzung.

Und ein Testfehler, der zweimal derselbe war: Die Socket-Antwort war
hinterlegt, BEVOR der Manager hochfuhr. Damit sagt man "diese Instanz
laeuft bereits", der Manager uebernimmt sie, der Starter wird nie
angefasst - und der Test prueft etwas anderes, als er behauptet. Es gibt
jetzt eine Hilfsmethode, die das ausschliesst.

Build ohne Warnungen, 774 Tests gruen, 8 uebersprungen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 22:54:51 +02:00

32 lines
1.3 KiB
C#

namespace ClawdDotNet.Licensing;
/// <summary>
/// Wo der Lizenzschlüssel liegt — und wo die Adresse steht, gegen die geprüft wird.
///
/// <para><b>Eine Schnittstelle, weil es zwei Ablagen gibt</b> (#528, E-M3). Die Anwendung
/// führt den Schlüssel in <c>Settings.json</c>, der Instanzmanager in
/// <c>manager.json</c>. Der Torwächter selbst soll von beidem nichts wissen: Er prüft
/// Schlüssel, er verwaltet keine Dateien.</para>
///
/// <para>Nach E-M3 gehört die Lizenz auf Dauer dem Manager — eine Lizenz gilt der
/// Installation und erlaubt beliebig viele Instanzen. Bis eine Instanz feststellen kann,
/// ob ein Manager da ist, führen beide ihren eigenen Schlüssel; sonst entstünde
/// zwischendurch eine Fassung ganz ohne Durchsetzung.</para>
/// </summary>
public interface ILicenseStore
{
/// <summary>Die Adresse des Deploymentcenters. Leer heißt: Vorgabe aus <see cref="LicenseInfo"/>.</summary>
string ServerUrl { get; }
/// <summary>Der hinterlegte Schlüssel. Der Torwächter schreibt ihn zurück, wenn ein neuer eingegeben wurde.</summary>
string LicenseKey { get; set; }
/// <summary>
/// Schreibt den Schlüssel fest.
///
/// <para>Darf werfen — der Aufrufer behandelt das als „gilt, ließ sich aber nicht
/// sichern" und läuft weiter.</para>
/// </summary>
void Save();
}