Baustein 6: Datei-Anhaenge synchronisieren (Kapitel 10)
Anhaenge laufen bewusst NICHT ueber den JSON-Ereigniskanal (wuerde ihn
fuer Fotos/Scans stark aufblaehen), sondern ueber einen eigenen
verschluesselten Binaerkanal - analog zum bereits bestehenden Muster
in SnapshotService.
- Neue Endpunkte POST/GET /api/sync/attachments/{storageId} in
LehrerApp.Api (AttachmentStore, dateibasiert je Nutzer)
- EventQueue: neue, vom JSON-Ereignis getrennte Warteliste fuer
ausstehende Uploads (SyncEventPublisher traegt Anhaenge einer
gespeicherten Documentation dort ein)
- AttachmentSyncer laedt ausstehende Anhaenge hoch (in
SyncEngine.SyncNowAsync nach dem Event-Push)
- EventApplier laedt fehlende Anhaenge nach dem Anwenden eines
Documentation-Ereignisses nach - ueber die rohe Collection statt
IAttachmentStorage.Upload, da dieses immer eine neue Id vergaebe und
hier die Original-StorageId erhalten bleiben muss
Round-Trip-Tests belegen byteidentische Uebertragung.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
using LehrerApp.Data;
|
||||
using LehrerApp.Sync.Crypto;
|
||||
|
||||
namespace LehrerApp.Sync;
|
||||
|
||||
/// <summary>
|
||||
/// Lädt ausstehende Datei-Anhänge (siehe <see cref="EventQueue.GetPendingAttachmentUploads"/>)
|
||||
/// als eigenen, verschlüsselten Binärtransfer hoch — getrennt vom JSON-Ereigniskanal, damit
|
||||
/// Fotos/Scans ihn nicht aufblähen. Gegenstück zum Download in <see cref="EventApplier"/>.
|
||||
/// </summary>
|
||||
public class AttachmentSyncer(LiteDbContext db, HttpClient http, byte[] syncKey)
|
||||
{
|
||||
public async Task UploadPendingAsync(EventQueue queue)
|
||||
{
|
||||
foreach (var storageId in queue.GetPendingAttachmentUploads())
|
||||
{
|
||||
if (!db.Attachments.Exists(storageId))
|
||||
{
|
||||
// Lokal inzwischen wieder gelöscht (z.B. HardDelete vor dem eigentlichen Upload) -
|
||||
// nichts hochzuladen, Warteliste trotzdem bereinigen.
|
||||
queue.MarkAttachmentUploaded(storageId);
|
||||
continue;
|
||||
}
|
||||
|
||||
using var raw = db.Attachments.OpenRead(storageId);
|
||||
using var buffer = new MemoryStream();
|
||||
await raw.CopyToAsync(buffer);
|
||||
var encrypted = SyncCrypto.Encrypt(buffer.ToArray(), syncKey);
|
||||
|
||||
using var content = new ByteArrayContent(encrypted);
|
||||
var resp = await http.PostAsync($"/api/sync/attachments/{storageId}", content);
|
||||
resp.EnsureSuccessStatusCode();
|
||||
queue.MarkAttachmentUploaded(storageId);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user