[Draft] Update 0.8 (#46)
* move stuff out into file transfer manager * obnoxious unsupported version text, adjustments to filetransfermanager * add back file upload transfer progress * restructure code * cleanup some more stuff I guess * downloadids by playername * individual anim/sound bs * fix migration stuff, finalize impl of individual sound/anim pause * fixes with logging stuff * move download manager to transient * rework dl ui first iteration * some refactoring and cleanup * more code cleanup * refactoring * switch to hostbuilder * some more rework I guess * more refactoring * clean up mediator calls and disposal * fun code cleanup * push error message when log level is set to anything but information in non-debug builds * remove notificationservice * move message to after login * add download bars to gameworld * fixes download progress bar * set gpose ui min and max size * remove unnecessary usings * adjustments to reconnection logic * add options to set visible/offline groups visibility * add impl of uploading display, transfer list in settings ui * attempt to fix issues with server selection * add back download status to compact ui * make dl bar fixed size based * some fixes for upload/download handling * adjust text from Syncing back to Uploading --------- Co-authored-by: rootdarkarchon <root.darkarchon@outlook.com> Co-authored-by: Stanley Dimant <stanley.dimant@varian.com>
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MareSynchronos.Services.Mediator;
|
||||
|
||||
public abstract class DisposableMediatorSubscriberBase : MediatorSubscriberBase, IDisposable
|
||||
{
|
||||
protected DisposableMediatorSubscriberBase(ILogger logger, MareMediator mediator) : base(logger, mediator)
|
||||
{
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
Logger.LogTrace("Disposing {type} ({this})", GetType().Name, this);
|
||||
UnsubscribeAll();
|
||||
}
|
||||
}
|
||||
6
MareSynchronos/Services/Mediator/IMediatorSubscriber.cs
Normal file
6
MareSynchronos/Services/Mediator/IMediatorSubscriber.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace MareSynchronos.Services.Mediator;
|
||||
|
||||
public interface IMediatorSubscriber
|
||||
{
|
||||
MareMediator Mediator { get; }
|
||||
}
|
||||
3
MareSynchronos/Services/Mediator/IMessage.cs
Normal file
3
MareSynchronos/Services/Mediator/IMessage.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace MareSynchronos.Services.Mediator;
|
||||
|
||||
public interface IMessage { }
|
||||
131
MareSynchronos/Services/Mediator/MareMediator.cs
Normal file
131
MareSynchronos/Services/Mediator/MareMediator.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text;
|
||||
|
||||
namespace MareSynchronos.Services.Mediator;
|
||||
|
||||
public sealed class MareMediator : IDisposable
|
||||
{
|
||||
private readonly object _addRemoveLock = new();
|
||||
|
||||
private readonly Dictionary<object, DateTime> _lastErrorTime = new();
|
||||
|
||||
private readonly ILogger<MareMediator> _logger;
|
||||
|
||||
private readonly PerformanceCollectorService _performanceCollector;
|
||||
|
||||
private readonly Dictionary<Type, HashSet<SubscriberAction>> _subscriberDict = new();
|
||||
|
||||
public MareMediator(ILogger<MareMediator> logger, PerformanceCollectorService performanceCollector)
|
||||
{
|
||||
_logger = logger;
|
||||
_performanceCollector = performanceCollector;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_logger.LogTrace("Disposing {type}", GetType());
|
||||
_subscriberDict.Clear();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public void PrintSubscriberInfo()
|
||||
{
|
||||
foreach (var kvp in _subscriberDict.SelectMany(c => c.Value.Select(v => v))
|
||||
.DistinctBy(p => p.Subscriber).OrderBy(p => p.Subscriber.GetType().FullName, StringComparer.Ordinal).ToList())
|
||||
{
|
||||
_logger.LogInformation("Subscriber {type}: {sub}", kvp.Subscriber.GetType().Name, kvp.Subscriber.ToString());
|
||||
StringBuilder sb = new();
|
||||
sb.Append("=> ");
|
||||
foreach (var item in _subscriberDict.Where(item => item.Value.Any(v => v.Subscriber == kvp.Subscriber)).ToList())
|
||||
{
|
||||
sb.Append(item.Key.Name).Append(", ");
|
||||
}
|
||||
|
||||
if (!string.Equals(sb.ToString(), "=> ", StringComparison.Ordinal))
|
||||
_logger.LogInformation("{sb}", sb.ToString());
|
||||
_logger.LogInformation("---");
|
||||
}
|
||||
}
|
||||
|
||||
public void Publish<T>(T message) where T : IMessage
|
||||
{
|
||||
if (_subscriberDict.TryGetValue(message.GetType(), out HashSet<SubscriberAction>? subscribers) && subscribers != null && subscribers.Any())
|
||||
{
|
||||
_performanceCollector.LogPerformance(this, $"Publish>{message.GetType().Name}", () =>
|
||||
{
|
||||
foreach (SubscriberAction subscriber in subscribers?.Where(s => s.Subscriber != null).ToHashSet() ?? new HashSet<SubscriberAction>())
|
||||
{
|
||||
try
|
||||
{
|
||||
_performanceCollector.LogPerformance(this, $"Publish>{message.GetType().Name}+{subscriber.Subscriber.GetType().Name}", () => ((Action<T>)subscriber.Action).Invoke(message));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (_lastErrorTime.TryGetValue(subscriber, out var lastErrorTime) && lastErrorTime.Add(TimeSpan.FromSeconds(10)) > DateTime.UtcNow)
|
||||
continue;
|
||||
|
||||
_logger.LogCritical(ex, "Error executing {type} for subscriber {subscriber}", message.GetType().Name, subscriber.Subscriber.GetType().Name);
|
||||
_lastErrorTime[subscriber] = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void Subscribe<T>(IMediatorSubscriber subscriber, Action<T> action) where T : IMessage
|
||||
{
|
||||
lock (_addRemoveLock)
|
||||
{
|
||||
_subscriberDict.TryAdd(typeof(T), new HashSet<SubscriberAction>());
|
||||
|
||||
if (!_subscriberDict[typeof(T)].Add(new(subscriber, action)))
|
||||
{
|
||||
throw new InvalidOperationException("Already subscribed");
|
||||
}
|
||||
|
||||
_logger.LogDebug("Subscriber added for message {message}: {sub}", typeof(T).Name, subscriber.GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
public void Unsubscribe<T>(IMediatorSubscriber subscriber) where T : IMessage
|
||||
{
|
||||
lock (_addRemoveLock)
|
||||
{
|
||||
if (_subscriberDict.ContainsKey(typeof(T)))
|
||||
{
|
||||
_subscriberDict[typeof(T)].RemoveWhere(p => p.Subscriber == subscriber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void UnsubscribeAll(IMediatorSubscriber subscriber)
|
||||
{
|
||||
lock (_addRemoveLock)
|
||||
{
|
||||
foreach (KeyValuePair<Type, HashSet<SubscriberAction>> kvp in _subscriberDict)
|
||||
{
|
||||
int unSubbed = _subscriberDict[kvp.Key]?.RemoveWhere(p => p.Subscriber == subscriber) ?? 0;
|
||||
if (unSubbed > 0)
|
||||
{
|
||||
_logger.LogDebug("{sub} unsubscribed from {msg}", subscriber.GetType().Name, kvp.Key.Name);
|
||||
if (_subscriberDict[kvp.Key].Any())
|
||||
{
|
||||
_logger.LogTrace("Remaining Subscribers: {item}", string.Join(", ", _subscriberDict[kvp.Key].Select(k => k.Subscriber.GetType().Name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class SubscriberAction
|
||||
{
|
||||
public SubscriberAction(IMediatorSubscriber subscriber, object action)
|
||||
{
|
||||
Subscriber = subscriber;
|
||||
Action = action;
|
||||
}
|
||||
|
||||
public object Action { get; }
|
||||
public IMediatorSubscriber Subscriber { get; }
|
||||
}
|
||||
}
|
||||
23
MareSynchronos/Services/Mediator/MediatorSubscriberBase.cs
Normal file
23
MareSynchronos/Services/Mediator/MediatorSubscriberBase.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MareSynchronos.Services.Mediator;
|
||||
|
||||
public abstract class MediatorSubscriberBase : IMediatorSubscriber
|
||||
{
|
||||
protected MediatorSubscriberBase(ILogger logger, MareMediator mediator)
|
||||
{
|
||||
Logger = logger;
|
||||
|
||||
Logger.LogTrace("Creating {type} ({this})", GetType().Name, this);
|
||||
Mediator = mediator;
|
||||
}
|
||||
|
||||
public MareMediator Mediator { get; }
|
||||
protected ILogger Logger { get; }
|
||||
|
||||
protected void UnsubscribeAll()
|
||||
{
|
||||
Logger.LogTrace("Unsubscribing from all for {type} ({this})", GetType().Name, this);
|
||||
Mediator.UnsubscribeAll(this);
|
||||
}
|
||||
}
|
||||
57
MareSynchronos/Services/Mediator/Messages.cs
Normal file
57
MareSynchronos/Services/Mediator/Messages.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using Dalamud.Interface.Internal.Notifications;
|
||||
using MareSynchronos.API.Dto;
|
||||
using MareSynchronos.PlayerData.Handlers;
|
||||
using MareSynchronos.WebAPI.Files.Models;
|
||||
|
||||
namespace MareSynchronos.Services.Mediator;
|
||||
|
||||
#pragma warning disable MA0048 // File name must match type name
|
||||
public record SwitchToIntroUiMessage : IMessage;
|
||||
public record SwitchToMainUiMessage : IMessage;
|
||||
public record OpenSettingsUiMessage : IMessage;
|
||||
public record DalamudLoginMessage : IMessage;
|
||||
public record DalamudLogoutMessage : IMessage;
|
||||
public record FrameworkUpdateMessage : IMessage;
|
||||
public record ClassJobChangedMessage : IMessage;
|
||||
public record DelayedFrameworkUpdateMessage : IMessage;
|
||||
public record ZoneSwitchStartMessage : IMessage;
|
||||
public record ZoneSwitchEndMessage : IMessage;
|
||||
public record CutsceneStartMessage : IMessage;
|
||||
public record GposeStartMessage : IMessage;
|
||||
public record GposeEndMessage : IMessage;
|
||||
public record CutsceneEndMessage : IMessage;
|
||||
public record CutsceneFrameworkUpdateMessage : IMessage;
|
||||
public record ConnectedMessage(ConnectionDto Connection) : IMessage;
|
||||
public record DisconnectedMessage : IMessage;
|
||||
public record PenumbraModSettingChangedMessage : IMessage;
|
||||
public record PenumbraInitializedMessage : IMessage;
|
||||
public record PenumbraDisposedMessage : IMessage;
|
||||
public record PenumbraRedrawMessage(IntPtr Address, int ObjTblIdx, bool WasRequested) : IMessage;
|
||||
public record HeelsOffsetMessage : IMessage;
|
||||
public record PenumbraResourceLoadMessage(IntPtr GameObject, string GamePath, string FilePath) : IMessage;
|
||||
public record CustomizePlusMessage : IMessage;
|
||||
public record PalettePlusMessage : IMessage;
|
||||
public record PlayerChangedMessage(API.Data.CharacterData Data) : IMessage;
|
||||
public record CharacterChangedMessage(GameObjectHandler GameObjectHandler) : IMessage;
|
||||
public record TransientResourceChangedMessage(IntPtr Address) : IMessage;
|
||||
public record AddWatchedGameObjectHandler(GameObjectHandler Handler) : IMessage;
|
||||
public record RemoveWatchedGameObjectHandler(GameObjectHandler Handler) : IMessage;
|
||||
public record HaltScanMessage(string Source) : IMessage;
|
||||
public record ResumeScanMessage(string Source) : IMessage;
|
||||
public record NotificationMessage
|
||||
(string Title, string Message, NotificationType Type, uint TimeShownOnScreen = 3000) : IMessage;
|
||||
public record CreateCacheForObjectMessage(GameObjectHandler ObjectToCreateFor) : IMessage;
|
||||
public record ClearCacheForObjectMessage(GameObjectHandler ObjectToCreateFor) : IMessage;
|
||||
public record CharacterDataCreatedMessage(API.Data.CharacterData CharacterData) : IMessage;
|
||||
public record PenumbraStartRedrawMessage(IntPtr Address) : IMessage;
|
||||
public record PenumbraEndRedrawMessage(IntPtr Address) : IMessage;
|
||||
public record HubReconnectingMessage(Exception? Exception) : IMessage;
|
||||
public record HubReconnectedMessage(string? Arg) : IMessage;
|
||||
public record HubClosedMessage(Exception? Exception) : IMessage;
|
||||
public record DownloadReadyMessage(Guid RequestId) : IMessage;
|
||||
public record DownloadStartedMessage(GameObjectHandler DownloadId, Dictionary<string, FileDownloadStatus> DownloadStatus) : IMessage;
|
||||
public record DownloadFinishedMessage(GameObjectHandler DownloadId) : IMessage;
|
||||
public record UiToggleMessage(Type UiType) : IMessage;
|
||||
public record PlayerUploadingMessage(GameObjectHandler Handler, bool IsUploading) : IMessage;
|
||||
|
||||
#pragma warning restore MA0048 // File name must match type name
|
||||
@@ -0,0 +1,45 @@
|
||||
using Dalamud.Interface.Windowing;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MareSynchronos.Services.Mediator;
|
||||
|
||||
public abstract class WindowMediatorSubscriberBase : Window, IMediatorSubscriber, IDisposable
|
||||
{
|
||||
protected readonly ILogger _logger;
|
||||
|
||||
protected WindowMediatorSubscriberBase(ILogger logger, MareMediator mediator, string name) : base(name)
|
||||
{
|
||||
_logger = logger;
|
||||
Mediator = mediator;
|
||||
|
||||
_logger.LogTrace("Creating {type}", GetType());
|
||||
|
||||
Mediator.Subscribe<UiToggleMessage>(this, (msg) =>
|
||||
{
|
||||
if (msg.UiType == GetType())
|
||||
{
|
||||
Toggle();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public MareMediator Mediator { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public virtual Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
_logger.LogTrace("Disposing {type}", GetType());
|
||||
|
||||
Mediator.UnsubscribeAll(this);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user