Skip to content

Commit

Permalink
it's ALIVE
Browse files Browse the repository at this point in the history
  • Loading branch information
adamhathcock committed Nov 28, 2024
1 parent bb0faaa commit 8e3b1da
Show file tree
Hide file tree
Showing 16 changed files with 148 additions and 133 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ public class ArcGISSelectionBinding : ISelectionBinding
public string Name => "selectionBinding";
public IBrowserBridge Parent { get; }

public ArcGISSelectionBinding(IBrowserBridge parent, MapMembersUtils mapMemberUtils, ITopLevelExceptionHandler topLevelExceptionHandler)
public ArcGISSelectionBinding(
IBrowserBridge parent,
MapMembersUtils mapMemberUtils,
ITopLevelExceptionHandler topLevelExceptionHandler
)
{
_mapMemberUtils = mapMemberUtils;
Parent = parent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ public class BasicConnectorBinding : IBasicConnectorBinding
private readonly DocumentModelStore _store;
private readonly ISpeckleApplication _speckleApplication;

public BasicConnectorBinding(DocumentModelStore store, IBrowserBridge parent, ISpeckleApplication speckleApplication, ITopLevelExceptionHandler topLevelExceptionHandler)
public BasicConnectorBinding(
DocumentModelStore store,
IBrowserBridge parent,
ISpeckleApplication speckleApplication,
ITopLevelExceptionHandler topLevelExceptionHandler
)
{
_store = store;
_speckleApplication = speckleApplication;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ public static void AddArcGIS(this IServiceCollection serviceCollection)
serviceCollection.AddSingleton<IBinding, ConfigBinding>();
serviceCollection.AddSingleton<IBinding, AccountBinding>();

serviceCollection.RegisterTopLevelExceptionHandler();

serviceCollection.AddSingleton<IBinding>(sp => sp.GetRequiredService<IBasicConnectorBinding>());
serviceCollection.AddSingleton<IBasicConnectorBinding, BasicConnectorBinding>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ public class AutocadSelectionBinding : ISelectionBinding

public IBrowserBridge Parent { get; }

public AutocadSelectionBinding(IBrowserBridge parent, IThreadContext threadContext, ITopLevelExceptionHandler topLevelExceptionHandler)
public AutocadSelectionBinding(
IBrowserBridge parent,
IThreadContext threadContext,
ITopLevelExceptionHandler topLevelExceptionHandler
)
{
_topLevelExceptionHandler = topLevelExceptionHandler;
Parent = parent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ IThreadContext threadContext
_logger = logger;
_speckleApplication = speckleApplication;
_threadContext = threadContext;
_topLevelExceptionHandler =topLevelExceptionHandler;
_topLevelExceptionHandler = topLevelExceptionHandler;
Parent = parent;
Commands = new SendBindingUICommands(parent);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ public static void AddAutocadBase(this IServiceCollection serviceCollection)
serviceCollection.AddSingleton<IBinding>(sp => sp.GetRequiredService<IBasicConnectorBinding>());
serviceCollection.AddSingleton<IBasicConnectorBinding, AutocadBasicConnectorBinding>();
serviceCollection.AddSingleton<IBinding, ConfigBinding>();

serviceCollection.RegisterTopLevelExceptionHandler();
}

public static void LoadSend(this IServiceCollection serviceCollection)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ public static void AddRevit(this IServiceCollection serviceCollection)
serviceCollection.AddSingleton<IBinding, RevitReceiveBinding>();
serviceCollection.AddSingleton<IAppIdleManager, RevitIdleManager>();

serviceCollection.RegisterTopLevelExceptionHandler();

serviceCollection.AddSingleton<IBinding>(sp => sp.GetRequiredService<IBasicConnectorBinding>());
serviceCollection.AddSingleton<IBasicConnectorBinding, BasicConnectorBindingRevit>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ public static void AddRhino(this IServiceCollection serviceCollection)
serviceCollection.AddSingleton<IBinding, ConfigBinding>(); // POC: Easier like this for now, should be cleaned up later
serviceCollection.AddSingleton<IBinding, AccountBinding>();

serviceCollection.RegisterTopLevelExceptionHandler();

serviceCollection.AddSingleton<IBinding>(sp => sp.GetRequiredService<IBasicConnectorBinding>());
serviceCollection.AddSingleton<IBasicConnectorBinding, RhinoBasicConnectorBinding>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ public static IServiceCollection AddTekla(this IServiceCollection services)
services.AddSingleton<IBinding, AccountBinding>();
services.AddSingleton<IBasicConnectorBinding, TeklaBasicConnectorBinding>();

services.RegisterTopLevelExceptionHandler();

services.AddSingleton<IBinding>(sp => sp.GetRequiredService<IBasicConnectorBinding>());
services.AddSingleton<IBinding, TeklaSendBinding>();
services.AddSingleton<IBinding, TeklaSelectionBinding>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public void CatchUnhandledAction_Exception()
var logger = Create<ILogger<TopLevelExceptionHandler>>(MockBehavior.Loose);
var eventAggregator = Create<ISpeckleEventAggregator>();

eventAggregator.Setup(x => x.GetEvent<ExceptionEvent>())
eventAggregator
.Setup(x => x.GetEvent<ExceptionEvent>())
.Returns(new ExceptionEvent(Create<IThreadContext>().Object));

var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object);
Expand Down Expand Up @@ -54,7 +55,8 @@ public void CatchUnhandledFunc_Exception()
var logger = Create<ILogger<TopLevelExceptionHandler>>(MockBehavior.Loose);
var eventAggregator = Create<ISpeckleEventAggregator>();

eventAggregator.Setup(x => x.GetEvent<ExceptionEvent>())
eventAggregator
.Setup(x => x.GetEvent<ExceptionEvent>())
.Returns(new ExceptionEvent(Create<IThreadContext>().Object));

var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object);
Expand Down Expand Up @@ -98,7 +100,8 @@ public async Task CatchUnhandledFuncAsync_Exception()
var logger = Create<ILogger<TopLevelExceptionHandler>>(MockBehavior.Loose);
var eventAggregator = Create<ISpeckleEventAggregator>();

