[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:
rootdarkarchon
2023-03-14 19:48:35 +01:00
committed by GitHub
parent 0824ba434b
commit 0c87e84f25
109 changed files with 7323 additions and 6488 deletions

View 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; }
}
}