Restore logic

This commit is contained in:
2025-11-25 09:42:34 +09:00
parent ef592032b3
commit 28d9110cb0
2 changed files with 114 additions and 430 deletions

View File

@@ -1,17 +1,16 @@
using System;
using LightlessSync.API.Data;
using LightlessSync.API.Data.Comparer;
using LightlessSync.PlayerData.Pairs;
using LightlessSync.Utils;
using LightlessSync.Services.Mediator;
using LightlessSync.Services;
using LightlessSync.WebAPI;
using LightlessSync.WebAPI.Files;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using LightlessSync.API.Data;
using LightlessSync.API.Data.Comparer;
using LightlessSync.Services;
using LightlessSync.Services.Mediator;
using LightlessSync.Utils;
using LightlessSync.WebAPI;
using LightlessSync.WebAPI.Files;
using Microsoft.Extensions.Logging;
namespace LightlessSync.PlayerData.Pairs;
@@ -28,9 +27,6 @@ public class VisibleUserDataDistributor : DisposableMediatorSubscriberBase
private readonly HashSet<UserData> _usersToPushDataTo = new(UserDataComparer.Instance);
private readonly SemaphoreSlim _pushDataSemaphore = new(1, 1);
private readonly CancellationTokenSource _runtimeCts = new();
private readonly Dictionary<string, string> _lastPushedHashes = new(StringComparer.Ordinal);
private readonly object _pushSync = new();
public VisibleUserDataDistributor(ILogger<VisibleUserDataDistributor> logger, ApiController apiController, DalamudUtilService dalamudUtil,
PairLedger pairLedger, LightlessMediator mediator, FileUploadManager fileTransferManager) : base(logger, mediator)
@@ -56,7 +52,14 @@ public class VisibleUserDataDistributor : DisposableMediatorSubscriberBase
});
Mediator.Subscribe<ConnectedMessage>(this, (_) => PushToAllVisibleUsers());
Mediator.Subscribe<DisconnectedMessage>(this, (_) => HandleDisconnected());
Mediator.Subscribe<DisconnectedMessage>(this, (_) =>
{
_fileTransferManager.CancelUpload();
_previouslyVisiblePlayers.Clear();
_usersToPushDataTo.Clear();
_uploadingCharacterData = null;
_fileUploadTask = null;
});
}
protected override void Dispose(bool disposing)
@@ -72,18 +75,15 @@ public class VisibleUserDataDistributor : DisposableMediatorSubscriberBase
private void PushToAllVisibleUsers(bool forced = false)
{
lock (_pushSync)
foreach (var user in GetVisibleUsers())
{
foreach (var user in GetVisibleUsers())
{
_usersToPushDataTo.Add(user);
}
_usersToPushDataTo.Add(user);
}
if (_usersToPushDataTo.Count > 0)
{
Logger.LogDebug("Pushing data {hash} for {count} visible players", _lastCreatedData?.DataHash.Value ?? "UNKNOWN", _usersToPushDataTo.Count);
PushCharacterData_internalLocked(forced);
}
if (_usersToPushDataTo.Count > 0)
{
Logger.LogDebug("Pushing data {hash} for {count} visible players", _lastCreatedData?.DataHash.Value ?? "UNKNOWN", _usersToPushDataTo.Count);
PushCharacterData(forced);
}
}
@@ -92,9 +92,7 @@ public class VisibleUserDataDistributor : DisposableMediatorSubscriberBase
if (!_dalamudUtil.GetIsPlayerPresent() || !_apiController.IsConnected) return;
var allVisibleUsers = GetVisibleUsers();
var newVisibleUsers = allVisibleUsers
.Except(_previouslyVisiblePlayers, UserDataComparer.Instance)
.ToList();
var newVisibleUsers = allVisibleUsers.Except(_previouslyVisiblePlayers, UserDataComparer.Instance).ToList();
_previouslyVisiblePlayers.Clear();
_previouslyVisiblePlayers.AddRange(allVisibleUsers);
if (newVisibleUsers.Count == 0) return;
@@ -102,115 +100,48 @@ public class VisibleUserDataDistributor : DisposableMediatorSubscriberBase
Logger.LogDebug("Scheduling character data push of {data} to {users}",
_lastCreatedData?.DataHash.Value ?? string.Empty,
string.Join(", ", newVisibleUsers.Select(k => k.AliasOrUID)));
lock (_pushSync)
foreach (var user in newVisibleUsers)
{
foreach (var user in newVisibleUsers)
{
_usersToPushDataTo.Add(user);
}
PushCharacterData_internalLocked();
_usersToPushDataTo.Add(user);
}
PushCharacterData();
}
private void PushCharacterData(bool forced = false)
{
lock (_pushSync)
{
PushCharacterData_internalLocked(forced);
}
}
private void PushCharacterData_internalLocked(bool forced = false)
{
if (_lastCreatedData == null || _usersToPushDataTo.Count == 0) return;
if (!_apiController.IsConnected || !_fileTransferManager.IsReady)
{
Logger.LogTrace("Skipping character push. Connected: {connected}, UploadManagerReady: {ready}",
_apiController.IsConnected, _fileTransferManager.IsReady);
return;
}
_ = Task.Run(async () =>
{
try
{
Task<CharacterData>? uploadTask;
bool forcedPush;
lock (_pushSync)
{
if (_lastCreatedData == null || _usersToPushDataTo.Count == 0) return;
forcedPush = forced | (_uploadingCharacterData?.DataHash != _lastCreatedData.DataHash);
forced |= _uploadingCharacterData?.DataHash != _lastCreatedData.DataHash;
if (_fileUploadTask == null || (_fileUploadTask?.IsCompleted ?? false) || forcedPush)
{
_uploadingCharacterData = _lastCreatedData.DeepClone();
Logger.LogDebug("Starting UploadTask for {hash}, Reason: TaskIsNull: {task}, TaskIsCompleted: {taskCpl}, Forced: {frc}",
_lastCreatedData.DataHash, _fileUploadTask == null, _fileUploadTask?.IsCompleted ?? false, forcedPush);
_fileUploadTask = _fileTransferManager.UploadFiles(_uploadingCharacterData, [.. _usersToPushDataTo]);
}
if (_fileUploadTask == null || (_fileUploadTask?.IsCompleted ?? false) || forced)
{
_uploadingCharacterData = _lastCreatedData.DeepClone();
Logger.LogDebug("Starting UploadTask for {hash}, Reason: TaskIsNull: {task}, TaskIsCompleted: {taskCpl}, Forced: {frc}",
_lastCreatedData.DataHash, _fileUploadTask == null, _fileUploadTask?.IsCompleted ?? false, forced);
_fileUploadTask = _fileTransferManager.UploadFiles(_uploadingCharacterData, [.. _usersToPushDataTo]);
}
uploadTask = _fileUploadTask;
}
var dataToSend = await uploadTask.ConfigureAwait(false);
var dataHash = dataToSend.DataHash.Value;
if (_fileUploadTask != null)
{
var dataToSend = await _fileUploadTask.ConfigureAwait(false);
await _pushDataSemaphore.WaitAsync(_runtimeCts.Token).ConfigureAwait(false);
try
{
List<UserData> recipients;
bool shouldSkip = false;
lock (_pushSync)
{
if (_usersToPushDataTo.Count == 0) return;
recipients = forcedPush
? _usersToPushDataTo.ToList()
: _usersToPushDataTo
.Where(user => !_lastPushedHashes.TryGetValue(user.UID, out var sentHash) || !string.Equals(sentHash, dataHash, StringComparison.Ordinal))
.ToList();
if (recipients.Count == 0 && !forcedPush)
{
Logger.LogTrace("All recipients already have character data hash {hash}, skipping push.", dataHash);
_usersToPushDataTo.Clear();
shouldSkip = true;
}
}
if (shouldSkip)
return;
Logger.LogDebug("Pushing {data} to {users}", dataHash, string.Join(", ", recipients.Select(k => k.AliasOrUID)));
await _apiController.PushCharacterData(dataToSend, recipients).ConfigureAwait(false);
lock (_pushSync)
{
foreach (var user in recipients)
{
_lastPushedHashes[user.UID] = dataHash;
_usersToPushDataTo.Remove(user);
}
if (!forcedPush && _usersToPushDataTo.Count > 0)
{
foreach (var satisfied in _usersToPushDataTo
.Where(user => _lastPushedHashes.TryGetValue(user.UID, out var sentHash) && string.Equals(sentHash, dataHash, StringComparison.Ordinal))
.ToList())
{
_usersToPushDataTo.Remove(satisfied);
}
}
if (forcedPush)
{
_usersToPushDataTo.Clear();
}
}
if (_usersToPushDataTo.Count == 0) return;
Logger.LogDebug("Pushing {data} to {users}", dataToSend.DataHash, string.Join(", ", _usersToPushDataTo.Select(k => k.AliasOrUID)));
await _apiController.PushCharacterData(dataToSend, [.. _usersToPushDataTo]).ConfigureAwait(false);
_usersToPushDataTo.Clear();
}
finally
{
_pushDataSemaphore.Release();
}
}
}
catch (OperationCanceledException) when (_runtimeCts.IsCancellationRequested)
{
Logger.LogDebug("PushCharacterData cancelled");
@@ -222,20 +153,6 @@ public class VisibleUserDataDistributor : DisposableMediatorSubscriberBase
});
}
private void HandleDisconnected()
{
_fileTransferManager.CancelUpload();
_previouslyVisiblePlayers.Clear();
lock (_pushSync)
{
_usersToPushDataTo.Clear();
_lastPushedHashes.Clear();
_uploadingCharacterData = null;
_fileUploadTask = null;
}
}
private List<UserData> GetVisibleUsers()
{
return _pairLedger.GetVisiblePairs()