From fc3ad1f7f8489f1dfead537e79d776bd70cdc90c Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Sat, 4 Feb 2023 02:04:26 +0100 Subject: [PATCH] attempt to gracefully reconnect, do not send notification for player on connect, do not check other players on framework update thread, delay palette+ sending data --- .../Managers/CacheCreationService.cs | 13 ++++++++- MareSynchronos/Managers/CachedPlayer.cs | 8 +++--- MareSynchronos/Managers/PairManager.cs | 1 + MareSynchronos/Models/GameObjectHandler.cs | 19 +++++++------ MareSynchronos/WebAPI/ApiController.cs | 13 +++------ .../WebAPI/Utils/ForeverRetryPolicy.cs | 28 +++++++++++++++++-- 6 files changed, 58 insertions(+), 24 deletions(-) diff --git a/MareSynchronos/Managers/CacheCreationService.cs b/MareSynchronos/Managers/CacheCreationService.cs index 0eeb9e4..7991883 100644 --- a/MareSynchronos/Managers/CacheCreationService.cs +++ b/MareSynchronos/Managers/CacheCreationService.cs @@ -15,6 +15,7 @@ public class CacheCreationService : MediatorSubscriberBase, IDisposable private readonly CharacterData _lastCreatedData = new(); private readonly CancellationTokenSource _cts = new(); private readonly List _playerRelatedObjects = new(); + private CancellationTokenSource _palettePlusCts = new(); public unsafe CacheCreationService(MareMediator mediator, CharacterDataFactory characterDataFactory, DalamudUtil dalamudUtil) : base(mediator) { @@ -45,7 +46,17 @@ public class CacheCreationService : MediatorSubscriberBase, IDisposable if (!string.Equals(msg.Data, _lastCreatedData.PalettePlusPalette, StringComparison.Ordinal)) { _lastCreatedData.PalettePlusPalette = msg.Data ?? string.Empty; - Mediator.Publish(new CharacterDataCreatedMessage(_lastCreatedData)); + + _palettePlusCts?.Cancel(); + _palettePlusCts?.Dispose(); + _palettePlusCts = new(); + var token = _palettePlusCts.Token; + + Task.Run(async () => + { + await Task.Delay(TimeSpan.FromSeconds(1), token).ConfigureAwait(false); + Mediator.Publish(new CharacterDataCreatedMessage(_lastCreatedData)); + }, token); } } diff --git a/MareSynchronos/Managers/CachedPlayer.cs b/MareSynchronos/Managers/CachedPlayer.cs index af51202..07d1a2f 100644 --- a/MareSynchronos/Managers/CachedPlayer.cs +++ b/MareSynchronos/Managers/CachedPlayer.cs @@ -19,7 +19,7 @@ public class CachedPlayer : MediatorSubscriberBase, IDisposable private readonly IpcManager _ipcManager; private readonly FileCacheManager _fileDbManager; private API.Data.CharacterData _cachedData = new(); - private GameObjectHandler? _currentCharacterEquipment; + private GameObjectHandler? _currentOtherChara; private CancellationTokenSource? _downloadCancellationTokenSource = new(); private bool _isVisible; @@ -209,7 +209,7 @@ public class CachedPlayer : MediatorSubscriberBase, IDisposable return false; } - if (_currentCharacterEquipment?.CheckAndUpdateObject() ?? false) + if (_currentOtherChara?.CheckAndUpdateObject() ?? false) { OnPlayerChanged(); } @@ -228,7 +228,7 @@ public class CachedPlayer : MediatorSubscriberBase, IDisposable Logger.Debug("Disposing " + PlayerName + " (" + OnlineUser + ")"); try { - _currentCharacterEquipment?.Dispose(); + _currentOtherChara?.Dispose(); Logger.Verbose("Restoring state for " + PlayerName); _ipcManager.PenumbraRemoveTemporaryCollection(PlayerName); _downloadCancellationTokenSource?.Cancel(); @@ -267,7 +267,7 @@ public class CachedPlayer : MediatorSubscriberBase, IDisposable Mediator.Subscribe(this, (msg) => IpcManagerOnPenumbraRedrawEvent(((PenumbraRedrawMessage)msg))); _originalGlamourerData = _ipcManager.GlamourerGetCharacterCustomization(PlayerCharacter); - _currentCharacterEquipment = new GameObjectHandler(Mediator, ObjectKind.Player, () => _dalamudUtil.GetPlayerCharacterFromObjectTableByName(PlayerName)?.Address ?? IntPtr.Zero, false); + _currentOtherChara = new GameObjectHandler(Mediator, ObjectKind.Player, () => _dalamudUtil.GetPlayerCharacterFromObjectTableByName(PlayerName)?.Address ?? IntPtr.Zero, false); } public override string ToString() diff --git a/MareSynchronos/Managers/PairManager.cs b/MareSynchronos/Managers/PairManager.cs index b3b0012..a25298e 100644 --- a/MareSynchronos/Managers/PairManager.cs +++ b/MareSynchronos/Managers/PairManager.cs @@ -32,6 +32,7 @@ public class PairManager : MediatorSubscriberBase, IDisposable _configurationService = configurationService; Mediator.Subscribe(this, (_) => DalamudUtilOnZoneSwitched()); Mediator.Subscribe(this, (_) => DalamudUtilOnDelayedFrameworkUpdate()); + Mediator.Subscribe(this, (_) => ClearPairs()); _directPairsInternal = DirectPairsLazy(); _groupPairsInternal = GroupPairsLazy(); } diff --git a/MareSynchronos/Models/GameObjectHandler.cs b/MareSynchronos/Models/GameObjectHandler.cs index feb2a72..7f398cd 100644 --- a/MareSynchronos/Models/GameObjectHandler.cs +++ b/MareSynchronos/Models/GameObjectHandler.cs @@ -34,22 +34,25 @@ public class GameObjectHandler : MediatorSubscriberBase } } - public GameObjectHandler(MareMediator mediator, ObjectKind objectKind, Func getAddress, bool sendUpdates = true) : base(mediator) + public GameObjectHandler(MareMediator mediator, ObjectKind objectKind, Func getAddress, bool watchedPlayer = true) : base(mediator) { _mediator = mediator; ObjectKind = objectKind; this._getAddress = getAddress; - _sendUpdates = sendUpdates; + _sendUpdates = watchedPlayer; _name = string.Empty; - Mediator.Subscribe(this, (msg) => + if (watchedPlayer) { - var actualMsg = (TransientResourceChangedMessage)msg; - if (actualMsg.Address != Address || !sendUpdates) return; - Mediator.Publish(new CreateCacheForObjectMessage(this)); - }); + Mediator.Subscribe(this, (msg) => + { + var actualMsg = (TransientResourceChangedMessage)msg; + if (actualMsg.Address != Address) return; + Mediator.Publish(new CreateCacheForObjectMessage(this)); + }); - Mediator.Subscribe(this, (_) => CheckAndUpdateObject()); + Mediator.Subscribe(this, (_) => CheckAndUpdateObject()); + } } public byte[] EquipSlotData { get; set; } = new byte[40]; diff --git a/MareSynchronos/WebAPI/ApiController.cs b/MareSynchronos/WebAPI/ApiController.cs index f2a270a..39d4dea 100644 --- a/MareSynchronos/WebAPI/ApiController.cs +++ b/MareSynchronos/WebAPI/ApiController.cs @@ -294,7 +294,7 @@ public partial class ApiController : MediatorSubscriberBase, IDisposable, IMareH foreach (var entry in await UserGetOnlinePairs().ConfigureAwait(false)) { - _pairManager.MarkPairOnline(entry, this, false); + _pairManager.MarkPairOnline(entry, this, sendNotif: false); } _healthCheckTokenSource?.Cancel(); @@ -323,7 +323,7 @@ public partial class ApiController : MediatorSubscriberBase, IDisposable, IMareH options.Headers.Add("Authorization", "Bearer " + _serverManager.GetToken()); options.Transports = HttpTransportType.WebSockets | HttpTransportType.ServerSentEvents | HttpTransportType.LongPolling; }) - .WithAutomaticReconnect(new ForeverRetryPolicy()) + .WithAutomaticReconnect(new ForeverRetryPolicy(Mediator)) .ConfigureLogging(a => { a.ClearProviders().AddProvider(new DalamudLoggingProvider()); @@ -347,15 +347,10 @@ public partial class ApiController : MediatorSubscriberBase, IDisposable, IMareH private Task MareHubOnReconnecting(Exception? arg) { - _connectionDto = null; _healthCheckTokenSource?.Cancel(); ServerState = ServerState.Reconnecting; - Mediator.Publish(new NotificationMessage("Connection lost", "Connection lost to " + _serverManager.CurrentServer!.ServerName, NotificationType.Error, 5000)); - Logger.Warn("Connection closed... Reconnecting"); - Logger.Warn(arg?.Message ?? string.Empty); - Logger.Warn(arg?.StackTrace ?? string.Empty); - Mediator.Publish(new DisconnectedMessage()); - _pairManager.ClearPairs(); + Mediator.Publish(new NotificationMessage("Connection lost", "Connection lost to " + _serverManager.CurrentServer!.ServerName, NotificationType.Warning, 5000)); + Logger.Warn("Connection closed... Reconnecting", arg); return Task.CompletedTask; } diff --git a/MareSynchronos/WebAPI/Utils/ForeverRetryPolicy.cs b/MareSynchronos/WebAPI/Utils/ForeverRetryPolicy.cs index b38384f..f22fb70 100644 --- a/MareSynchronos/WebAPI/Utils/ForeverRetryPolicy.cs +++ b/MareSynchronos/WebAPI/Utils/ForeverRetryPolicy.cs @@ -1,11 +1,35 @@ -using Microsoft.AspNetCore.SignalR.Client; +using MareSynchronos.Mediator; +using Microsoft.AspNetCore.SignalR.Client; namespace MareSynchronos.WebAPI.Utils; public class ForeverRetryPolicy : IRetryPolicy { + private readonly MareMediator _mediator; + private bool _sentDisconnected = false; + + public ForeverRetryPolicy(MareMediator mediator) + { + _mediator = mediator; + } + public TimeSpan? NextRetryDelay(RetryContext retryContext) { - return TimeSpan.FromSeconds(new Random().Next(10, 20)); + TimeSpan timeToWait = TimeSpan.FromSeconds(new Random().Next(10, 20)); + if (retryContext.PreviousRetryCount == 0) + { + _sentDisconnected = false; + timeToWait = TimeSpan.FromSeconds(1); + } + else if (retryContext.PreviousRetryCount == 1) timeToWait = TimeSpan.FromSeconds(2); + else if (retryContext.PreviousRetryCount == 2) timeToWait = TimeSpan.FromSeconds(3); + else + { + if (!_sentDisconnected) + _mediator.Publish(new DisconnectedMessage()); + _sentDisconnected = true; + } + + return timeToWait; } } \ No newline at end of file