feat: sync guard - Blockieren alter Clients beim sync

This commit is contained in:
2026-08-20 23:54:04 +02:00
parent 7b883555bf
commit 59bd8abb45
19 changed files with 369 additions and 26 deletions
+18 -5
View File
@@ -100,6 +100,12 @@ public class SyncEngine : IDisposable
$"{pulled} gepullt ({conflicts} Pull-Konflikte)");
return new() { Success = true, EventsPushed = pushed, EventsPulled = pulled, Conflicts = conflicts };
}
catch (SyncProtocolMismatchException ex)
{
_logger?.Error("Sync wegen inkompatibler Protokollversion abgebrochen", ex);
SetState(SyncState.IncompatibleVersion, ex.Message);
return new() { Reason = ex.Message };
}
catch (HttpRequestException ex)
{
// Sammelt sowohl echte Netzwerkfehler als auch nicht-erfolgreiche HTTP-Antworten
@@ -128,8 +134,10 @@ public class SyncEngine : IDisposable
evt.BasedOnServerSeq = _queue.GetKnownServerSeq(evt.EntityType, evt.EntityId);
_logger?.Info($"Sync: Push - {pending.Count} Ereignis(se) ausstehend: " +
string.Join(", ", pending.Select(e => $"{e.EntityType}/{e.Operation}")));
var resp = await _http.PostAsJsonAsync("/api/sync/push", pending);
resp.EnsureSuccessStatusCode();
using var request = SyncProtocol.CreateRequest(HttpMethod.Post, "/api/sync/push");
request.Content = JsonContent.Create(pending);
using var resp = await _http.SendAsync(request);
await SyncProtocol.EnsureCompatibleSuccessAsync(resp);
var result = await resp.Content.ReadFromJsonAsync<PushResponse>();
if (result is null) { _logger?.Warn("Sync: Push - leere Server-Antwort."); return (0, 0); }
_queue.Acknowledge(pending
@@ -196,7 +204,9 @@ public class SyncEngine : IDisposable
HttpResponseMessage resp;
try
{
resp = await _http.GetAsync($"/api/sync/entity/{local.EntityType}/{local.EntityId}");
using var request = SyncProtocol.CreateRequest(HttpMethod.Get,
$"/api/sync/entity/{local.EntityType}/{local.EntityId}");
resp = await _http.SendAsync(request);
}
catch (Exception ex)
{
@@ -217,7 +227,7 @@ public class SyncEngine : IDisposable
"nächster Push behandelt sie als neu.");
continue;
}
resp.EnsureSuccessStatusCode();
await SyncProtocol.EnsureCompatibleSuccessAsync(resp);
var remote = await resp.Content.ReadFromJsonAsync<SyncEvent>();
if (remote is null)
{
@@ -253,8 +263,11 @@ public class SyncEngine : IDisposable
{
var since = _queue.GetLastServerSeq();
_logger?.Info($"Sync: Pull - frage Server nach Ereignissen seit ServerSequenceNr={since}.");
var resp = await _http.GetFromJsonAsync<PullResponse>(
using var request = SyncProtocol.CreateRequest(HttpMethod.Get,
$"/api/sync/pull?since={since}&deviceId={_config.DeviceId}");
using var response = await _http.SendAsync(request);
await SyncProtocol.EnsureCompatibleSuccessAsync(response);
var resp = await response.Content.ReadFromJsonAsync<PullResponse>();
if (resp is null || resp.Events.Count == 0)
{
_logger?.Info("Sync: Pull - keine neuen Ereignisse vom Server.");