Die zentrale, bisher komplett fehlende Luecke: selbst mit Baustein 1-4 haette SyncEngine.PullAsync empfangene Ereignisse nur zur Konflikterkennung genutzt, nie in die lokale LiteDB geschrieben - ankommende Aenderungen von anderen Geraeten waeren nirgends sichtbar geworden. Neu EventApplier: entschluesselt, dispatcht ueber eine explizite EntityType-Tabelle, schreibt IMMER direkt auf die rohe LiteDB- Collection, nie ueber eine Repository-Save/Delete-Methode - sonst wuerde der OnChange-Hook (Baustein 2) die gerade angewendete Aenderung als neues ausgehendes Ereignis re-enqueuen (Sync-Ping-Pong). Ein gemeinsames Suppress-Flag wurde geprueft und verworfen: SyncEngine laeuft per Timer nebenlaeufig zum UI-Thread, ein Flag koennte einen echten Nutzer-Save waehrenddessen verschlucken. Der direkte Collection- Zugriff ist zustandslos und dadurch korrekt. Kaskaden-Faelle nutzen dieselben internen LiteDbContext-Hilfsmethoden wie die Repositories (Baustein 4). Neu SyncEventPublisher, der den OnChange-Hook in ein verschluesseltes EventQueue.Enqueue uebersetzt (an LiteDbContext.OnChange gehaengt). Mit dediziertem Loop-Prevention-Test abgesichert: belegt mit echtem LiteDbContext + OnChange-Zaehler, dass Apply keinen neuen Hook-Aufruf ausloest. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
20 lines
817 B
C#
20 lines
817 B
C#
using LehrerApp.Data;
|
|
using LehrerApp.Sync.Crypto;
|
|
using LehrerApp.Sync.Models;
|
|
|
|
namespace LehrerApp.Sync;
|
|
|
|
/// <summary>
|
|
/// Wandelt <see cref="LiteDbContext.OnChange"/>-Aufrufe in ausgehende Sync-Ereignisse um. Wird in
|
|
/// AppBootstrapper an <see cref="LiteDbContext.OnChange"/> gehängt, wenn Sync konfiguriert ist —
|
|
/// dort entsteht aus den ~27 Repository-Aufrufen genau ein verschlüsseltes Ereignis pro Aufruf.
|
|
/// </summary>
|
|
public class SyncEventPublisher(EventQueue queue, string deviceId, byte[] syncKey)
|
|
{
|
|
public void Publish(string entityType, string entityId, string operation, object? payload)
|
|
{
|
|
var encrypted = payload is null ? "" : SyncCrypto.EncryptObject(payload, syncKey);
|
|
queue.Enqueue(deviceId, DeviceType.Desktop, entityType, entityId, operation, encrypted);
|
|
}
|
|
}
|