62 lines
2.9 KiB
C#
62 lines
2.9 KiB
C#
using LehrerApp.Core.Models;
|
|
using LehrerApp.Core.Services;
|
|
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, AppLogger? logger = null)
|
|
{
|
|
private const string CompetencyCatalogBackfillId = "competency-catalog-v1";
|
|
|
|
public void Publish(string entityType, string entityId, string operation, object? payload)
|
|
{
|
|
var encrypted = payload is null ? "" : SyncCrypto.EncryptObject(payload, syncKey);
|
|
var evt = queue.Enqueue(deviceId, DeviceType.Desktop, entityType, entityId, operation, encrypted);
|
|
// Erfolgs-Protokollierung (nicht nur Fehler, siehe SyncEngine/EventApplier) — sonst lässt
|
|
// sich ohne zwei parallele Testgeräte nie nachvollziehen, ob eine lokale Änderung
|
|
// überhaupt in die Outbox gelangt ist, bevor Push/Pull überhaupt ins Spiel kommen.
|
|
logger?.Info($"Sync: Ereignis eingereiht (SequenceNr={evt.SequenceNr}) - {entityType} {operation} " +
|
|
$"EntityId={entityId}");
|
|
|
|
// Anhänge reisen nicht im JSON-Ereignis mit (würde den Kanal für Fotos/Scans aufblähen),
|
|
// sondern als eigener Binärtransfer über AttachmentSyncer — hier nur zur Warteliste hinzufügen.
|
|
if (payload is IHasAttachments withAttachments)
|
|
foreach (var attachment in withAttachments.Attachments)
|
|
queue.QueueAttachmentUpload(attachment.StorageId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Veröffentlicht bestehende Kompetenzkataloge einmalig als vollständige Snapshots. Das
|
|
/// repariert Daten, die vor aktivierter Synchronisation oder während einer Migration direkt
|
|
/// in LiteDB geschrieben wurden und deshalb nie den Repository-OnChange-Hook durchlaufen
|
|
/// haben. Der Marker liegt gerätespezifisch in dessen lokaler EventQueue.
|
|
/// </summary>
|
|
public int BackfillCompetencyCatalog(LiteDbContext db)
|
|
{
|
|
if (queue.IsMaintenanceCompleted(CompetencyCatalogBackfillId)) return 0;
|
|
|
|
var count = 0;
|
|
foreach (var version in db.CompetencyCatalogVersions.FindAll())
|
|
{
|
|
Publish(nameof(CompetencyCatalogVersion), version.Id.ToString(), "Save", version);
|
|
count++;
|
|
}
|
|
foreach (var domain in db.CompetencyDomains.FindAll())
|
|
{
|
|
Publish(nameof(CompetencyDomain), domain.Id.ToString(), "Save", domain);
|
|
count++;
|
|
}
|
|
|
|
queue.MarkMaintenanceCompleted(CompetencyCatalogBackfillId);
|
|
logger?.Info($"Sync: einmaliger Kompetenzkatalog-Backfill abgeschlossen ({count} Ereignis(se)).");
|
|
return count;
|
|
}
|
|
}
|