PalacePal/Pal.Client/Scheduled/QueuedSyncResponse.cs

161 lines
6.2 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Linq;
2023-02-18 20:12:36 +00:00
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Pal.Client.Configuration;
using Pal.Client.DependencyInjection;
using Pal.Client.Extensions;
2023-02-18 20:12:36 +00:00
using Pal.Client.Floors;
using Pal.Client.Floors.Tasks;
using Pal.Client.Net;
using Pal.Common;
2023-03-30 20:01:43 +00:00
namespace Pal.Client.Scheduled;
internal sealed class QueuedSyncResponse : IQueueOnFrameworkThread
{
2023-03-30 20:01:43 +00:00
public required SyncType Type { get; init; }
public required ushort TerritoryType { get; init; }
public required bool Success { get; init; }
public required IReadOnlyList<PersistentLocation> Locations { get; init; }
internal sealed class Handler : IQueueOnFrameworkThread.Handler<QueuedSyncResponse>
{
2023-03-30 20:01:43 +00:00
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly IPalacePalConfiguration _configuration;
private readonly FloorService _floorService;
private readonly TerritoryState _territoryState;
private readonly DebugState _debugState;
public Handler(
ILogger<Handler> logger,
IServiceScopeFactory serviceScopeFactory,
IPalacePalConfiguration configuration,
FloorService floorService,
TerritoryState territoryState,
DebugState debugState)
: base(logger)
{
_serviceScopeFactory = serviceScopeFactory;
_configuration = configuration;
_floorService = floorService;
_territoryState = territoryState;
_debugState = debugState;
}
2023-03-30 20:01:43 +00:00
protected override void Run(QueuedSyncResponse queued, ref bool recreateLayout)
{
2023-03-30 20:01:43 +00:00
recreateLayout = true;
_logger.LogDebug(
"Sync response for territory {Territory} of type {Type}, success = {Success}, response objects = {Count}",
(ETerritoryType)queued.TerritoryType, queued.Type, queued.Success, queued.Locations.Count);
var memoryTerritory = _floorService.GetTerritoryIfReady(queued.TerritoryType);
if (memoryTerritory == null)
{
2023-03-30 20:01:43 +00:00
_logger.LogWarning("Discarding sync response for territory {Territory} as it isn't ready",
(ETerritoryType)queued.TerritoryType);
return;
}
2023-03-30 20:01:43 +00:00
try
{
2023-03-30 20:01:43 +00:00
var remoteMarkers = queued.Locations;
if (_configuration.Mode == EMode.Online && queued.Success && remoteMarkers.Count > 0)
{
2023-03-30 20:01:43 +00:00
switch (queued.Type)
{
2023-03-30 20:01:43 +00:00
case SyncType.Download:
case SyncType.Upload:
List<PersistentLocation> newLocations = new();
foreach (var remoteMarker in remoteMarkers)
{
// Both uploads and downloads return the network id to be set, but only the downloaded marker is new as in to-be-saved.
PersistentLocation? localLocation =
memoryTerritory.Locations.SingleOrDefault(x => x == remoteMarker);
if (localLocation != null)
{
2023-03-30 20:01:43 +00:00
localLocation.NetworkId = remoteMarker.NetworkId;
continue;
}
2023-03-30 20:01:43 +00:00
if (queued.Type == SyncType.Download)
{
memoryTerritory.Locations.Add(remoteMarker);
newLocations.Add(remoteMarker);
}
}
2023-02-18 20:12:36 +00:00
2023-03-30 20:01:43 +00:00
if (newLocations.Count > 0)
new SaveNewLocations(_serviceScopeFactory, memoryTerritory, newLocations).Start();
2023-03-30 20:01:43 +00:00
break;
2023-02-18 20:12:36 +00:00
2023-03-30 20:01:43 +00:00
case SyncType.MarkSeen:
var partialAccountId =
_configuration.FindAccount(RemoteApi.RemoteUrl)?.AccountId.ToPartialId();
if (partialAccountId == null)
break;
2023-02-18 20:12:36 +00:00
2023-03-30 20:01:43 +00:00
List<PersistentLocation> locationsToUpdate = new();
foreach (var remoteMarker in remoteMarkers)
{
PersistentLocation? localLocation =
memoryTerritory.Locations.SingleOrDefault(x => x == remoteMarker);
if (localLocation != null)
2023-02-18 20:12:36 +00:00
{
2023-03-30 20:01:43 +00:00
localLocation.RemoteSeenOn.Add(partialAccountId);
locationsToUpdate.Add(localLocation);
}
2023-03-30 20:01:43 +00:00
}
2023-03-30 20:01:43 +00:00
if (locationsToUpdate.Count > 0)
{
new MarkRemoteSeen(_serviceScopeFactory, memoryTerritory, locationsToUpdate,
partialAccountId).Start();
}
2023-03-30 20:01:43 +00:00
break;
}
}
2023-03-30 20:01:43 +00:00
// don't modify state for outdated floors
if (_territoryState.LastTerritory != queued.TerritoryType)
return;
if (queued.Type == SyncType.Download)
{
2023-03-30 20:01:43 +00:00
if (queued.Success)
memoryTerritory.SyncState = ESyncState.Complete;
else
memoryTerritory.SyncState = ESyncState.Failed;
}
}
2023-03-30 20:01:43 +00:00
catch (Exception e)
{
_logger.LogError(e, "Sync failed for territory {Territory}", (ETerritoryType)queued.TerritoryType);
_debugState.SetFromException(e);
if (queued.Type == SyncType.Download)
memoryTerritory.SyncState = ESyncState.Failed;
}
}
}
2023-03-30 20:01:43 +00:00
}
2023-03-30 20:01:43 +00:00
public enum ESyncState
{
NotAttempted,
NotNeeded,
Started,
Complete,
Failed,
}
2023-03-30 20:01:43 +00:00
public enum SyncType
{
Upload,
Download,
MarkSeen,
}