eventAggregator.Setup(x => x.GetEvent<ExceptionEvent>())
eventAggregator
.Setup(x => x.GetEvent<ExceptionEvent>())
.Returns(new ExceptionEvent(Create<IThreadContext>().Object));

var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object);
Expand Down
31 changes: 23 additions & 8 deletions DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ public BrowserBridge(
IJsonSerializer jsonSerializer,
ILogger<BrowserBridge> logger,
IBrowserScriptExecutor browserScriptExecutor,
IThreadOptions threadOptions, ISpeckleEventAggregator eventAggregator, ITopLevelExceptionHandler topLevelExceptionHandler)
IThreadOptions threadOptions,
ISpeckleEventAggregator eventAggregator,
ITopLevelExceptionHandler topLevelExceptionHandler
)
{
_threadContext = threadContext;
_jsonSerializer = jsonSerializer;
Expand All @@ -73,13 +76,25 @@ public BrowserBridge(
_threadOptions = threadOptions;
_eventAggregator = eventAggregator;
_topLevelExceptionHandler = topLevelExceptionHandler;
eventAggregator.GetEvent<ExceptionEvent>().Subscribe(ex =>
{
Send(BasicConnectorBindingCommands.SET_GLOBAL_NOTIFICATION,
new { type = ToastNotificationType.DANGER, title = "Unhandled Exception Occurred", description = ex.ToFormattedString(), autoClose = false }
)
.ConfigureAwait(false);
}, ThreadOption.UIThread);
eventAggregator
.GetEvent<ExceptionEvent>()
.Subscribe(
ex =>
{
Send(
BasicConnectorBindingCommands.SET_GLOBAL_NOTIFICATION,
new
{
type = ToastNotificationType.DANGER,
title = "Unhandled Exception Occurred",
description = ex.ToFormattedString(),
autoClose = false
}
)
.ConfigureAwait(false);
},
ThreadOption.UIThread
);
}

public void AssociateWithBinding(IBinding binding)
Expand Down
61 changes: 61 additions & 0 deletions DUI3/Speckle.Connectors.DUI/Bridge/SpeckleEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using Speckle.Connectors.Common.Threading;

namespace Speckle.Connectors.DUI.Bridge;

public class ExceptionEvent(IThreadContext threadContext) : SpeckleEvent<Exception>(threadContext);

public class ThreadContextEventSubscription<T>(
IDelegateReference actionReference,
IDelegateReference filterReference,
IThreadContext threadContext
) : EventSubscription<T>(actionReference, filterReference)
{
public override void InvokeAction(Action<T> action, T payload) =>
threadContext.RunOnMain(() => action.Invoke(payload));
}

public class SpeckleEvent<T>(IThreadContext threadContext) : PubSubEvent<T>
{
public override SubscriptionToken Subscribe(
Action<T> action,
ThreadOption threadOption,
bool keepSubscriberReferenceAlive,
Predicate<T>? filter
)
{
IDelegateReference actionReference = new DelegateReference(action, keepSubscriberReferenceAlive);
IDelegateReference filterReference;
if (filter != null)
{
filterReference = new DelegateReference(filter, keepSubscriberReferenceAlive);
}
else
{
filterReference = new DelegateReference(
new Predicate<T>(
delegate
{
return true;
}
),
true
);
}
EventSubscription<T> subscription;
switch (threadOption)
{
case ThreadOption.BackgroundThread:
subscription = new BackgroundEventSubscription<T>(actionReference, filterReference);
break;
case ThreadOption.UIThread:
subscription = new ThreadContextEventSubscription<T>(actionReference, filterReference, threadContext);
break;
case ThreadOption.PublisherThread:
default:
subscription = new EventSubscription<T>(actionReference, filterReference);
break;
}

return InternalSubscribe(subscription);
}
}
35 changes: 35 additions & 0 deletions DUI3/Speckle.Connectors.DUI/Bridge/SpeckleEventAggregator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Microsoft.Extensions.DependencyInjection;

namespace Speckle.Connectors.DUI.Bridge;

public interface ISpeckleEventAggregator
{
TEventType GetEvent<TEventType>()
where TEventType : EventBase;
}

public class SpeckleEventAggregator : ISpeckleEventAggregator
{
private readonly IServiceProvider _serviceProvider;

private readonly Dictionary<Type, EventBase> _events = new();

public SpeckleEventAggregator(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}

public TEventType GetEvent<TEventType>()
where TEventType : EventBase
{
lock (_events)
{
if (!_events.TryGetValue(typeof(TEventType), out var existingEvent))
{
existingEvent = (TEventType)_serviceProvider.GetRequiredService(typeof(TEventType));
_events[typeof(TEventType)] = existingEvent;
}
return (TEventType)existingEvent;
}
}
}
75 changes: 1 addition & 74 deletions DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Common.Threading;
using Speckle.InterfaceGenerator;
using Speckle.Sdk;

Expand Down Expand Up @@ -27,7 +26,7 @@ public sealed class TopLevelExceptionHandler : ITopLevelExceptionHandler

private const string UNHANDLED_LOGGER_TEMPLATE = "An unhandled Exception occured";

internal TopLevelExceptionHandler(ILogger<TopLevelExceptionHandler> logger, ISpeckleEventAggregator eventAggregator)
public TopLevelExceptionHandler(ILogger<TopLevelExceptionHandler> logger, ISpeckleEventAggregator eventAggregator)
{
_logger = logger;
_eventAggregator = eventAggregator;
Expand Down Expand Up @@ -114,75 +113,3 @@ public async Task<Result<T>> CatchUnhandledAsync<T>(Func<Task<T>> function)
/// <param name="function"><inheritdoc cref="CatchUnhandled{T}(Func{T})"/></param>
public async void FireAndForget(Func<Task> function) => await CatchUnhandledAsync(function).ConfigureAwait(false);
}

public interface ISpeckleEventAggregator
{
TEventType GetEvent<TEventType>() where TEventType : EventBase;
}
public class SpeckleEventAggregator : ISpeckleEventAggregator
{
private readonly IServiceProvider _serviceProvider;


private readonly Dictionary<Type, EventBase> _events = new();

public SpeckleEventAggregator(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}

public TEventType GetEvent<TEventType>() where TEventType : EventBase
{
lock (_events)
{
if (!_events.TryGetValue(typeof(TEventType), out var existingEvent))
{
existingEvent = (TEventType)_serviceProvider.GetService(typeof(TEventType));
_events[typeof(TEventType)] = existingEvent;
}
return (TEventType)existingEvent;
}
}
}

public class ExceptionEvent(IThreadContext threadContext) : SpeckleEvent<Exception>(threadContext);

public class SpeckleEvent<T>(IThreadContext threadContext) : PubSubEvent<T>
{
public override SubscriptionToken Subscribe(Action<T> action, ThreadOption threadOption, bool keepSubscriberReferenceAlive,
Predicate<T> filter)
{
IDelegateReference actionReference = new DelegateReference(action, keepSubscriberReferenceAlive);

EventSubscription subscription;
switch (threadOption)
{
case ThreadOption.PublisherThread:
subscription = new EventSubscription(actionReference);
break;
case ThreadOption.BackgroundThread:
subscription = new BackgroundEventSubscription(actionReference);
break;
case ThreadOption.UIThread:
subscription = new ThreadContextEventSubscription(actionReference, threadContext);
break;
default:
subscription = new EventSubscription(actionReference);
break;
}

return InternalSubscribe(subscription);

}
}

public class ThreadContextEventSubscription : EventSubscription
{
private readonly IThreadContext _threadContext;
public ThreadContextEventSubscription(IDelegateReference actionReference, IThreadContext threadContext) : base(actionReference)
{
_threadContext = threadContext;
}

public override void InvokeAction(Action action) => _threadContext.RunOnMain(action);
}
6 changes: 2 additions & 4 deletions DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,12 @@ public static void AddDUI<TThreadContext, TDocumentStore>(this IServiceCollectio
serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetAssembly(typeof(IdleCallManager)));
serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetAssembly(typeof(IServerTransportFactory)));
serviceCollection.AddSingleton<ISpeckleEventAggregator>(sp => new SpeckleEventAggregator(sp));
}

public static void RegisterTopLevelExceptionHandler(this IServiceCollection serviceCollection)
{
serviceCollection.AddSingleton<IBinding, TopLevelExceptionHandlerBinding>(sp =>
sp.GetRequiredService<TopLevelExceptionHandlerBinding>()
);
serviceCollection.AddSingleton<TopLevelExceptionHandlerBinding>();
serviceCollection.AddSingleton<ITopLevelExceptionHandler>();
serviceCollection.AddSingleton<ITopLevelExceptionHandler, TopLevelExceptionHandler>();
serviceCollection.AddTransient<ExceptionEvent>();
}
}
Loading

0 comments on commit 8e3b1da

Please sign in to comment.