From bb0faaa847bb27a3727b5bf035e683a2a0bb8264 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 28 Nov 2024 16:29:39 +0000 Subject: [PATCH 01/16] Use EventAggregator to decouple exception handler and UI --- .../Bindings/ArcGISSelectionBinding.cs | 5 +- .../Bindings/ArcGISSendBinding.cs | 9 +- .../Bindings/BasicConnectorBinding.cs | 4 +- .../packages.lock.json | 6 + .../packages.lock.json | 6 + .../packages.lock.json | 6 + .../packages.lock.json | 6 + .../packages.lock.json | 6 + .../Bindings/AutocadBasicConnectorBinding.cs | 3 +- .../Bindings/AutocadSelectionBinding.cs | 4 +- .../Bindings/AutocadSendBaseBinding.cs | 3 +- .../Bindings/AutocadSendBinding.cs | 2 + .../packages.lock.json | 6 + .../packages.lock.json | 6 + .../packages.lock.json | 6 + .../packages.lock.json | 6 + .../Bindings/Civil3dSendBinding.cs | 2 + .../packages.lock.json | 6 + .../packages.lock.json | 6 + .../packages.lock.json | 6 + .../packages.lock.json | 6 + .../Bindings/BasicConnectorBindingRevit.cs | 5 +- .../Bindings/RevitSendBinding.cs | 4 +- .../Bindings/SelectionBinding.cs | 3 +- .../packages.lock.json | 6 + .../packages.lock.json | 6 + .../Bindings/RhinoBasicConnectorBinding.cs | 5 +- .../Bindings/RhinoSendBinding.cs | 5 +- .../packages.lock.json | 6 + .../packages.lock.json | 6 + .../Bindings/TeklaBasicConnectorBinding.cs | 3 +- .../packages.lock.json | 6 + .../packages.lock.json | 6 + .../packages.lock.json | 6 + .../Bridge/TopLevelExceptionHandlerTests.cs | 49 ++++---- .../packages.lock.json | 6 + .../packages.lock.json | 12 ++ .../Bindings/OperationProgressManager.cs | 4 +- .../TopLevelExceptionHandlerBinding.cs | 4 - .../Bridge/BrowserBridge.cs | 20 +++- .../Bridge/IBrowserBridge.cs | 2 - .../Bridge/TopLevelExceptionHandler.cs | 109 +++++++++++++----- .../ContainerRegistration.cs | 5 +- .../Speckle.Connectors.DUI.csproj | 1 + .../Speckle.Connectors.DUI/packages.lock.json | 6 + Directory.Packages.props | 3 +- 46 files changed, 299 insertions(+), 99 deletions(-) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSelectionBinding.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSelectionBinding.cs index d243d12b7..239ea1115 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSelectionBinding.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSelectionBinding.cs @@ -12,15 +12,14 @@ public class ArcGISSelectionBinding : ISelectionBinding public string Name => "selectionBinding"; public IBrowserBridge Parent { get; } - public ArcGISSelectionBinding(IBrowserBridge parent, MapMembersUtils mapMemberUtils) + public ArcGISSelectionBinding(IBrowserBridge parent, MapMembersUtils mapMemberUtils, ITopLevelExceptionHandler topLevelExceptionHandler) { _mapMemberUtils = mapMemberUtils; Parent = parent; - var topLevelHandler = parent.TopLevelExceptionHandler; // example: https://github.com/Esri/arcgis-pro-sdk-community-samples/blob/master/Map-Authoring/QueryBuilderControl/DefinitionQueryDockPaneViewModel.cs // MapViewEventArgs args = new(MapView.Active); - TOCSelectionChangedEvent.Subscribe(_ => topLevelHandler.CatchUnhandled(OnSelectionChanged), true); + TOCSelectionChangedEvent.Subscribe(_ => topLevelExceptionHandler.CatchUnhandled(OnSelectionChanged), true); } private void OnSelectionChanged() diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs index 7082ee687..288b90c9d 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs @@ -66,6 +66,7 @@ public ArcGISSendBinding( IOperationProgressManager operationProgressManager, ILogger logger, IArcGISConversionSettingsFactory arcGisConversionSettingsFactory, + ITopLevelExceptionHandler topLevelExceptionHandler, MapMembersUtils mapMemberUtils ) { @@ -76,7 +77,7 @@ MapMembersUtils mapMemberUtils _sendConversionCache = sendConversionCache; _operationProgressManager = operationProgressManager; _logger = logger; - _topLevelExceptionHandler = parent.TopLevelExceptionHandler; + _topLevelExceptionHandler = topLevelExceptionHandler; _arcGISConversionSettingsFactory = arcGisConversionSettingsFactory; _mapMemberUtils = mapMemberUtils; @@ -190,7 +191,7 @@ private void SubscribeToAnyDataSourceChange(Table layerTable) { RowCreatedEvent.Subscribe( (args) => - Parent.TopLevelExceptionHandler.FireAndForget(async () => + _topLevelExceptionHandler.FireAndForget(async () => { await OnRowChanged(args).ConfigureAwait(false); }), @@ -198,7 +199,7 @@ private void SubscribeToAnyDataSourceChange(Table layerTable) ); RowChangedEvent.Subscribe( (args) => - Parent.TopLevelExceptionHandler.FireAndForget(async () => + _topLevelExceptionHandler.FireAndForget(async () => { await OnRowChanged(args).ConfigureAwait(false); }), @@ -206,7 +207,7 @@ private void SubscribeToAnyDataSourceChange(Table layerTable) ); RowDeletedEvent.Subscribe( (args) => - Parent.TopLevelExceptionHandler.FireAndForget(async () => + _topLevelExceptionHandler.FireAndForget(async () => { await OnRowChanged(args).ConfigureAwait(false); }), diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs index 89f04d1f6..5744735a9 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs @@ -21,7 +21,7 @@ public class BasicConnectorBinding : IBasicConnectorBinding private readonly DocumentModelStore _store; private readonly ISpeckleApplication _speckleApplication; - public BasicConnectorBinding(DocumentModelStore store, IBrowserBridge parent, ISpeckleApplication speckleApplication) + public BasicConnectorBinding(DocumentModelStore store, IBrowserBridge parent, ISpeckleApplication speckleApplication, ITopLevelExceptionHandler topLevelExceptionHandler) { _store = store; _speckleApplication = speckleApplication; @@ -29,7 +29,7 @@ public BasicConnectorBinding(DocumentModelStore store, IBrowserBridge parent, IS Commands = new BasicConnectorBindingCommands(parent); _store.DocumentChanged += (_, _) => - parent.TopLevelExceptionHandler.FireAndForget(async () => + topLevelExceptionHandler.FireAndForget(async () => { await Commands.NotifyDocumentChanged().ConfigureAwait(false); }); diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json index 5f273fe0c..f04d83729 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json @@ -166,6 +166,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -240,6 +245,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json index 90cb7fe9a..4927a144b 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json @@ -164,6 +164,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -273,6 +278,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json index 5ce5caae0..61597c899 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json @@ -164,6 +164,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -273,6 +278,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json index c12eb3cba..9cc4fdf0f 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json @@ -164,6 +164,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -273,6 +278,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json index 94d9d3057..3b2f4305a 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json @@ -155,6 +155,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -229,6 +234,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs index 552c43aaf..12d69566e 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs @@ -31,6 +31,7 @@ public AutocadBasicConnectorBinding( IAccountManager accountManager, ISpeckleApplication speckleApplication, ILogger logger, + ITopLevelExceptionHandler topLevelExceptionHandler, IThreadContext threadContext ) { @@ -40,7 +41,7 @@ IThreadContext threadContext _speckleApplication = speckleApplication; Commands = new BasicConnectorBindingCommands(parent); _store.DocumentChanged += (_, _) => - parent.TopLevelExceptionHandler.FireAndForget(async () => + topLevelExceptionHandler.FireAndForget(async () => { await Commands.NotifyDocumentChanged().ConfigureAwait(false); }); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs index 0af057595..d323156f0 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs @@ -18,9 +18,9 @@ public class AutocadSelectionBinding : ISelectionBinding public IBrowserBridge Parent { get; } - public AutocadSelectionBinding(IBrowserBridge parent, IThreadContext threadContext) + public AutocadSelectionBinding(IBrowserBridge parent, IThreadContext threadContext, ITopLevelExceptionHandler topLevelExceptionHandler) { - _topLevelExceptionHandler = parent.TopLevelExceptionHandler; + _topLevelExceptionHandler = topLevelExceptionHandler; Parent = parent; _threadContext = threadContext; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs index cf2a9b659..6aa6756b0 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs @@ -60,6 +60,7 @@ protected AutocadSendBaseBinding( IOperationProgressManager operationProgressManager, ILogger logger, ISpeckleApplication speckleApplication, + ITopLevelExceptionHandler topLevelExceptionHandler, IThreadContext threadContext ) { @@ -73,7 +74,7 @@ IThreadContext threadContext _logger = logger; _speckleApplication = speckleApplication; _threadContext = threadContext; - _topLevelExceptionHandler = parent.TopLevelExceptionHandler; + _topLevelExceptionHandler =topLevelExceptionHandler; Parent = parent; Commands = new SendBindingUICommands(parent); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs index ddd5c223c..65b14ab1a 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs @@ -30,6 +30,7 @@ public AutocadSendBinding( ILogger logger, IAutocadConversionSettingsFactory autocadConversionSettingsFactory, ISpeckleApplication speckleApplication, + ITopLevelExceptionHandler topLevelExceptionHandler, IThreadContext threadContext ) : base( @@ -43,6 +44,7 @@ IThreadContext threadContext operationProgressManager, logger, speckleApplication, + topLevelExceptionHandler, threadContext ) { diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json index f32ba4a78..6d44b1c6b 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json @@ -173,6 +173,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -282,6 +287,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json index 26e3bfefb..d30ee8ee2 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json @@ -173,6 +173,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -282,6 +287,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json index e3fa8c79f..5474ff59a 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json @@ -173,6 +173,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -282,6 +287,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json index 7f9f5b453..bc67aa30d 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json @@ -164,6 +164,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -238,6 +243,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs index 4b26c74ef..57a120595 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs @@ -34,6 +34,7 @@ public Civil3dSendBinding( ICivil3dConversionSettingsFactory civil3dConversionSettingsFactory, IAutocadConversionSettingsFactory autocadConversionSettingsFactory, ISpeckleApplication speckleApplication, + ITopLevelExceptionHandler topLevelExceptionHandler, IThreadContext threadContext ) : base( @@ -47,6 +48,7 @@ IThreadContext threadContext operationProgressManager, logger, speckleApplication, + topLevelExceptionHandler, threadContext ) { diff --git a/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json index 647bacc38..9e9b70a59 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json @@ -192,6 +192,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -301,6 +306,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json index d7f833c1e..07db1b489 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json @@ -192,6 +192,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -301,6 +306,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json index 6e34d1d52..720697d9d 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json @@ -192,6 +192,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -301,6 +306,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json index 023ab26c3..c595be280 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json @@ -177,6 +177,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -251,6 +256,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs index 6691eb77b..0e7805b76 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs @@ -26,7 +26,8 @@ public BasicConnectorBindingRevit( DocumentModelStore store, IBrowserBridge parent, RevitContext revitContext, - ISpeckleApplication speckleApplication + ISpeckleApplication speckleApplication, + ITopLevelExceptionHandler topLevelExceptionHandler ) { Name = "baseBinding"; @@ -38,7 +39,7 @@ ISpeckleApplication speckleApplication // POC: event binding? _store.DocumentChanged += (_, _) => - parent.TopLevelExceptionHandler.FireAndForget(async () => + topLevelExceptionHandler.FireAndForget(async () => { await Commands.NotifyDocumentChanged().ConfigureAwait(false); }); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs index 48cd80243..d36a240af 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs @@ -59,7 +59,8 @@ public RevitSendBinding( ILogger logger, ElementUnpacker elementUnpacker, IRevitConversionSettingsFactory revitConversionSettingsFactory, - ISpeckleApplication speckleApplication + ISpeckleApplication speckleApplication, + ITopLevelExceptionHandler topLevelExceptionHandler ) : base("sendBinding", store, bridge, revitContext) { @@ -73,7 +74,6 @@ ISpeckleApplication speckleApplication _elementUnpacker = elementUnpacker; _revitConversionSettingsFactory = revitConversionSettingsFactory; _speckleApplication = speckleApplication; - var topLevelExceptionHandler = Parent.TopLevelExceptionHandler; Commands = new SendBindingUICommands(bridge); // TODO expiry events diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SelectionBinding.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SelectionBinding.cs index eabb03f7f..a5903928f 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SelectionBinding.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SelectionBinding.cs @@ -17,6 +17,7 @@ public SelectionBinding( RevitContext revitContext, DocumentModelStore store, IAppIdleManager revitIdleManager, + ITopLevelExceptionHandler topLevelExceptionHandler, IBrowserBridge parent ) : base("selectionBinding", store, parent, revitContext) @@ -24,7 +25,7 @@ IBrowserBridge parent #if REVIT2022 // NOTE: getting the selection data should be a fast function all, even for '000s of elements - and having a timer hitting it every 1s is ok. _selectionTimer = new System.Timers.Timer(1000); - _selectionTimer.Elapsed += (_, _) => parent.TopLevelExceptionHandler.CatchUnhandled(OnSelectionChanged); + _selectionTimer.Elapsed += (_, _) => topLevelExceptionHandler.CatchUnhandled(OnSelectionChanged); _selectionTimer.Start(); #else diff --git a/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json b/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json index 4ad0873ae..fcb6d4454 100644 --- a/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json +++ b/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json @@ -173,6 +173,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -282,6 +287,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json b/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json index 5c61db061..493e3f93c 100644 --- a/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json +++ b/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json @@ -173,6 +173,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -282,6 +287,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoBasicConnectorBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoBasicConnectorBinding.cs index 432c2c81f..0cf61e606 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoBasicConnectorBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoBasicConnectorBinding.cs @@ -26,7 +26,8 @@ public RhinoBasicConnectorBinding( DocumentModelStore store, IBrowserBridge parent, ISendConversionCache sendConversionCache, - ISpeckleApplication speckleApplication + ISpeckleApplication speckleApplication, + ITopLevelExceptionHandler topLevelExceptionHandler ) { _store = store; @@ -36,7 +37,7 @@ ISpeckleApplication speckleApplication Commands = new BasicConnectorBindingCommands(parent); _store.DocumentChanged += (_, _) => - parent.TopLevelExceptionHandler.FireAndForget(async () => + topLevelExceptionHandler.FireAndForget(async () => { await Commands.NotifyDocumentChanged().ConfigureAwait(false); // Note: this prevents scaling issues when copy-pasting from one rhino doc to another in the same session. diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs index 1d4e454b8..36a90a8c2 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs @@ -64,7 +64,8 @@ public RhinoSendBinding( ILogger logger, IRhinoConversionSettingsFactory rhinoConversionSettingsFactory, ISpeckleApplication speckleApplication, - ISdkActivityFactory activityFactory + ISdkActivityFactory activityFactory, + ITopLevelExceptionHandler topLevelExceptionHandler ) { _store = store; @@ -77,7 +78,7 @@ ISdkActivityFactory activityFactory _logger = logger; _rhinoConversionSettingsFactory = rhinoConversionSettingsFactory; _speckleApplication = speckleApplication; - _topLevelExceptionHandler = parent.TopLevelExceptionHandler.Parent.TopLevelExceptionHandler; + _topLevelExceptionHandler = topLevelExceptionHandler; Parent = parent; Commands = new SendBindingUICommands(parent); // POC: Commands are tightly coupled with their bindings, at least for now, saves us injecting a factory. _activityFactory = activityFactory; diff --git a/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json b/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json index 26ec29612..a895c9f4a 100644 --- a/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json +++ b/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json @@ -212,6 +212,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -341,6 +346,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json b/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json index 3225e90b7..63ac3df21 100644 --- a/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json +++ b/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json @@ -231,6 +231,11 @@ "resolved": "0.11.4", "contentHash": "IC1h5g0NeJGHIUgzM1P82ld57knhP0IcQfrYITDPXlNpMYGUrsG5TxuaWTjaeqDNQMBDNZkB8L0rBnwsY6JHuQ==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -422,6 +427,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaBasicConnectorBinding.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaBasicConnectorBinding.cs index bc1449c7c..60f3f13a9 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaBasicConnectorBinding.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaBasicConnectorBinding.cs @@ -25,6 +25,7 @@ public TeklaBasicConnectorBinding( ISpeckleApplication speckleApplication, DocumentModelStore store, ILogger logger, + ITopLevelExceptionHandler topLevelExceptionHandler, TSM.Model model ) { @@ -35,7 +36,7 @@ TSM.Model model _model = model; Commands = new BasicConnectorBindingCommands(parent); _store.DocumentChanged += (_, _) => - parent.TopLevelExceptionHandler.FireAndForget(async () => + topLevelExceptionHandler.FireAndForget(async () => { await Commands.NotifyDocumentChanged().ConfigureAwait(false); }); diff --git a/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json b/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json index 77afeebe8..cfd016d4a 100644 --- a/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json +++ b/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json @@ -164,6 +164,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -273,6 +278,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json b/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json index 08ccad09b..2c553583f 100644 --- a/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json +++ b/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json @@ -155,6 +155,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -229,6 +234,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json b/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json index 247926a4a..3bc6b830d 100644 --- a/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json +++ b/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json @@ -164,6 +164,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -238,6 +243,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs b/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs index 8ba16dc14..674dbd850 100644 --- a/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs +++ b/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; -using Speckle.Connectors.DUI.Bindings; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bridge; using Speckle.Testing; @@ -14,8 +14,8 @@ public class TopLevelExceptionHandlerTests : MoqTest public void CatchUnhandledAction_Happy() { var logger = Create>(MockBehavior.Loose); - var bridge = Create(); - var sut = new TopLevelExceptionHandler(logger.Object, bridge.Object); + var eventAggregator = Create(); + var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); sut.CatchUnhandled(() => { }); } @@ -24,13 +24,12 @@ public void CatchUnhandledAction_Happy() public void CatchUnhandledAction_Exception() { var logger = Create>(MockBehavior.Loose); - var bridge = Create(); + var eventAggregator = Create(); - bridge - .Setup(x => x.Send(BasicConnectorBindingCommands.SET_GLOBAL_NOTIFICATION, It.IsAny(), default)) - .Returns(Task.CompletedTask); + eventAggregator.Setup(x => x.GetEvent()) + .Returns(new ExceptionEvent(Create().Object)); - var sut = new TopLevelExceptionHandler(logger.Object, bridge.Object); + var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); sut.CatchUnhandled(() => throw new InvalidOperationException()); } @@ -40,8 +39,8 @@ public void CatchUnhandledFunc_Happy() { var val = 2; var logger = Create>(MockBehavior.Loose); - var bridge = Create(); - var sut = new TopLevelExceptionHandler(logger.Object, bridge.Object); + var eventAggregator = Create(); + var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); var returnVal = sut.CatchUnhandled(() => val); returnVal.Value.Should().Be(val); @@ -53,13 +52,12 @@ public void CatchUnhandledFunc_Happy() public void CatchUnhandledFunc_Exception() { var logger = Create>(MockBehavior.Loose); - var bridge = Create(); + var eventAggregator = Create(); - bridge - .Setup(x => x.Send(BasicConnectorBindingCommands.SET_GLOBAL_NOTIFICATION, It.IsAny(), default)) - .Returns(Task.CompletedTask); + eventAggregator.Setup(x => x.GetEvent()) + .Returns(new ExceptionEvent(Create().Object)); - var sut = new TopLevelExceptionHandler(logger.Object, bridge.Object); + var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); var returnVal = sut.CatchUnhandled((Func)(() => throw new InvalidOperationException())); returnVal.Value.Should().BeNull(); @@ -71,8 +69,8 @@ public void CatchUnhandledFunc_Exception() public void CatchUnhandledFunc_Exception_Fatal() { var logger = Create>(MockBehavior.Loose); - var bridge = Create(); - var sut = new TopLevelExceptionHandler(logger.Object, bridge.Object); + var eventAggregator = Create(); + var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); var exception = Assert.Throws( () => sut.CatchUnhandled(new Func(() => throw new AppDomainUnloadedException())) @@ -85,8 +83,8 @@ public async Task CatchUnhandledFuncAsync_Happy() { var val = 2; var logger = Create>(MockBehavior.Loose); - var bridge = Create(); - var sut = new TopLevelExceptionHandler(logger.Object, bridge.Object); + var eventAggregator = Create(); + var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); var returnVal = await sut.CatchUnhandledAsync(() => Task.FromResult(val)); returnVal.Value.Should().Be(val); @@ -98,13 +96,12 @@ public async Task CatchUnhandledFuncAsync_Happy() public async Task CatchUnhandledFuncAsync_Exception() { var logger = Create>(MockBehavior.Loose); - var bridge = Create(); + var eventAggregator = Create(); - bridge - .Setup(x => x.Send(BasicConnectorBindingCommands.SET_GLOBAL_NOTIFICATION, It.IsAny(), default)) - .Returns(Task.CompletedTask); + eventAggregator.Setup(x => x.GetEvent()) + .Returns(new ExceptionEvent(Create().Object)); - var sut = new TopLevelExceptionHandler(logger.Object, bridge.Object); + var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); var returnVal = await sut.CatchUnhandledAsync(new Func>(() => throw new InvalidOperationException())); returnVal.Value.Should().BeNull(); @@ -116,8 +113,8 @@ public async Task CatchUnhandledFuncAsync_Exception() public void CatchUnhandledFuncAsync_Exception_Fatal() { var logger = Create>(MockBehavior.Loose); - var bridge = Create(); - var sut = new TopLevelExceptionHandler(logger.Object, bridge.Object); + var eventAggregator = Create(); + var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); var exception = Assert.ThrowsAsync( async () => await sut.CatchUnhandledAsync(new Func>(() => throw new AppDomainUnloadedException())) diff --git a/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json b/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json index 0b906a217..9b95cfa6d 100644 --- a/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json +++ b/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json @@ -236,6 +236,11 @@ "resolved": "13.0.1", "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -333,6 +338,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json b/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json index 73b4c347b..5466b56da 100644 --- a/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json +++ b/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json @@ -164,6 +164,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -273,6 +278,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -500,6 +506,11 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Prism.Events": { + "type": "Transitive", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -574,6 +585,7 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", + "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" diff --git a/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs b/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs index 992aaf669..a0da34e8b 100644 --- a/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs +++ b/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs @@ -11,7 +11,7 @@ namespace Speckle.Connectors.DUI.Bindings; /// This class requires a specific bridge in its binding, so registering it will create random bridge which we don't want to. /// [GenerateAutoInterface] -public class OperationProgressManager : IOperationProgressManager +public class OperationProgressManager(ITopLevelExceptionHandler topLevelExceptionHandler) : IOperationProgressManager { private class NonUIThreadProgress(Action handler) : IProgress { @@ -30,7 +30,7 @@ CancellationToken cancellationToken ) { var progress = new NonUIThreadProgress(args => - bridge.TopLevelExceptionHandler.FireAndForget( + topLevelExceptionHandler.FireAndForget( () => SetModelProgress( bridge, diff --git a/DUI3/Speckle.Connectors.DUI/Bindings/TopLevelExceptionHandlerBinding.cs b/DUI3/Speckle.Connectors.DUI/Bindings/TopLevelExceptionHandlerBinding.cs index 617722d69..2fec4a7ca 100644 --- a/DUI3/Speckle.Connectors.DUI/Bindings/TopLevelExceptionHandlerBinding.cs +++ b/DUI3/Speckle.Connectors.DUI/Bindings/TopLevelExceptionHandlerBinding.cs @@ -2,10 +2,6 @@ namespace Speckle.Connectors.DUI.Bindings; -/// -/// Simple binding that can be injected into non- services to get access to the -/// -/// public sealed class TopLevelExceptionHandlerBinding(IBrowserBridge parent) : IBinding { public string Name => "topLevelExceptionHandlerBinding"; diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 9249aa255..f7514e281 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -27,7 +27,9 @@ public sealed class BrowserBridge : IBrowserBridge /// private readonly ConcurrentDictionary _resultsStore = new(); - public ITopLevelExceptionHandler TopLevelExceptionHandler { get; } + + private readonly ITopLevelExceptionHandler _topLevelExceptionHandler; + private readonly ISpeckleEventAggregator _eventAggregator; private readonly IThreadContext _threadContext; private readonly IThreadOptions _threadOptions; @@ -60,18 +62,24 @@ public BrowserBridge( IThreadContext threadContext, IJsonSerializer jsonSerializer, ILogger logger, - ILogger topLogger, IBrowserScriptExecutor browserScriptExecutor, - IThreadOptions threadOptions - ) + IThreadOptions threadOptions, ISpeckleEventAggregator eventAggregator, ITopLevelExceptionHandler topLevelExceptionHandler) { _threadContext = threadContext; _jsonSerializer = jsonSerializer; _logger = logger; - TopLevelExceptionHandler = new TopLevelExceptionHandler(topLogger, this); // Capture the main thread's SynchronizationContext _browserScriptExecutor = browserScriptExecutor; _threadOptions = threadOptions; + _eventAggregator = eventAggregator; + _topLevelExceptionHandler = topLevelExceptionHandler; + eventAggregator.GetEvent().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) @@ -108,7 +116,7 @@ public void RunMethod(string methodName, string requestId, string methodArgs) => _threadContext.RunOnThreadAsync( async () => { - var task = await TopLevelExceptionHandler + var task = await _topLevelExceptionHandler .CatchUnhandledAsync(async () => { var result = await ExecuteMethod(methodName, methodArgs).ConfigureAwait(false); diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs index f968bf3ef..b4232f766 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs @@ -39,6 +39,4 @@ public interface IBrowserBridge /// Bridge was not initialized with a binding public Task Send(string eventName, T data, CancellationToken cancellationToken = default) where T : class; - - public ITopLevelExceptionHandler TopLevelExceptionHandler { get; } } diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs index 569440a4e..1c5fb6397 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs @@ -1,8 +1,7 @@ using Microsoft.Extensions.Logging; -using Speckle.Connectors.DUI.Bindings; +using Speckle.Connectors.Common.Threading; using Speckle.InterfaceGenerator; using Speckle.Sdk; -using Speckle.Sdk.Models.Extensions; namespace Speckle.Connectors.DUI.Bridge; @@ -23,15 +22,15 @@ namespace Speckle.Connectors.DUI.Bridge; public sealed class TopLevelExceptionHandler : ITopLevelExceptionHandler { private readonly ILogger _logger; - public IBrowserBridge Parent { get; } + private readonly ISpeckleEventAggregator _eventAggregator; public string Name => nameof(TopLevelExceptionHandler); private const string UNHANDLED_LOGGER_TEMPLATE = "An unhandled Exception occured"; - internal TopLevelExceptionHandler(ILogger logger, IBrowserBridge bridge) + internal TopLevelExceptionHandler(ILogger logger, ISpeckleEventAggregator eventAggregator) { _logger = logger; - Parent = bridge; + _eventAggregator = eventAggregator; } /// @@ -70,13 +69,7 @@ public async Task CatchUnhandledAsync(Func function) catch (Exception ex) when (!ex.IsFatal()) { _logger.LogError(ex, UNHANDLED_LOGGER_TEMPLATE); - await SetGlobalNotification( - ToastNotificationType.DANGER, - "Unhandled Exception Occured", - ex.ToFormattedString(), - false - ) - .ConfigureAwait(false); + _eventAggregator.GetEvent().Publish(ex); return new(ex); } } @@ -99,13 +92,7 @@ public async Task> CatchUnhandledAsync(Func> function) catch (Exception ex) when (!ex.IsFatal()) { _logger.LogError(ex, UNHANDLED_LOGGER_TEMPLATE); - await SetGlobalNotification( - ToastNotificationType.DANGER, - "Unhandled Exception Occured", - ex.ToFormattedString(), - false - ) - .ConfigureAwait(false); + _eventAggregator.GetEvent().Publish(ex); return new(ex); } } @@ -126,18 +113,76 @@ await SetGlobalNotification( /// /// public async void FireAndForget(Func function) => await CatchUnhandledAsync(function).ConfigureAwait(false); +} + +public interface ISpeckleEventAggregator +{ + TEventType GetEvent() where TEventType : EventBase; +} +public class SpeckleEventAggregator : ISpeckleEventAggregator +{ + private readonly IServiceProvider _serviceProvider; + + + private readonly Dictionary _events = new(); + + public SpeckleEventAggregator(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public TEventType GetEvent() 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(threadContext); + +public class SpeckleEvent(IThreadContext threadContext) : PubSubEvent +{ + public override SubscriptionToken Subscribe(Action action, ThreadOption threadOption, bool keepSubscriberReferenceAlive, + Predicate 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; + } - private async Task SetGlobalNotification(ToastNotificationType type, string title, string message, bool autoClose) => - await Parent - .Send( - BasicConnectorBindingCommands.SET_GLOBAL_NOTIFICATION, //TODO: We could move these constants into a DUI3 constants static class - new - { - type, - title, - description = message, - autoClose - } - ) - .ConfigureAwait(false); + public override void InvokeAction(Action action) => _threadContext.RunOnMain(action); } diff --git a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs index f922d234f..8b64a90b3 100644 --- a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs +++ b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs @@ -23,6 +23,7 @@ public static void AddDUI(this IServiceCollectio serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetAssembly(typeof(IdleCallManager))); serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetAssembly(typeof(IServerTransportFactory))); + serviceCollection.AddSingleton(sp => new SpeckleEventAggregator(sp)); } public static void RegisterTopLevelExceptionHandler(this IServiceCollection serviceCollection) @@ -31,8 +32,6 @@ public static void RegisterTopLevelExceptionHandler(this IServiceCollection serv sp.GetRequiredService() ); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(c => - c.GetRequiredService().Parent.TopLevelExceptionHandler - ); + serviceCollection.AddSingleton(); } } diff --git a/DUI3/Speckle.Connectors.DUI/Speckle.Connectors.DUI.csproj b/DUI3/Speckle.Connectors.DUI/Speckle.Connectors.DUI.csproj index e2909423f..2b842c1d7 100644 --- a/DUI3/Speckle.Connectors.DUI/Speckle.Connectors.DUI.csproj +++ b/DUI3/Speckle.Connectors.DUI/Speckle.Connectors.DUI.csproj @@ -12,6 +12,7 @@ + diff --git a/DUI3/Speckle.Connectors.DUI/packages.lock.json b/DUI3/Speckle.Connectors.DUI/packages.lock.json index c3cb0647e..79ffe1039 100644 --- a/DUI3/Speckle.Connectors.DUI/packages.lock.json +++ b/DUI3/Speckle.Connectors.DUI/packages.lock.json @@ -42,6 +42,12 @@ "resolved": "1.14.1", "contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ==" }, + "Prism.Events": { + "type": "Direct", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.InterfaceGenerator": { "type": "Direct", "requested": "[0.9.6, )", diff --git a/Directory.Packages.props b/Directory.Packages.props index 04a20fc9d..9d668aa6a 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -17,6 +17,7 @@ + @@ -48,4 +49,4 @@ - + \ No newline at end of file From 8e3b1da99fdbe570504860035155e688143ae35e Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 28 Nov 2024 16:46:13 +0000 Subject: [PATCH 02/16] it's ALIVE --- .../Bindings/ArcGISSelectionBinding.cs | 6 +- .../Bindings/BasicConnectorBinding.cs | 7 +- .../ArcGISConnectorModule.cs | 2 - .../Bindings/AutocadSelectionBinding.cs | 6 +- .../Bindings/AutocadSendBaseBinding.cs | 2 +- .../DependencyInjection/SharedRegistration.cs | 2 - .../RevitConnectorModule.cs | 2 - .../Registration/ServiceRegistration.cs | 2 - .../ServiceRegistration.cs | 2 - .../Bridge/TopLevelExceptionHandlerTests.cs | 9 ++- .../Bridge/BrowserBridge.cs | 31 ++++++-- .../Bridge/SpeckleEvent.cs | 61 +++++++++++++++ .../Bridge/SpeckleEventAggregator.cs | 35 +++++++++ .../Bridge/TopLevelExceptionHandler.cs | 75 +------------------ .../ContainerRegistration.cs | 6 +- .../Operations/ReceiveOperation.cs | 33 +------- 16 files changed, 148 insertions(+), 133 deletions(-) create mode 100644 DUI3/Speckle.Connectors.DUI/Bridge/SpeckleEvent.cs create mode 100644 DUI3/Speckle.Connectors.DUI/Bridge/SpeckleEventAggregator.cs diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSelectionBinding.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSelectionBinding.cs index 239ea1115..180156939 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSelectionBinding.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSelectionBinding.cs @@ -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; diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs index 5744735a9..627ab22d0 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs @@ -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; diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs index 1908a7372..6af5dd36a 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs @@ -34,8 +34,6 @@ public static void AddArcGIS(this IServiceCollection serviceCollection) serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); - serviceCollection.RegisterTopLevelExceptionHandler(); - serviceCollection.AddSingleton(sp => sp.GetRequiredService()); serviceCollection.AddSingleton(); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs index d323156f0..0d15f1501 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs @@ -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; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs index 6aa6756b0..77048c950 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs @@ -74,7 +74,7 @@ IThreadContext threadContext _logger = logger; _speckleApplication = speckleApplication; _threadContext = threadContext; - _topLevelExceptionHandler =topLevelExceptionHandler; + _topLevelExceptionHandler = topLevelExceptionHandler; Parent = parent; Commands = new SendBindingUICommands(parent); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs index f264e63d2..7158cdb49 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs @@ -59,8 +59,6 @@ public static void AddAutocadBase(this IServiceCollection serviceCollection) serviceCollection.AddSingleton(sp => sp.GetRequiredService()); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); - - serviceCollection.RegisterTopLevelExceptionHandler(); } public static void LoadSend(this IServiceCollection serviceCollection) diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs index b719cc2d4..59dc9da5f 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs @@ -43,8 +43,6 @@ public static void AddRevit(this IServiceCollection serviceCollection) serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); - serviceCollection.RegisterTopLevelExceptionHandler(); - serviceCollection.AddSingleton(sp => sp.GetRequiredService()); serviceCollection.AddSingleton(); diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs index a5ad1c12d..88c7d03da 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs @@ -45,8 +45,6 @@ public static void AddRhino(this IServiceCollection serviceCollection) serviceCollection.AddSingleton(); // POC: Easier like this for now, should be cleaned up later serviceCollection.AddSingleton(); - serviceCollection.RegisterTopLevelExceptionHandler(); - serviceCollection.AddSingleton(sp => sp.GetRequiredService()); serviceCollection.AddSingleton(); diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs index d9d42e0cf..e7f5f0620 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs @@ -42,8 +42,6 @@ public static IServiceCollection AddTekla(this IServiceCollection services) services.AddSingleton(); services.AddSingleton(); - services.RegisterTopLevelExceptionHandler(); - services.AddSingleton(sp => sp.GetRequiredService()); services.AddSingleton(); services.AddSingleton(); diff --git a/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs b/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs index 674dbd850..b4224e3a6 100644 --- a/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs +++ b/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs @@ -26,7 +26,8 @@ public void CatchUnhandledAction_Exception() var logger = Create>(MockBehavior.Loose); var eventAggregator = Create(); - eventAggregator.Setup(x => x.GetEvent()) + eventAggregator + .Setup(x => x.GetEvent()) .Returns(new ExceptionEvent(Create().Object)); var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); @@ -54,7 +55,8 @@ public void CatchUnhandledFunc_Exception() var logger = Create>(MockBehavior.Loose); var eventAggregator = Create(); - eventAggregator.Setup(x => x.GetEvent()) + eventAggregator + .Setup(x => x.GetEvent()) .Returns(new ExceptionEvent(Create().Object)); var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); @@ -98,7 +100,8 @@ public async Task CatchUnhandledFuncAsync_Exception() var logger = Create>(MockBehavior.Loose); var eventAggregator = Create(); - eventAggregator.Setup(x => x.GetEvent()) + eventAggregator + .Setup(x => x.GetEvent()) .Returns(new ExceptionEvent(Create().Object)); var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index f7514e281..35da721ea 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -63,7 +63,10 @@ public BrowserBridge( IJsonSerializer jsonSerializer, ILogger logger, IBrowserScriptExecutor browserScriptExecutor, - IThreadOptions threadOptions, ISpeckleEventAggregator eventAggregator, ITopLevelExceptionHandler topLevelExceptionHandler) + IThreadOptions threadOptions, + ISpeckleEventAggregator eventAggregator, + ITopLevelExceptionHandler topLevelExceptionHandler + ) { _threadContext = threadContext; _jsonSerializer = jsonSerializer; @@ -73,13 +76,25 @@ public BrowserBridge( _threadOptions = threadOptions; _eventAggregator = eventAggregator; _topLevelExceptionHandler = topLevelExceptionHandler; - eventAggregator.GetEvent().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() + .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) diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/SpeckleEvent.cs b/DUI3/Speckle.Connectors.DUI/Bridge/SpeckleEvent.cs new file mode 100644 index 000000000..f97c86068 --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Bridge/SpeckleEvent.cs @@ -0,0 +1,61 @@ +using Speckle.Connectors.Common.Threading; + +namespace Speckle.Connectors.DUI.Bridge; + +public class ExceptionEvent(IThreadContext threadContext) : SpeckleEvent(threadContext); + +public class ThreadContextEventSubscription( + IDelegateReference actionReference, + IDelegateReference filterReference, + IThreadContext threadContext +) : EventSubscription(actionReference, filterReference) +{ + public override void InvokeAction(Action action, T payload) => + threadContext.RunOnMain(() => action.Invoke(payload)); +} + +public class SpeckleEvent(IThreadContext threadContext) : PubSubEvent +{ + public override SubscriptionToken Subscribe( + Action action, + ThreadOption threadOption, + bool keepSubscriberReferenceAlive, + Predicate? filter + ) + { + IDelegateReference actionReference = new DelegateReference(action, keepSubscriberReferenceAlive); + IDelegateReference filterReference; + if (filter != null) + { + filterReference = new DelegateReference(filter, keepSubscriberReferenceAlive); + } + else + { + filterReference = new DelegateReference( + new Predicate( + delegate + { + return true; + } + ), + true + ); + } + EventSubscription subscription; + switch (threadOption) + { + case ThreadOption.BackgroundThread: + subscription = new BackgroundEventSubscription(actionReference, filterReference); + break; + case ThreadOption.UIThread: + subscription = new ThreadContextEventSubscription(actionReference, filterReference, threadContext); + break; + case ThreadOption.PublisherThread: + default: + subscription = new EventSubscription(actionReference, filterReference); + break; + } + + return InternalSubscribe(subscription); + } +} diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/SpeckleEventAggregator.cs b/DUI3/Speckle.Connectors.DUI/Bridge/SpeckleEventAggregator.cs new file mode 100644 index 000000000..5bd522c3c --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Bridge/SpeckleEventAggregator.cs @@ -0,0 +1,35 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Speckle.Connectors.DUI.Bridge; + +public interface ISpeckleEventAggregator +{ + TEventType GetEvent() + where TEventType : EventBase; +} + +public class SpeckleEventAggregator : ISpeckleEventAggregator +{ + private readonly IServiceProvider _serviceProvider; + + private readonly Dictionary _events = new(); + + public SpeckleEventAggregator(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public TEventType GetEvent() + 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; + } + } +} diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs index 1c5fb6397..6faf5893b 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.Logging; -using Speckle.Connectors.Common.Threading; using Speckle.InterfaceGenerator; using Speckle.Sdk; @@ -27,7 +26,7 @@ public sealed class TopLevelExceptionHandler : ITopLevelExceptionHandler private const string UNHANDLED_LOGGER_TEMPLATE = "An unhandled Exception occured"; - internal TopLevelExceptionHandler(ILogger logger, ISpeckleEventAggregator eventAggregator) + public TopLevelExceptionHandler(ILogger logger, ISpeckleEventAggregator eventAggregator) { _logger = logger; _eventAggregator = eventAggregator; @@ -114,75 +113,3 @@ public async Task> CatchUnhandledAsync(Func> function) /// public async void FireAndForget(Func function) => await CatchUnhandledAsync(function).ConfigureAwait(false); } - -public interface ISpeckleEventAggregator -{ - TEventType GetEvent() where TEventType : EventBase; -} -public class SpeckleEventAggregator : ISpeckleEventAggregator -{ - private readonly IServiceProvider _serviceProvider; - - - private readonly Dictionary _events = new(); - - public SpeckleEventAggregator(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - - public TEventType GetEvent() 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(threadContext); - -public class SpeckleEvent(IThreadContext threadContext) : PubSubEvent -{ - public override SubscriptionToken Subscribe(Action action, ThreadOption threadOption, bool keepSubscriberReferenceAlive, - Predicate 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); -} diff --git a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs index 8b64a90b3..0386cf2e6 100644 --- a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs +++ b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs @@ -24,14 +24,12 @@ public static void AddDUI(this IServiceCollectio serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetAssembly(typeof(IdleCallManager))); serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetAssembly(typeof(IServerTransportFactory))); serviceCollection.AddSingleton(sp => new SpeckleEventAggregator(sp)); - } - public static void RegisterTopLevelExceptionHandler(this IServiceCollection serviceCollection) - { serviceCollection.AddSingleton(sp => sp.GetRequiredService() ); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddTransient(); } } diff --git a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs index 4647e79fb..5c929b118 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs @@ -1,11 +1,11 @@ using Speckle.Connectors.Common.Builders; using Speckle.Connectors.Common.Threading; -using Speckle.Connectors.Logging; using Speckle.Sdk.Api; using Speckle.Sdk.Credentials; using Speckle.Sdk.Logging; using Speckle.Sdk.Models; using Speckle.Sdk.Models.Extensions; +#pragma warning disable CS9113 // Parameter is unread. namespace Speckle.Connectors.Common.Operations; @@ -20,40 +20,13 @@ public sealed class ReceiveOperation( IThreadOptions threadOptions ) { - public async Task Execute( + public Task Execute( ReceiveInfo receiveInfo, IProgress onOperationProgressed, CancellationToken cancellationToken ) { - using var execute = activityFactory.Start("Receive Operation"); - execute?.SetTag("receiveInfo", receiveInfo); - // 2 - Check account exist - Account account = accountService.GetAccountWithServerUrlFallback(receiveInfo.AccountId, receiveInfo.ServerUrl); - using Client apiClient = clientFactory.Create(account); - using var userScope = ActivityScope.SetTag(Consts.USER_ID, account.GetHashedEmail()); - - var version = await apiClient - .Version.Get(receiveInfo.SelectedVersionId, receiveInfo.ProjectId, cancellationToken) - .BackToAny(); - - var commitObject = await threadContext - .RunOnWorkerAsync(() => ReceiveData(account, version, receiveInfo, onOperationProgressed, cancellationToken)) - .BackToAny(); - - // 4 - Convert objects - HostObjectBuilderResult res = await threadContext - .RunOnThreadAsync( - () => ConvertObjects(commitObject, receiveInfo, onOperationProgressed, cancellationToken), - threadOptions.RunReceiveBuildOnMainThread - ) - .BackToAny(); - - await apiClient - .Version.Received(new(version.id, receiveInfo.ProjectId, receiveInfo.SourceApplication), cancellationToken) - .BackToAny(); - - return res; + throw new NotImplementedException("This is a placeholder for now."); } private async Task ReceiveData( From 67ddd6256c175b42b86ef7ad40642ac7be338d09 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 28 Nov 2024 16:49:43 +0000 Subject: [PATCH 03/16] regenerate locks --- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 11 +++++----- .../packages.lock.json | 22 ++++++++++--------- 22 files changed, 138 insertions(+), 115 deletions(-) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json index f04d83729..e70b0cc00 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json @@ -166,11 +166,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -302,6 +297,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json index 4927a144b..4bc86ccc3 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json @@ -164,11 +164,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -341,6 +336,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json index 61597c899..492af7cf2 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json @@ -164,11 +164,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -341,6 +336,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json index 9cc4fdf0f..2c35d813e 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json @@ -164,11 +164,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -342,6 +337,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json index 3b2f4305a..f20cf7982 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json @@ -155,11 +155,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -298,6 +293,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json index 6d44b1c6b..6fdae0349 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json @@ -173,11 +173,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -351,6 +346,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json index d30ee8ee2..002e107c1 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json @@ -173,11 +173,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -351,6 +346,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json index 5474ff59a..989ab6d6d 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json @@ -173,11 +173,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -351,6 +346,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json index bc67aa30d..9d9c8dc44 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json @@ -164,11 +164,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -308,6 +303,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json index 9e9b70a59..7f5d9a7a5 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json @@ -192,11 +192,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -356,6 +351,12 @@ "resolved": "2.2.0", "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json index 07db1b489..4c0a7c585 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json @@ -192,11 +192,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -356,6 +351,12 @@ "resolved": "2.2.0", "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json index 720697d9d..a47ee2b10 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json @@ -192,11 +192,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -356,6 +351,12 @@ "resolved": "2.2.0", "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json index c595be280..6ac5c102b 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json @@ -177,11 +177,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -319,6 +314,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json b/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json index fcb6d4454..35fb6bdcf 100644 --- a/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json +++ b/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json @@ -173,11 +173,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -350,6 +345,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json b/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json index 493e3f93c..d4a628a68 100644 --- a/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json +++ b/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json @@ -173,11 +173,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -350,6 +345,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json b/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json index a895c9f4a..9da95e5e2 100644 --- a/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json +++ b/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json @@ -212,11 +212,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -410,6 +405,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Sdk": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json b/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json index 63ac3df21..2a524f9dc 100644 --- a/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json +++ b/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json @@ -231,11 +231,6 @@ "resolved": "0.11.4", "contentHash": "IC1h5g0NeJGHIUgzM1P82ld57knhP0IcQfrYITDPXlNpMYGUrsG5TxuaWTjaeqDNQMBDNZkB8L0rBnwsY6JHuQ==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -491,6 +486,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Sdk": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json b/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json index cfd016d4a..106ef77ee 100644 --- a/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json +++ b/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json @@ -164,11 +164,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -334,6 +329,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json b/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json index 2c553583f..32f388dcd 100644 --- a/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json +++ b/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json @@ -155,11 +155,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -290,6 +285,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json b/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json index 3bc6b830d..010952a0e 100644 --- a/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json +++ b/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json @@ -164,11 +164,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -299,6 +294,12 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json b/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json index 9b95cfa6d..5c82cb3b0 100644 --- a/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json +++ b/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json @@ -236,11 +236,6 @@ "resolved": "13.0.1", "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -381,6 +376,12 @@ "resolved": "2.2.0", "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json b/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json index 5466b56da..8e0ef7b73 100644 --- a/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json +++ b/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json @@ -164,11 +164,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -314,6 +309,12 @@ "resolved": "2.2.0", "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", @@ -506,11 +507,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Prism.Events": { - "type": "Transitive", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.DoubleNumerics": { "type": "Transitive", "resolved": "4.0.1", @@ -621,6 +617,12 @@ "resolved": "2.2.0", "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" }, + "Prism.Events": { + "type": "CentralTransitive", + "requested": "[9.0.537, )", + "resolved": "9.0.537", + "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" + }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", From fded4dbc51627221cd4d2e06342a7e8355fe1c55 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Fri, 29 Nov 2024 08:32:42 +0000 Subject: [PATCH 04/16] Add Prism Evening to DUI --- .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../packages.lock.json | 7 - .../Bridge/TopLevelExceptionHandlerTests.cs | 1 + .../packages.lock.json | 7 - .../packages.lock.json | 14 -- .../Bridge/BrowserBridge.cs | 1 + .../Bridge/TopLevelExceptionHandler.cs | 1 + .../ContainerRegistration.cs | 1 + .../Eventing/BackgroundEventSubscription.cs | 44 ++++ .../Eventing/DelegateReference.cs | 95 ++++++++ .../Eventing/EventBase.cs | 212 ++++++++++++++++++ .../Eventing/EventSubscription.cs | 210 +++++++++++++++++ .../Eventing/PubSubEvent.cs | 141 ++++++++++++ .../{Bridge => Eventing}/SpeckleEvent.cs | 13 +- .../SpeckleEventAggregator.cs | 14 +- .../ThreadContextEventSubscription.cs | 13 ++ .../Speckle.Connectors.DUI.csproj | 1 - .../Speckle.Connectors.DUI/packages.lock.json | 6 - Directory.Packages.props | 1 - 37 files changed, 725 insertions(+), 190 deletions(-) create mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/BackgroundEventSubscription.cs create mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/DelegateReference.cs create mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/EventBase.cs create mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs create mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs rename DUI3/Speckle.Connectors.DUI/{Bridge => Eventing}/SpeckleEvent.cs (78%) rename DUI3/Speckle.Connectors.DUI/{Bridge => Eventing}/SpeckleEventAggregator.cs (59%) create mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/ThreadContextEventSubscription.cs diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json index e70b0cc00..5f273fe0c 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json @@ -240,7 +240,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -297,12 +296,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json index 4bc86ccc3..90cb7fe9a 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json @@ -273,7 +273,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -336,12 +335,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json index 492af7cf2..5ce5caae0 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json @@ -273,7 +273,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -336,12 +335,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json index 2c35d813e..c12eb3cba 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json @@ -273,7 +273,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -337,12 +336,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json index f20cf7982..94d9d3057 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json @@ -229,7 +229,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -293,12 +292,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json index 6fdae0349..f32ba4a78 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json @@ -282,7 +282,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -346,12 +345,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json index 002e107c1..26e3bfefb 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json @@ -282,7 +282,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -346,12 +345,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json index 989ab6d6d..e3fa8c79f 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json @@ -282,7 +282,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -346,12 +345,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json index 9d9c8dc44..7f9f5b453 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json @@ -238,7 +238,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -303,12 +302,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json index 7f5d9a7a5..647bacc38 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json @@ -301,7 +301,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -351,12 +350,6 @@ "resolved": "2.2.0", "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json index 4c0a7c585..d7f833c1e 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json @@ -301,7 +301,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -351,12 +350,6 @@ "resolved": "2.2.0", "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json index a47ee2b10..6e34d1d52 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json @@ -301,7 +301,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -351,12 +350,6 @@ "resolved": "2.2.0", "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json index 6ac5c102b..023ab26c3 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json @@ -251,7 +251,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -314,12 +313,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json b/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json index 35fb6bdcf..4ad0873ae 100644 --- a/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json +++ b/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json @@ -282,7 +282,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -345,12 +344,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json b/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json index d4a628a68..5c61db061 100644 --- a/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json +++ b/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json @@ -282,7 +282,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -345,12 +344,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json b/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json index 9da95e5e2..26ec29612 100644 --- a/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json +++ b/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json @@ -341,7 +341,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -405,12 +404,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Sdk": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json b/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json index 2a524f9dc..3225e90b7 100644 --- a/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json +++ b/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json @@ -422,7 +422,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -486,12 +485,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Sdk": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json b/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json index 106ef77ee..77afeebe8 100644 --- a/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json +++ b/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json @@ -273,7 +273,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -329,12 +328,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json b/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json index 32f388dcd..08ccad09b 100644 --- a/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json +++ b/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json @@ -229,7 +229,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -285,12 +284,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json b/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json index 010952a0e..247926a4a 100644 --- a/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json +++ b/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json @@ -238,7 +238,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -294,12 +293,6 @@ "resolved": "1.0.1938.49", "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs b/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs index b4224e3a6..b79883e08 100644 --- a/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs +++ b/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs @@ -4,6 +4,7 @@ using NUnit.Framework; using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Testing; namespace Speckle.Connectors.DUI.Tests.Bridge; diff --git a/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json b/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json index 5c82cb3b0..0b906a217 100644 --- a/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json +++ b/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json @@ -333,7 +333,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -376,12 +375,6 @@ "resolved": "2.2.0", "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json b/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json index 8e0ef7b73..73b4c347b 100644 --- a/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json +++ b/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json @@ -273,7 +273,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -309,12 +308,6 @@ "resolved": "2.2.0", "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", @@ -581,7 +574,6 @@ "type": "Project", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Prism.Events": "[9.0.537, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" @@ -617,12 +609,6 @@ "resolved": "2.2.0", "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" }, - "Prism.Events": { - "type": "CentralTransitive", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.Objects": { "type": "CentralTransitive", "requested": "[3.1.0-dev.200, )", diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 35da721ea..ba4ae963d 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging; using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Utils; using Speckle.Newtonsoft.Json; using Speckle.Sdk.Common; diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs index 6faf5893b..ad3ad993f 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Logging; +using Speckle.Connectors.DUI.Eventing; using Speckle.InterfaceGenerator; using Speckle.Sdk; diff --git a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs index 0386cf2e6..763b035a8 100644 --- a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs +++ b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs @@ -3,6 +3,7 @@ using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Models; using Speckle.Sdk; using Speckle.Sdk.Transports; diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/BackgroundEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/BackgroundEventSubscription.cs new file mode 100644 index 000000000..2352ad63d --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Eventing/BackgroundEventSubscription.cs @@ -0,0 +1,44 @@ +using Speckle.Connectors.Common.Threading; + +namespace Speckle.Connectors.DUI.Eventing; + +/// +/// Extends to invoke the delegate in a background thread. +/// +public class BackgroundEventSubscription(IDelegateReference actionReference, IThreadContext threadContext) : EventSubscription(actionReference) +{ + public override void InvokeAction(Action action) => threadContext.RunOnWorker(action); +} + + +/// + /// Extends to invoke the delegate in a background thread. + /// + /// The type to use for the generic and types. + public class BackgroundEventSubscription : EventSubscription + { + /// + /// Creates a new instance of . + /// + /// A reference to a delegate of type . + /// A reference to a delegate of type . + /// When or are . + /// When the target of is not of type , + /// or the target of is not of type . + public BackgroundEventSubscription(IDelegateReference actionReference, IDelegateReference filterReference) + : base(actionReference, filterReference) + { + } + + /// + /// Invokes the specified in an asynchronous thread by using a . + /// + /// The action to execute. + /// The payload to pass while invoking it. + public override void InvokeAction(Action action, TPayload argument) + { + //ThreadPool.QueueUserWorkItem( (o) => action(argument) ); + Task.Run(() => action(argument)); + } + } + diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/DelegateReference.cs b/DUI3/Speckle.Connectors.DUI/Eventing/DelegateReference.cs new file mode 100644 index 000000000..36d7f2943 --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Eventing/DelegateReference.cs @@ -0,0 +1,95 @@ +using System.Reflection; + +namespace Speckle.Connectors.DUI.Eventing; +public interface IDelegateReference +{ + /// + /// Gets the referenced object. + /// + /// A instance if the target is valid; otherwise . + Delegate? Target { get; } +} +public class DelegateReference : IDelegateReference +{ + private readonly Delegate? _delegate; + private readonly WeakReference _weakReference; + private readonly MethodInfo _method; + private readonly Type _delegateType; + + /// + /// Initializes a new instance of . + /// + /// The original to create a reference for. + /// If the class will create a weak reference to the delegate, allowing it to be garbage collected. Otherwise it will keep a strong reference to the target. + /// If the passed is not assignable to . + public DelegateReference(Delegate @delegate, bool keepReferenceAlive) + { + if (@delegate == null) + { + throw new ArgumentNullException(nameof(@delegate)); + } + + if (keepReferenceAlive) + { + this._delegate = @delegate; + } + else + { + _weakReference = new WeakReference(@delegate.Target); + _method = @delegate.GetMethodInfo(); + _delegateType = @delegate.GetType(); + } + } + + /// + /// Gets the (the target) referenced by the current object. + /// + /// if the object referenced by the current object has been garbage collected; otherwise, a reference to the referenced by the current object. + public Delegate? Target + { + get + { + if (_delegate != null) + { + return _delegate; + } + else + { + return TryGetDelegate(); + } + } + } + + /// + /// Checks if the (the target) referenced by the current object are equal to another . + /// This is equivalent with comparing with , only more efficient. + /// + /// The other delegate to compare with. + /// True if the target referenced by the current object are equal to . + public bool TargetEquals(Delegate @delegate) + { + if (_delegate != null) + { + return _delegate == @delegate; + } + if (@delegate == null) + { + return !_method.IsStatic && !_weakReference.IsAlive; + } + return _weakReference.Target == @delegate.Target && Equals(_method, @delegate.GetMethodInfo()); + } + + private Delegate? TryGetDelegate() + { + if (_method.IsStatic) + { + return _method.CreateDelegate(_delegateType, null); + } + object target = _weakReference.Target; + if (target != null) + { + return _method.CreateDelegate(_delegateType, target); + } + return null; + } +} diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/EventBase.cs b/DUI3/Speckle.Connectors.DUI/Eventing/EventBase.cs new file mode 100644 index 000000000..28d2ab68e --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Eventing/EventBase.cs @@ -0,0 +1,212 @@ +namespace Speckle.Connectors.DUI.Eventing; + +/// +/// Defines a base class to publish and subscribe to events. +/// +public abstract class EventBase +{ + private readonly List _subscriptions = new List(); + + /// + /// Allows the SynchronizationContext to be set by the EventAggregator for UI Thread Dispatching + /// + public SynchronizationContext SynchronizationContext { get; set; } + + /// + /// Gets the list of current subscriptions. + /// + /// The current subscribers. + protected ICollection Subscriptions => _subscriptions; + + /// + /// Adds the specified to the subscribers' collection. + /// + /// The subscriber. + /// The that uniquely identifies every subscriber. + /// + /// Adds the subscription to the internal list and assigns it a new . + /// + protected virtual SubscriptionToken InternalSubscribe(IEventSubscription eventSubscription) + { + if (eventSubscription == null) + { + throw new ArgumentNullException(nameof(eventSubscription)); + } + + eventSubscription.SubscriptionToken = new SubscriptionToken(Unsubscribe); + + lock (Subscriptions) + { + Subscriptions.Add(eventSubscription); + } + return eventSubscription.SubscriptionToken; + } + + /// + /// Calls all the execution strategies exposed by the list of . + /// + /// The arguments that will be passed to the listeners. + /// Before executing the strategies, this class will prune all the subscribers from the + /// list that return a when calling the + /// method. + protected virtual void InternalPublish(params object[] arguments) + { + List> executionStrategies = PruneAndReturnStrategies(); + foreach (var executionStrategy in executionStrategies) + { + executionStrategy(arguments); + } + } + + /// + /// Removes the subscriber matching the . + /// + /// The returned by while subscribing to the event. + public virtual void Unsubscribe(SubscriptionToken token) + { + lock (Subscriptions) + { + IEventSubscription subscription = Subscriptions.FirstOrDefault(evt => evt.SubscriptionToken == token); + if (subscription != null) + { + Subscriptions.Remove(subscription); + } + } + } + + /// + /// Returns if there is a subscriber matching . + /// + /// The returned by while subscribing to the event. + /// if there is a that matches; otherwise . + public virtual bool Contains(SubscriptionToken token) + { + lock (Subscriptions) + { + IEventSubscription subscription = Subscriptions.FirstOrDefault(evt => evt.SubscriptionToken == token); + return subscription != null; + } + } + + private List> PruneAndReturnStrategies() + { + List> returnList = new List>(); + + lock (Subscriptions) + { + for (var i = Subscriptions.Count - 1; i >= 0; i--) + { + Action? listItem = + _subscriptions[i].GetExecutionStrategy(); + + if (listItem == null) + { + // Prune from main list. Log? + _subscriptions.RemoveAt(i); + } + else + { + returnList.Add(listItem); + } + } + } + + return returnList; + } + + /// + /// Forces the PubSubEvent to remove any subscriptions that no longer have an execution strategy. + /// + public void Prune() + { + lock (Subscriptions) + { + for (var i = Subscriptions.Count - 1; i >= 0; i--) + { + if (_subscriptions[i].GetExecutionStrategy() == null) + { + _subscriptions.RemoveAt(i); + } + } + } + } +} + + public sealed class SubscriptionToken : IEquatable, IDisposable + { + private readonly Guid _token; + private Action? _unsubscribeAction; + + /// + /// Initializes a new instance of . + /// + public SubscriptionToken(Action unsubscribeAction) + { + _unsubscribeAction = unsubscribeAction; + _token = Guid.NewGuid(); + } + + /// + ///Indicates whether the current object is equal to another object of the same type. + /// + /// + /// if the current object is equal to the parameter; otherwise, . + /// + ///An object to compare with this object. + public bool Equals(SubscriptionToken? other) + { + if (other == null) + { + return false; + } + + return Equals(_token, other._token); + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(this, obj)) + { + return true; + } + + return Equals(obj as SubscriptionToken); + } + + public override int GetHashCode() + { + return _token.GetHashCode(); + } + + /// + /// Disposes the SubscriptionToken, removing the subscription from the corresponding . + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "Should never have need for a finalizer, hence no need for Dispose(bool).")] + public void Dispose() + { + // While the SubscriptionToken class implements IDisposable, in the case of weak subscriptions + // (i.e. keepSubscriberReferenceAlive set to false in the Subscribe method) it's not necessary to unsubscribe, + // as no resources should be kept alive by the event subscription. + // In such cases, if a warning is issued, it could be suppressed. + + if (this._unsubscribeAction != null) + { + this._unsubscribeAction(this); + this._unsubscribeAction = null; + } + } + } + public enum ThreadOption + { + PublisherThread, + + /// + /// The call is done on the UI thread. + /// + UIThread, + + /// + /// The call is done asynchronously on a background thread. + /// + BackgroundThread + } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs new file mode 100644 index 000000000..f0739c702 --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs @@ -0,0 +1,210 @@ +namespace Speckle.Connectors.DUI.Eventing; + +public interface IEventSubscription +{ + /// + /// Gets or sets a that identifies this . + /// + /// A token that identifies this . + SubscriptionToken SubscriptionToken { get; set; } + + /// + /// Gets the execution strategy to publish this event. + /// + /// An with the execution strategy, or if the is no longer valid. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + Action? GetExecutionStrategy(); +} + +public class EventSubscription : IEventSubscription +{ + private readonly IDelegateReference _actionReference; + + /// + /// Creates a new instance of . + /// + ///A reference to a delegate of type . + ///When or are . + ///When the target of is not of type . + public EventSubscription(IDelegateReference actionReference) + { + if (actionReference == null) + { + throw new ArgumentNullException(nameof(actionReference)); + } + + if (actionReference.Target is not System.Action) + { + throw new ArgumentException(null, nameof(actionReference)); + } + + _actionReference = actionReference; + } + + /// + /// Gets the target that is referenced by the . + /// + /// An or if the referenced target is not alive. + public Action? Action => (Action?)_actionReference.Target; + + /// + /// Gets or sets a that identifies this . + /// + /// A token that identifies this . + public SubscriptionToken SubscriptionToken { get; set; } + + /// + /// Gets the execution strategy to publish this event. + /// + /// An with the execution strategy, or if the is no longer valid. + /// + /// If is no longer valid because it was + /// garbage collected, this method will return . + /// Otherwise it will return a delegate that evaluates the and if it + /// returns will then call . The returned + /// delegate holds a hard reference to the target + /// delegates. As long as the returned delegate is not garbage collected, + /// the references delegates won't get collected either. + /// + public virtual Action? GetExecutionStrategy() + { + Action? action = this.Action; + if (action == null) + { + return null; + } + return arguments => + { + InvokeAction(action); + }; + } + + /// + /// Invokes the specified synchronously when not overridden. + /// + /// The action to execute. + /// An is thrown if is null. + public virtual void InvokeAction(Action action) + { + if (action == null) + { + throw new ArgumentNullException(nameof(action)); + } + + action(); + } +} + + + /// + /// Provides a way to retrieve a to execute an action depending + /// on the value of a second filter predicate that returns true if the action should execute. + /// + /// The type to use for the generic and types. + public class EventSubscription : IEventSubscription + { + private readonly IDelegateReference _actionReference; + private readonly IDelegateReference _filterReference; + + /// + /// Creates a new instance of . + /// + ///A reference to a delegate of type . + ///A reference to a delegate of type . + ///When or are . + ///When the target of is not of type , + ///or the target of is not of type . + public EventSubscription(IDelegateReference actionReference, IDelegateReference filterReference) + { + if (actionReference == null) + { + throw new ArgumentNullException(nameof(actionReference)); + } + + if (actionReference.Target is not Action) + { + throw new ArgumentException(null, nameof(actionReference)); + } + + if (filterReference == null) + { + throw new ArgumentNullException(nameof(filterReference)); + } + + if (filterReference.Target is not Predicate) + { + throw new ArgumentException(null, nameof(filterReference)); + } + + _actionReference = actionReference; + _filterReference = filterReference; + } + + /// + /// Gets the target that is referenced by the . + /// + /// An or if the referenced target is not alive. + public Action? Action => (Action?)_actionReference.Target; + + /// + /// Gets the target that is referenced by the . + /// + /// An or if the referenced target is not alive. + public Predicate? Filter => (Predicate?)_filterReference.Target; + + /// + /// Gets or sets a that identifies this . + /// + /// A token that identifies this . + public SubscriptionToken SubscriptionToken { get; set; } + + /// + /// Gets the execution strategy to publish this event. + /// + /// An with the execution strategy, or if the is no longer valid. + /// + /// If or are no longer valid because they were + /// garbage collected, this method will return . + /// Otherwise it will return a delegate that evaluates the and if it + /// returns will then call . The returned + /// delegate holds hard references to the and target + /// delegates. As long as the returned delegate is not garbage collected, + /// the and references delegates won't get collected either. + /// + public virtual Action? GetExecutionStrategy() + { + Action? action = this.Action; + if (action is null) + { + return null; + } + Predicate? filter = this.Filter; + return arguments => + { + TPayload argument = (TPayload)arguments[0]; + if (filter is null) + { + InvokeAction(action, argument); + }else if (filter(argument)) + { + InvokeAction(action, argument); + } + }; + } + + /// + /// Invokes the specified synchronously when not overridden. + /// + /// The action to execute. + /// The payload to pass while invoking it. + /// An is thrown if is null. + public virtual void InvokeAction(Action action, TPayload argument) + { + if (action == null) + { + throw new ArgumentNullException(nameof(action)); + } + + action(argument); + } + } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs new file mode 100644 index 000000000..e22cfe527 --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs @@ -0,0 +1,141 @@ +namespace Speckle.Connectors.DUI.Eventing; + +/// +/// Defines a class that manages publication and subscription to events. +/// +/// The type of message that will be passed to the subscribers. +public abstract class PubSubEvent : EventBase +where TPayload : notnull +{ + /// + /// Subscribes a delegate to an event that will be published on the . + /// will maintain a to the target of the supplied delegate. + /// + /// The delegate that gets executed when the event is published. + /// A that uniquely identifies the added subscription. + /// + /// The PubSubEvent collection is thread-safe. + /// + public SubscriptionToken Subscribe(Action action) + { + return Subscribe(action, ThreadOption.PublisherThread); + } + + /// + /// Subscribes a delegate to an event that will be published on the + /// + /// The delegate that gets executed when the event is raised. + /// Filter to evaluate if the subscriber should receive the event. + /// A that uniquely identifies the added subscription. + public virtual SubscriptionToken Subscribe(Action action, Predicate filter) + { + return Subscribe(action, ThreadOption.PublisherThread, false, filter); + } + + /// + /// Subscribes a delegate to an event. + /// PubSubEvent will maintain a to the Target of the supplied delegate. + /// + /// The delegate that gets executed when the event is raised. + /// Specifies on which thread to receive the delegate callback. + /// A that uniquely identifies the added subscription. + /// + /// The PubSubEvent collection is thread-safe. + /// + public SubscriptionToken Subscribe(Action action, ThreadOption threadOption) + { + return Subscribe(action, threadOption, false); + } + + /// + /// Subscribes a delegate to an event that will be published on the . + /// + /// The delegate that gets executed when the event is published. + /// When , the keeps a reference to the subscriber so it does not get garbage collected. + /// A that uniquely identifies the added subscription. + /// + /// If is set to , will maintain a to the Target of the supplied delegate. + /// If not using a WeakReference ( is ), the user must explicitly call Unsubscribe for the event when disposing the subscriber in order to avoid memory leaks or unexpected behavior. + /// + /// The PubSubEvent collection is thread-safe. + /// + public SubscriptionToken Subscribe(Action action, bool keepSubscriberReferenceAlive) + { + return Subscribe(action, ThreadOption.PublisherThread, keepSubscriberReferenceAlive); + } + + /// + /// Subscribes a delegate to an event. + /// + /// The delegate that gets executed when the event is published. + /// Specifies on which thread to receive the delegate callback. + /// When , the keeps a reference to the subscriber so it does not get garbage collected. + /// A that uniquely identifies the added subscription. + /// + /// If is set to , will maintain a to the Target of the supplied delegate. + /// If not using a WeakReference ( is ), the user must explicitly call Unsubscribe for the event when disposing the subscriber in order to avoid memory leaks or unexpected behavior. + /// + /// The PubSubEvent collection is thread-safe. + /// + public SubscriptionToken Subscribe(Action action, ThreadOption threadOption, bool keepSubscriberReferenceAlive) + { + return Subscribe(action, threadOption, keepSubscriberReferenceAlive, null); + } + + /// + /// Subscribes a delegate to an event. + /// + /// The delegate that gets executed when the event is published. + /// Specifies on which thread to receive the delegate callback. + /// When , the keeps a reference to the subscriber so it does not get garbage collected. + /// Filter to evaluate if the subscriber should receive the event. + /// A that uniquely identifies the added subscription. + /// + /// If is set to , will maintain a to the Target of the supplied delegate. + /// If not using a WeakReference ( is ), the user must explicitly call Unsubscribe for the event when disposing the subscriber in order to avoid memory leaks or unexpected behavior. + /// + /// The PubSubEvent collection is thread-safe. + /// + public abstract SubscriptionToken Subscribe(Action action, ThreadOption threadOption, + bool keepSubscriberReferenceAlive, Predicate? filter); + + /// + /// Publishes the . + /// + /// Message to pass to the subscribers. + public virtual void Publish(TPayload payload) + { + InternalPublish(payload); + } + + /// + /// Removes the first subscriber matching from the subscribers' list. + /// + /// The used when subscribing to the event. + public virtual void Unsubscribe(Action subscriber) + { + lock (Subscriptions) + { + IEventSubscription eventSubscription = Subscriptions.Cast>().FirstOrDefault(evt => evt.Action == subscriber); + if (eventSubscription != null) + { + Subscriptions.Remove(eventSubscription); + } + } + } + + /// + /// Returns if there is a subscriber matching . + /// + /// The used when subscribing to the event. + /// if there is an that matches; otherwise . + public virtual bool Contains(Action subscriber) + { + IEventSubscription eventSubscription; + lock (Subscriptions) + { + eventSubscription = Subscriptions.Cast>().FirstOrDefault(evt => evt.Action == subscriber); + } + return eventSubscription != null; + } +} diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/SpeckleEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs similarity index 78% rename from DUI3/Speckle.Connectors.DUI/Bridge/SpeckleEvent.cs rename to DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs index f97c86068..f714364fc 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/SpeckleEvent.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs @@ -1,20 +1,11 @@ using Speckle.Connectors.Common.Threading; -namespace Speckle.Connectors.DUI.Bridge; +namespace Speckle.Connectors.DUI.Eventing; public class ExceptionEvent(IThreadContext threadContext) : SpeckleEvent(threadContext); -public class ThreadContextEventSubscription( - IDelegateReference actionReference, - IDelegateReference filterReference, - IThreadContext threadContext -) : EventSubscription(actionReference, filterReference) -{ - public override void InvokeAction(Action action, T payload) => - threadContext.RunOnMain(() => action.Invoke(payload)); -} - public class SpeckleEvent(IThreadContext threadContext) : PubSubEvent +where T : notnull { public override SubscriptionToken Subscribe( Action action, diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/SpeckleEventAggregator.cs b/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEventAggregator.cs similarity index 59% rename from DUI3/Speckle.Connectors.DUI/Bridge/SpeckleEventAggregator.cs rename to DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEventAggregator.cs index 5bd522c3c..a31c61a14 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/SpeckleEventAggregator.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEventAggregator.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.DependencyInjection; -namespace Speckle.Connectors.DUI.Bridge; +namespace Speckle.Connectors.DUI.Eventing; public interface ISpeckleEventAggregator { @@ -8,17 +8,11 @@ TEventType GetEvent() where TEventType : EventBase; } -public class SpeckleEventAggregator : ISpeckleEventAggregator +//based on Prism.Events +public class SpeckleEventAggregator(IServiceProvider serviceProvider) : ISpeckleEventAggregator { - private readonly IServiceProvider _serviceProvider; - private readonly Dictionary _events = new(); - public SpeckleEventAggregator(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - public TEventType GetEvent() where TEventType : EventBase { @@ -26,7 +20,7 @@ public TEventType GetEvent() { if (!_events.TryGetValue(typeof(TEventType), out var existingEvent)) { - existingEvent = (TEventType)_serviceProvider.GetRequiredService(typeof(TEventType)); + existingEvent = (TEventType)serviceProvider.GetRequiredService(typeof(TEventType)); _events[typeof(TEventType)] = existingEvent; } return (TEventType)existingEvent; diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/ThreadContextEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadContextEventSubscription.cs new file mode 100644 index 000000000..6196b6e80 --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadContextEventSubscription.cs @@ -0,0 +1,13 @@ +using Speckle.Connectors.Common.Threading; + +namespace Speckle.Connectors.DUI.Eventing; + +public class ThreadContextEventSubscription( + IDelegateReference actionReference, + IDelegateReference filterReference, + IThreadContext threadContext +) : EventSubscription(actionReference, filterReference) +{ + public override void InvokeAction(Action action, T payload) => + threadContext.RunOnMain(() => action.Invoke(payload)); +} diff --git a/DUI3/Speckle.Connectors.DUI/Speckle.Connectors.DUI.csproj b/DUI3/Speckle.Connectors.DUI/Speckle.Connectors.DUI.csproj index 2b842c1d7..e2909423f 100644 --- a/DUI3/Speckle.Connectors.DUI/Speckle.Connectors.DUI.csproj +++ b/DUI3/Speckle.Connectors.DUI/Speckle.Connectors.DUI.csproj @@ -12,7 +12,6 @@ - diff --git a/DUI3/Speckle.Connectors.DUI/packages.lock.json b/DUI3/Speckle.Connectors.DUI/packages.lock.json index 79ffe1039..c3cb0647e 100644 --- a/DUI3/Speckle.Connectors.DUI/packages.lock.json +++ b/DUI3/Speckle.Connectors.DUI/packages.lock.json @@ -42,12 +42,6 @@ "resolved": "1.14.1", "contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ==" }, - "Prism.Events": { - "type": "Direct", - "requested": "[9.0.537, )", - "resolved": "9.0.537", - "contentHash": "Pzp5MGUuhAyKXZUbHVYNWLGF/eA3sScqDN6VrzbWlKj85R0IS0q+JXe99umynso2xhXAe+1jrQCCkgqmEFCBng==" - }, "Speckle.InterfaceGenerator": { "type": "Direct", "requested": "[0.9.6, )", diff --git a/Directory.Packages.props b/Directory.Packages.props index 9d668aa6a..9c5289072 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -17,7 +17,6 @@ - From 56811a9cbb44ed3846d52dc4710612d9cf9e79b7 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Fri, 29 Nov 2024 08:40:49 +0000 Subject: [PATCH 05/16] clean up --- .../Eventing/BackgroundEventSubscription.cs | 57 +++--- .../Eventing/DelegateReference.cs | 6 +- .../Eventing/EventBase.cs | 96 +-------- .../Eventing/EventSubscription.cs | 192 +++++++++--------- .../Speckle.Connectors.DUI/Eventing/Events.cs | 5 + .../Eventing/PubSubEvent.cs | 55 +++-- .../Eventing/SpeckleEvent.cs | 4 +- .../Eventing/SubscriptionToken.cs | 46 +++++ .../Eventing/ThreadOption.cs | 8 + 9 files changed, 215 insertions(+), 254 deletions(-) create mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/Events.cs create mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/SubscriptionToken.cs create mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/ThreadOption.cs diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/BackgroundEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/BackgroundEventSubscription.cs index 2352ad63d..036258e07 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/BackgroundEventSubscription.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/BackgroundEventSubscription.cs @@ -5,40 +5,35 @@ namespace Speckle.Connectors.DUI.Eventing; /// /// Extends to invoke the delegate in a background thread. /// -public class BackgroundEventSubscription(IDelegateReference actionReference, IThreadContext threadContext) : EventSubscription(actionReference) +public class BackgroundEventSubscription(IDelegateReference actionReference, IThreadContext threadContext) + : EventSubscription(actionReference) { public override void InvokeAction(Action action) => threadContext.RunOnWorker(action); } - /// - /// Extends to invoke the delegate in a background thread. - /// - /// The type to use for the generic and types. - public class BackgroundEventSubscription : EventSubscription - { - /// - /// Creates a new instance of . - /// - /// A reference to a delegate of type . - /// A reference to a delegate of type . - /// When or are . - /// When the target of is not of type , - /// or the target of is not of type . - public BackgroundEventSubscription(IDelegateReference actionReference, IDelegateReference filterReference) - : base(actionReference, filterReference) - { - } - - /// - /// Invokes the specified in an asynchronous thread by using a . - /// - /// The action to execute. - /// The payload to pass while invoking it. - public override void InvokeAction(Action action, TPayload argument) - { - //ThreadPool.QueueUserWorkItem( (o) => action(argument) ); - Task.Run(() => action(argument)); - } - } +/// Extends to invoke the delegate in a background thread. +/// +/// The type to use for the generic and types. +public class BackgroundEventSubscription : EventSubscription +{ + /// + /// Creates a new instance of . + /// + /// A reference to a delegate of type . + /// A reference to a delegate of type . + /// When or are . + /// When the target of is not of type , + /// or the target of is not of type . + public BackgroundEventSubscription(IDelegateReference actionReference, IDelegateReference filterReference) + : base(actionReference, filterReference) { } + /// + /// Invokes the specified in an asynchronous thread by using a . + /// + /// The action to execute. + /// The payload to pass while invoking it. + public override void InvokeAction(Action action, TPayload argument) => + //ThreadPool.QueueUserWorkItem( (o) => action(argument) ); + Task.Run(() => action(argument)); +} diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/DelegateReference.cs b/DUI3/Speckle.Connectors.DUI/Eventing/DelegateReference.cs index 36d7f2943..8601359a9 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/DelegateReference.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/DelegateReference.cs @@ -1,6 +1,7 @@ using System.Reflection; namespace Speckle.Connectors.DUI.Eventing; + public interface IDelegateReference { /// @@ -9,6 +10,7 @@ public interface IDelegateReference /// A instance if the target is valid; otherwise . Delegate? Target { get; } } + public class DelegateReference : IDelegateReference { private readonly Delegate? _delegate; @@ -31,7 +33,7 @@ public DelegateReference(Delegate @delegate, bool keepReferenceAlive) if (keepReferenceAlive) { - this._delegate = @delegate; + _delegate = @delegate; } else { @@ -66,7 +68,7 @@ public Delegate? Target /// /// The other delegate to compare with. /// True if the target referenced by the current object are equal to . - public bool TargetEquals(Delegate @delegate) + public bool TargetEquals(Delegate? @delegate) { if (_delegate != null) { diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/EventBase.cs b/DUI3/Speckle.Connectors.DUI/Eventing/EventBase.cs index 28d2ab68e..d0186bbce 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/EventBase.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/EventBase.cs @@ -5,17 +5,7 @@ /// public abstract class EventBase { - private readonly List _subscriptions = new List(); - - /// - /// Allows the SynchronizationContext to be set by the EventAggregator for UI Thread Dispatching - /// - public SynchronizationContext SynchronizationContext { get; set; } - - /// - /// Gets the list of current subscriptions. - /// - /// The current subscribers. + private readonly List _subscriptions = new(); protected ICollection Subscriptions => _subscriptions; /// @@ -90,14 +80,13 @@ public virtual bool Contains(SubscriptionToken token) private List> PruneAndReturnStrategies() { - List> returnList = new List>(); + List> returnList = new(); lock (Subscriptions) { for (var i = Subscriptions.Count - 1; i >= 0; i--) { - Action? listItem = - _subscriptions[i].GetExecutionStrategy(); + Action? listItem = _subscriptions[i].GetExecutionStrategy(); if (listItem == null) { @@ -131,82 +120,3 @@ public void Prune() } } } - - public sealed class SubscriptionToken : IEquatable, IDisposable - { - private readonly Guid _token; - private Action? _unsubscribeAction; - - /// - /// Initializes a new instance of . - /// - public SubscriptionToken(Action unsubscribeAction) - { - _unsubscribeAction = unsubscribeAction; - _token = Guid.NewGuid(); - } - - /// - ///Indicates whether the current object is equal to another object of the same type. - /// - /// - /// if the current object is equal to the parameter; otherwise, . - /// - ///An object to compare with this object. - public bool Equals(SubscriptionToken? other) - { - if (other == null) - { - return false; - } - - return Equals(_token, other._token); - } - - public override bool Equals(object? obj) - { - if (ReferenceEquals(this, obj)) - { - return true; - } - - return Equals(obj as SubscriptionToken); - } - - public override int GetHashCode() - { - return _token.GetHashCode(); - } - - /// - /// Disposes the SubscriptionToken, removing the subscription from the corresponding . - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "Should never have need for a finalizer, hence no need for Dispose(bool).")] - public void Dispose() - { - // While the SubscriptionToken class implements IDisposable, in the case of weak subscriptions - // (i.e. keepSubscriberReferenceAlive set to false in the Subscribe method) it's not necessary to unsubscribe, - // as no resources should be kept alive by the event subscription. - // In such cases, if a warning is issued, it could be suppressed. - - if (this._unsubscribeAction != null) - { - this._unsubscribeAction(this); - this._unsubscribeAction = null; - } - } - } - public enum ThreadOption - { - PublisherThread, - - /// - /// The call is done on the UI thread. - /// - UIThread, - - /// - /// The call is done asynchronously on a background thread. - /// - BackgroundThread - } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs index f0739c702..e65027a03 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs @@ -68,15 +68,15 @@ public EventSubscription(IDelegateReference actionReference) /// public virtual Action? GetExecutionStrategy() { - Action? action = this.Action; + Action? action = Action; if (action == null) { return null; } - return arguments => - { - InvokeAction(action); - }; + return arguments => + { + InvokeAction(action); + }; } /// @@ -95,50 +95,49 @@ public virtual void InvokeAction(Action action) } } +/// +/// Provides a way to retrieve a to execute an action depending +/// on the value of a second filter predicate that returns true if the action should execute. +/// +/// The type to use for the generic and types. +public class EventSubscription : IEventSubscription +{ + private readonly IDelegateReference _actionReference; + private readonly IDelegateReference _filterReference; - /// - /// Provides a way to retrieve a to execute an action depending - /// on the value of a second filter predicate that returns true if the action should execute. - /// - /// The type to use for the generic and types. - public class EventSubscription : IEventSubscription + /// + /// Creates a new instance of . + /// + ///A reference to a delegate of type . + ///A reference to a delegate of type . + ///When or are . + ///When the target of is not of type , + ///or the target of is not of type . + public EventSubscription(IDelegateReference actionReference, IDelegateReference filterReference) + { + if (actionReference == null) { - private readonly IDelegateReference _actionReference; - private readonly IDelegateReference _filterReference; - - /// - /// Creates a new instance of . - /// - ///A reference to a delegate of type . - ///A reference to a delegate of type . - ///When or are . - ///When the target of is not of type , - ///or the target of is not of type . - public EventSubscription(IDelegateReference actionReference, IDelegateReference filterReference) - { - if (actionReference == null) - { - throw new ArgumentNullException(nameof(actionReference)); - } - - if (actionReference.Target is not Action) - { - throw new ArgumentException(null, nameof(actionReference)); - } - - if (filterReference == null) - { - throw new ArgumentNullException(nameof(filterReference)); - } - - if (filterReference.Target is not Predicate) - { - throw new ArgumentException(null, nameof(filterReference)); - } - - _actionReference = actionReference; - _filterReference = filterReference; - } + throw new ArgumentNullException(nameof(actionReference)); + } + + if (actionReference.Target is not Action) + { + throw new ArgumentException(null, nameof(actionReference)); + } + + if (filterReference == null) + { + throw new ArgumentNullException(nameof(filterReference)); + } + + if (filterReference.Target is not Predicate) + { + throw new ArgumentException(null, nameof(filterReference)); + } + + _actionReference = actionReference; + _filterReference = filterReference; + } /// /// Gets the target that is referenced by the . @@ -158,53 +157,54 @@ public EventSubscription(IDelegateReference actionReference, IDelegateReference /// A token that identifies this . public SubscriptionToken SubscriptionToken { get; set; } - /// - /// Gets the execution strategy to publish this event. - /// - /// An with the execution strategy, or if the is no longer valid. - /// - /// If or are no longer valid because they were - /// garbage collected, this method will return . - /// Otherwise it will return a delegate that evaluates the and if it - /// returns will then call . The returned - /// delegate holds hard references to the and target - /// delegates. As long as the returned delegate is not garbage collected, - /// the and references delegates won't get collected either. - /// - public virtual Action? GetExecutionStrategy() - { - Action? action = this.Action; - if (action is null) - { - return null; - } - Predicate? filter = this.Filter; - return arguments => - { - TPayload argument = (TPayload)arguments[0]; - if (filter is null) - { - InvokeAction(action, argument); - }else if (filter(argument)) - { - InvokeAction(action, argument); - } - }; - } - - /// - /// Invokes the specified synchronously when not overridden. - /// - /// The action to execute. - /// The payload to pass while invoking it. - /// An is thrown if is null. - public virtual void InvokeAction(Action action, TPayload argument) - { - if (action == null) - { - throw new ArgumentNullException(nameof(action)); - } - - action(argument); - } + /// + /// Gets the execution strategy to publish this event. + /// + /// An with the execution strategy, or if the is no longer valid. + /// + /// If or are no longer valid because they were + /// garbage collected, this method will return . + /// Otherwise it will return a delegate that evaluates the and if it + /// returns will then call . The returned + /// delegate holds hard references to the and target + /// delegates. As long as the returned delegate is not garbage collected, + /// the and references delegates won't get collected either. + /// + public virtual Action? GetExecutionStrategy() + { + Action? action = Action; + if (action is null) + { + return null; + } + Predicate? filter = Filter; + return arguments => + { + TPayload argument = (TPayload)arguments[0]; + if (filter is null) + { + InvokeAction(action, argument); + } + else if (filter(argument)) + { + InvokeAction(action, argument); + } + }; + } + + /// + /// Invokes the specified synchronously when not overridden. + /// + /// The action to execute. + /// The payload to pass while invoking it. + /// An is thrown if is null. + public virtual void InvokeAction(Action action, TPayload argument) + { + if (action == null) + { + throw new ArgumentNullException(nameof(action)); } + + action(argument); + } +} diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs b/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs new file mode 100644 index 000000000..e8c11a5ab --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs @@ -0,0 +1,5 @@ +using Speckle.Connectors.Common.Threading; + +namespace Speckle.Connectors.DUI.Eventing; + +public class ExceptionEvent(IThreadContext threadContext) : SpeckleEvent(threadContext); diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs index e22cfe527..929015432 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs @@ -5,7 +5,7 @@ /// /// The type of message that will be passed to the subscribers. public abstract class PubSubEvent : EventBase -where TPayload : notnull + where TPayload : notnull { /// /// Subscribes a delegate to an event that will be published on the . @@ -16,10 +16,7 @@ public abstract class PubSubEvent : EventBase /// /// The PubSubEvent collection is thread-safe. /// - public SubscriptionToken Subscribe(Action action) - { - return Subscribe(action, ThreadOption.PublisherThread); - } + public SubscriptionToken Subscribe(Action action) => Subscribe(action, ThreadOption.PublisherThread); /// /// Subscribes a delegate to an event that will be published on the @@ -27,10 +24,8 @@ public SubscriptionToken Subscribe(Action action) /// The delegate that gets executed when the event is raised. /// Filter to evaluate if the subscriber should receive the event. /// A that uniquely identifies the added subscription. - public virtual SubscriptionToken Subscribe(Action action, Predicate filter) - { - return Subscribe(action, ThreadOption.PublisherThread, false, filter); - } + public virtual SubscriptionToken Subscribe(Action action, Predicate filter) => + Subscribe(action, ThreadOption.PublisherThread, false, filter); /// /// Subscribes a delegate to an event. @@ -42,10 +37,8 @@ public virtual SubscriptionToken Subscribe(Action action, Predicate /// The PubSubEvent collection is thread-safe. /// - public SubscriptionToken Subscribe(Action action, ThreadOption threadOption) - { - return Subscribe(action, threadOption, false); - } + public SubscriptionToken Subscribe(Action action, ThreadOption threadOption) => + Subscribe(action, threadOption, false); /// /// Subscribes a delegate to an event that will be published on the . @@ -59,10 +52,8 @@ public SubscriptionToken Subscribe(Action action, ThreadOption threadO /// /// The PubSubEvent collection is thread-safe. /// - public SubscriptionToken Subscribe(Action action, bool keepSubscriberReferenceAlive) - { - return Subscribe(action, ThreadOption.PublisherThread, keepSubscriberReferenceAlive); - } + public SubscriptionToken Subscribe(Action action, bool keepSubscriberReferenceAlive) => + Subscribe(action, ThreadOption.PublisherThread, keepSubscriberReferenceAlive); /// /// Subscribes a delegate to an event. @@ -77,10 +68,11 @@ public SubscriptionToken Subscribe(Action action, bool keepSubscriberR /// /// The PubSubEvent collection is thread-safe. /// - public SubscriptionToken Subscribe(Action action, ThreadOption threadOption, bool keepSubscriberReferenceAlive) - { - return Subscribe(action, threadOption, keepSubscriberReferenceAlive, null); - } + public SubscriptionToken Subscribe( + Action action, + ThreadOption threadOption, + bool keepSubscriberReferenceAlive + ) => Subscribe(action, threadOption, keepSubscriberReferenceAlive, null); /// /// Subscribes a delegate to an event. @@ -96,17 +88,18 @@ public SubscriptionToken Subscribe(Action action, ThreadOption threadO /// /// The PubSubEvent collection is thread-safe. /// - public abstract SubscriptionToken Subscribe(Action action, ThreadOption threadOption, - bool keepSubscriberReferenceAlive, Predicate? filter); + public abstract SubscriptionToken Subscribe( + Action action, + ThreadOption threadOption, + bool keepSubscriberReferenceAlive, + Predicate? filter + ); /// /// Publishes the . /// /// Message to pass to the subscribers. - public virtual void Publish(TPayload payload) - { - InternalPublish(payload); - } + public virtual void Publish(TPayload payload) => InternalPublish(payload); /// /// Removes the first subscriber matching from the subscribers' list. @@ -116,7 +109,9 @@ public virtual void Unsubscribe(Action subscriber) { lock (Subscriptions) { - IEventSubscription eventSubscription = Subscriptions.Cast>().FirstOrDefault(evt => evt.Action == subscriber); + IEventSubscription eventSubscription = Subscriptions + .Cast>() + .FirstOrDefault(evt => evt.Action == subscriber); if (eventSubscription != null) { Subscriptions.Remove(eventSubscription); @@ -134,7 +129,9 @@ public virtual bool Contains(Action subscriber) IEventSubscription eventSubscription; lock (Subscriptions) { - eventSubscription = Subscriptions.Cast>().FirstOrDefault(evt => evt.Action == subscriber); + eventSubscription = Subscriptions + .Cast>() + .FirstOrDefault(evt => evt.Action == subscriber); } return eventSubscription != null; } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs index f714364fc..99807ef81 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs @@ -2,10 +2,8 @@ namespace Speckle.Connectors.DUI.Eventing; -public class ExceptionEvent(IThreadContext threadContext) : SpeckleEvent(threadContext); - public class SpeckleEvent(IThreadContext threadContext) : PubSubEvent -where T : notnull + where T : notnull { public override SubscriptionToken Subscribe( Action action, diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/SubscriptionToken.cs b/DUI3/Speckle.Connectors.DUI/Eventing/SubscriptionToken.cs new file mode 100644 index 000000000..d7dacbc2e --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Eventing/SubscriptionToken.cs @@ -0,0 +1,46 @@ +namespace Speckle.Connectors.DUI.Eventing; + +//based on Prism.Events +public sealed class SubscriptionToken(Action unsubscribeAction) + : IEquatable, + IDisposable +{ + private readonly Guid _token = Guid.NewGuid(); + private Action? _unsubscribeAction = unsubscribeAction; + + public bool Equals(SubscriptionToken? other) + { + if (other == null) + { + return false; + } + + return Equals(_token, other._token); + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(this, obj)) + { + return true; + } + + return Equals(obj as SubscriptionToken); + } + + public override int GetHashCode() => _token.GetHashCode(); + + public void Dispose() + { + // While the SubscriptionToken class implements IDisposable, in the case of weak subscriptions + // (i.e. keepSubscriberReferenceAlive set to false in the Subscribe method) it's not necessary to unsubscribe, + // as no resources should be kept alive by the event subscription. + // In such cases, if a warning is issued, it could be suppressed. + + if (_unsubscribeAction != null) + { + _unsubscribeAction(this); + _unsubscribeAction = null; + } + } +} diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/ThreadOption.cs b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadOption.cs new file mode 100644 index 000000000..9b8b3ea96 --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadOption.cs @@ -0,0 +1,8 @@ +namespace Speckle.Connectors.DUI.Eventing; + +public enum ThreadOption +{ + PublisherThread, + UIThread, + BackgroundThread +} From bda6abecaada66b6cfc186af5601fff23e0f0441 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Fri, 29 Nov 2024 08:43:39 +0000 Subject: [PATCH 06/16] always run on background thread --- .../Eventing/BackgroundEventSubscription.cs | 38 ++------- .../Eventing/EventSubscription.cs | 79 ------------------- .../Eventing/SpeckleEvent.cs | 2 +- 3 files changed, 7 insertions(+), 112 deletions(-) diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/BackgroundEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/BackgroundEventSubscription.cs index 036258e07..4d83bbc0a 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/BackgroundEventSubscription.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/BackgroundEventSubscription.cs @@ -2,38 +2,12 @@ namespace Speckle.Connectors.DUI.Eventing; -/// -/// Extends to invoke the delegate in a background thread. -/// -public class BackgroundEventSubscription(IDelegateReference actionReference, IThreadContext threadContext) - : EventSubscription(actionReference) +public class BackgroundEventSubscription( + IDelegateReference actionReference, + IDelegateReference filterReference, + IThreadContext threadContext +) : EventSubscription(actionReference, filterReference) { - public override void InvokeAction(Action action) => threadContext.RunOnWorker(action); -} - -/// -/// Extends to invoke the delegate in a background thread. -/// -/// The type to use for the generic and types. -public class BackgroundEventSubscription : EventSubscription -{ - /// - /// Creates a new instance of . - /// - /// A reference to a delegate of type . - /// A reference to a delegate of type . - /// When or are . - /// When the target of is not of type , - /// or the target of is not of type . - public BackgroundEventSubscription(IDelegateReference actionReference, IDelegateReference filterReference) - : base(actionReference, filterReference) { } - - /// - /// Invokes the specified in an asynchronous thread by using a . - /// - /// The action to execute. - /// The payload to pass while invoking it. public override void InvokeAction(Action action, TPayload argument) => - //ThreadPool.QueueUserWorkItem( (o) => action(argument) ); - Task.Run(() => action(argument)); + threadContext.RunOnWorker(() => action(argument)); } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs index e65027a03..1e731d987 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs @@ -16,85 +16,6 @@ public interface IEventSubscription Action? GetExecutionStrategy(); } -public class EventSubscription : IEventSubscription -{ - private readonly IDelegateReference _actionReference; - - /// - /// Creates a new instance of . - /// - ///A reference to a delegate of type . - ///When or are . - ///When the target of is not of type . - public EventSubscription(IDelegateReference actionReference) - { - if (actionReference == null) - { - throw new ArgumentNullException(nameof(actionReference)); - } - - if (actionReference.Target is not System.Action) - { - throw new ArgumentException(null, nameof(actionReference)); - } - - _actionReference = actionReference; - } - - /// - /// Gets the target that is referenced by the . - /// - /// An or if the referenced target is not alive. - public Action? Action => (Action?)_actionReference.Target; - - /// - /// Gets or sets a that identifies this . - /// - /// A token that identifies this . - public SubscriptionToken SubscriptionToken { get; set; } - - /// - /// Gets the execution strategy to publish this event. - /// - /// An with the execution strategy, or if the is no longer valid. - /// - /// If is no longer valid because it was - /// garbage collected, this method will return . - /// Otherwise it will return a delegate that evaluates the and if it - /// returns will then call . The returned - /// delegate holds a hard reference to the target - /// delegates. As long as the returned delegate is not garbage collected, - /// the references delegates won't get collected either. - /// - public virtual Action? GetExecutionStrategy() - { - Action? action = Action; - if (action == null) - { - return null; - } - return arguments => - { - InvokeAction(action); - }; - } - - /// - /// Invokes the specified synchronously when not overridden. - /// - /// The action to execute. - /// An is thrown if is null. - public virtual void InvokeAction(Action action) - { - if (action == null) - { - throw new ArgumentNullException(nameof(action)); - } - - action(); - } -} - /// /// Provides a way to retrieve a to execute an action depending /// on the value of a second filter predicate that returns true if the action should execute. diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs index 99807ef81..230aea914 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs @@ -34,7 +34,7 @@ public override SubscriptionToken Subscribe( switch (threadOption) { case ThreadOption.BackgroundThread: - subscription = new BackgroundEventSubscription(actionReference, filterReference); + subscription = new BackgroundEventSubscription(actionReference, filterReference, threadContext); break; case ThreadOption.UIThread: subscription = new ThreadContextEventSubscription(actionReference, filterReference, threadContext); From 47fca75b70e69e6b0a7bb5194e8b68ce1fdf4ad4 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Fri, 29 Nov 2024 14:24:03 +0000 Subject: [PATCH 07/16] Clean up to be specific --- .../Bridge/TopLevelExceptionHandlerTests.cs | 16 ++++++++-------- .../Bridge/BrowserBridge.cs | 6 +++--- .../Bridge/TopLevelExceptionHandler.cs | 4 ++-- .../ContainerRegistration.cs | 2 +- ...ckleEventAggregator.cs => EventAggregator.cs} | 8 +++++--- DUI3/Speckle.Connectors.DUI/Eventing/Events.cs | 2 +- ...ription.cs => MainThreadEventSubscription.cs} | 2 +- .../Eventing/ThreadOption.cs | 4 ++-- .../{SpeckleEvent.cs => ThreadedEvent.cs} | 10 +++++----- ...ubscription.cs => WorkerEventSubscription.cs} | 2 +- 10 files changed, 29 insertions(+), 27 deletions(-) rename DUI3/Speckle.Connectors.DUI/Eventing/{SpeckleEventAggregator.cs => EventAggregator.cs} (62%) rename DUI3/Speckle.Connectors.DUI/Eventing/{ThreadContextEventSubscription.cs => MainThreadEventSubscription.cs} (88%) rename DUI3/Speckle.Connectors.DUI/Eventing/{SpeckleEvent.cs => ThreadedEvent.cs} (77%) rename DUI3/Speckle.Connectors.DUI/Eventing/{BackgroundEventSubscription.cs => WorkerEventSubscription.cs} (88%) diff --git a/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs b/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs index b79883e08..a03434f58 100644 --- a/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs +++ b/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs @@ -15,7 +15,7 @@ public class TopLevelExceptionHandlerTests : MoqTest public void CatchUnhandledAction_Happy() { var logger = Create>(MockBehavior.Loose); - var eventAggregator = Create(); + var eventAggregator = Create(); var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); sut.CatchUnhandled(() => { }); @@ -25,7 +25,7 @@ public void CatchUnhandledAction_Happy() public void CatchUnhandledAction_Exception() { var logger = Create>(MockBehavior.Loose); - var eventAggregator = Create(); + var eventAggregator = Create(); eventAggregator .Setup(x => x.GetEvent()) @@ -41,7 +41,7 @@ public void CatchUnhandledFunc_Happy() { var val = 2; var logger = Create>(MockBehavior.Loose); - var eventAggregator = Create(); + var eventAggregator = Create(); var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); var returnVal = sut.CatchUnhandled(() => val); @@ -54,7 +54,7 @@ public void CatchUnhandledFunc_Happy() public void CatchUnhandledFunc_Exception() { var logger = Create>(MockBehavior.Loose); - var eventAggregator = Create(); + var eventAggregator = Create(); eventAggregator .Setup(x => x.GetEvent()) @@ -72,7 +72,7 @@ public void CatchUnhandledFunc_Exception() public void CatchUnhandledFunc_Exception_Fatal() { var logger = Create>(MockBehavior.Loose); - var eventAggregator = Create(); + var eventAggregator = Create(); var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); var exception = Assert.Throws( @@ -86,7 +86,7 @@ public async Task CatchUnhandledFuncAsync_Happy() { var val = 2; var logger = Create>(MockBehavior.Loose); - var eventAggregator = Create(); + var eventAggregator = Create(); var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); var returnVal = await sut.CatchUnhandledAsync(() => Task.FromResult(val)); @@ -99,7 +99,7 @@ public async Task CatchUnhandledFuncAsync_Happy() public async Task CatchUnhandledFuncAsync_Exception() { var logger = Create>(MockBehavior.Loose); - var eventAggregator = Create(); + var eventAggregator = Create(); eventAggregator .Setup(x => x.GetEvent()) @@ -117,7 +117,7 @@ public async Task CatchUnhandledFuncAsync_Exception() public void CatchUnhandledFuncAsync_Exception_Fatal() { var logger = Create>(MockBehavior.Loose); - var eventAggregator = Create(); + var eventAggregator = Create(); var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); var exception = Assert.ThrowsAsync( diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index ba4ae963d..0a34aba26 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -30,7 +30,7 @@ public sealed class BrowserBridge : IBrowserBridge private readonly ConcurrentDictionary _resultsStore = new(); private readonly ITopLevelExceptionHandler _topLevelExceptionHandler; - private readonly ISpeckleEventAggregator _eventAggregator; + private readonly IEventAggregator _eventAggregator; private readonly IThreadContext _threadContext; private readonly IThreadOptions _threadOptions; @@ -65,7 +65,7 @@ public BrowserBridge( ILogger logger, IBrowserScriptExecutor browserScriptExecutor, IThreadOptions threadOptions, - ISpeckleEventAggregator eventAggregator, + IEventAggregator eventAggregator, ITopLevelExceptionHandler topLevelExceptionHandler ) { @@ -94,7 +94,7 @@ ITopLevelExceptionHandler topLevelExceptionHandler ) .ConfigureAwait(false); }, - ThreadOption.UIThread + ThreadOption.MainThread ); } diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs index ad3ad993f..cece66ad8 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs @@ -22,12 +22,12 @@ namespace Speckle.Connectors.DUI.Bridge; public sealed class TopLevelExceptionHandler : ITopLevelExceptionHandler { private readonly ILogger _logger; - private readonly ISpeckleEventAggregator _eventAggregator; + private readonly IEventAggregator _eventAggregator; public string Name => nameof(TopLevelExceptionHandler); private const string UNHANDLED_LOGGER_TEMPLATE = "An unhandled Exception occured"; - public TopLevelExceptionHandler(ILogger logger, ISpeckleEventAggregator eventAggregator) + public TopLevelExceptionHandler(ILogger logger, IEventAggregator eventAggregator) { _logger = logger; _eventAggregator = eventAggregator; diff --git a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs index 763b035a8..f3f3d946e 100644 --- a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs +++ b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs @@ -24,7 +24,7 @@ public static void AddDUI(this IServiceCollectio serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetAssembly(typeof(IdleCallManager))); serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetAssembly(typeof(IServerTransportFactory))); - serviceCollection.AddSingleton(sp => new SpeckleEventAggregator(sp)); + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(sp => sp.GetRequiredService() diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEventAggregator.cs b/DUI3/Speckle.Connectors.DUI/Eventing/EventAggregator.cs similarity index 62% rename from DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEventAggregator.cs rename to DUI3/Speckle.Connectors.DUI/Eventing/EventAggregator.cs index a31c61a14..eea2f87ac 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEventAggregator.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/EventAggregator.cs @@ -2,14 +2,16 @@ namespace Speckle.Connectors.DUI.Eventing; -public interface ISpeckleEventAggregator +public interface IEventAggregator { TEventType GetEvent() where TEventType : EventBase; } -//based on Prism.Events -public class SpeckleEventAggregator(IServiceProvider serviceProvider) : ISpeckleEventAggregator +//based on Prism.Events at verison 8 +// which was MIT https://github.com/PrismLibrary/Prism/tree/952e343f585b068ccb7d3478d3982485253a0508/src/Prism.Events +// License https://github.com/PrismLibrary/Prism/blob/952e343f585b068ccb7d3478d3982485253a0508/LICENSE +public class EventAggregator(IServiceProvider serviceProvider) : IEventAggregator { private readonly Dictionary _events = new(); diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs b/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs index e8c11a5ab..fa4684fb3 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs @@ -2,4 +2,4 @@ namespace Speckle.Connectors.DUI.Eventing; -public class ExceptionEvent(IThreadContext threadContext) : SpeckleEvent(threadContext); +public class ExceptionEvent(IThreadContext threadContext) : ThreadedEvent(threadContext); diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/ThreadContextEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs similarity index 88% rename from DUI3/Speckle.Connectors.DUI/Eventing/ThreadContextEventSubscription.cs rename to DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs index 6196b6e80..8922989d9 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/ThreadContextEventSubscription.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs @@ -2,7 +2,7 @@ namespace Speckle.Connectors.DUI.Eventing; -public class ThreadContextEventSubscription( +public class MainThreadEventSubscription( IDelegateReference actionReference, IDelegateReference filterReference, IThreadContext threadContext diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/ThreadOption.cs b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadOption.cs index 9b8b3ea96..6866be71e 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/ThreadOption.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadOption.cs @@ -3,6 +3,6 @@ public enum ThreadOption { PublisherThread, - UIThread, - BackgroundThread + MainThread, + WorkerThread } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs similarity index 77% rename from DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs rename to DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs index 230aea914..20b8b2997 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs @@ -2,7 +2,7 @@ namespace Speckle.Connectors.DUI.Eventing; -public class SpeckleEvent(IThreadContext threadContext) : PubSubEvent +public class ThreadedEvent(IThreadContext threadContext) : PubSubEvent where T : notnull { public override SubscriptionToken Subscribe( @@ -33,11 +33,11 @@ public override SubscriptionToken Subscribe( EventSubscription subscription; switch (threadOption) { - case ThreadOption.BackgroundThread: - subscription = new BackgroundEventSubscription(actionReference, filterReference, threadContext); + case ThreadOption.WorkerThread: + subscription = new WorkerEventSubscription(actionReference, filterReference, threadContext); break; - case ThreadOption.UIThread: - subscription = new ThreadContextEventSubscription(actionReference, filterReference, threadContext); + case ThreadOption.MainThread: + subscription = new MainThreadEventSubscription(actionReference, filterReference, threadContext); break; case ThreadOption.PublisherThread: default: diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/BackgroundEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs similarity index 88% rename from DUI3/Speckle.Connectors.DUI/Eventing/BackgroundEventSubscription.cs rename to DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs index 4d83bbc0a..653cfabd7 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/BackgroundEventSubscription.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs @@ -2,7 +2,7 @@ namespace Speckle.Connectors.DUI.Eventing; -public class BackgroundEventSubscription( +public class WorkerEventSubscription( IDelegateReference actionReference, IDelegateReference filterReference, IThreadContext threadContext From b1f41c68157daf725587f6e3fd3377e909bd074f Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 3 Dec 2024 09:24:21 +0000 Subject: [PATCH 08/16] fix build issues --- .../ServiceRegistration.cs | 2 -- .../Bridge/TopLevelExceptionHandler.cs | 30 +------------------ .../Operations/ReceiveOperation.cs | 4 +-- 3 files changed, 3 insertions(+), 33 deletions(-) diff --git a/Connectors/CSi/Speckle.Connectors.CSiShared/ServiceRegistration.cs b/Connectors/CSi/Speckle.Connectors.CSiShared/ServiceRegistration.cs index 0f689e31f..257796e18 100644 --- a/Connectors/CSi/Speckle.Connectors.CSiShared/ServiceRegistration.cs +++ b/Connectors/CSi/Speckle.Connectors.CSiShared/ServiceRegistration.cs @@ -39,8 +39,6 @@ public static IServiceCollection AddCSi(this IServiceCollection services) services.AddScoped(); - services.RegisterTopLevelExceptionHandler(); - return services; } } diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs index 3c62e2362..b1d780fa1 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs @@ -93,7 +93,6 @@ public async Task> CatchUnhandledAsync(Func> function) { _logger.LogError(ex, UNHANDLED_LOGGER_TEMPLATE); _eventAggregator.GetEvent().Publish(ex); - await HandleException(ex).ConfigureAwait(false); return new(ex); } } @@ -103,34 +102,7 @@ public async Task> CatchUnhandledAsync(Func> function) throw; } } - - private async Task HandleException(Exception ex) - { - _logger.LogError(ex, UNHANDLED_LOGGER_TEMPLATE); - - try - { - await SetGlobalNotification( - ToastNotificationType.DANGER, - "Unhandled Exception Occured", - ex.ToFormattedString(), - false - ) - .ConfigureAwait(false); - } - catch (Exception toastEx) - { - // Not only was a top level exception caught, but our attempt to display a toast failed! - // Toasts can fail if the BrowserBridge is not yet associated with a binding - // For this reason, binding authors should avoid doing anything in - // the constructors of bindings that may try and use the bridge! - AggregateException aggregateException = - new("An Unhandled top level exception was caught, and the toast failed to display it!", [toastEx, ex]); - - throw aggregateException; - } - } - + /// /// Triggers an async action without explicitly needing to await it.
/// Any thrown by invoking will be handled by the
diff --git a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs index 8b36e6c78..c33cd74af 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs @@ -1,11 +1,11 @@ using Speckle.Connectors.Common.Builders; using Speckle.Connectors.Common.Threading; +using Speckle.Connectors.Logging; using Speckle.Sdk.Api; using Speckle.Sdk.Credentials; using Speckle.Sdk.Logging; using Speckle.Sdk.Models; using Speckle.Sdk.Models.Extensions; -#pragma warning disable CS9113 // Parameter is unread. namespace Speckle.Connectors.Common.Operations; @@ -20,7 +20,7 @@ public sealed class ReceiveOperation( IThreadOptions threadOptions ) { - public Task Execute( + public async Task Execute( ReceiveInfo receiveInfo, IProgress onOperationProgressed, CancellationToken cancellationToken From 69745bb2061cb7e138aafa054ac6d168373533b7 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 3 Dec 2024 10:00:44 +0000 Subject: [PATCH 09/16] Do top level handling in event aggregator --- .../Bridge/TopLevelExceptionHandlerTests.cs | 6 +-- .../Bridge/TopLevelExceptionHandler.cs | 39 +++++++++++++------ .../Eventing/EventSubscription.cs | 11 ++++-- .../Speckle.Connectors.DUI/Eventing/Events.cs | 3 +- .../Eventing/MainThreadEventSubscription.cs | 9 +++-- .../Eventing/ThreadedEvent.cs | 9 +++-- .../Eventing/WorkerEventSubscription.cs | 6 ++- 7 files changed, 54 insertions(+), 29 deletions(-) diff --git a/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs b/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs index a03434f58..2a4957745 100644 --- a/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs +++ b/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs @@ -29,7 +29,7 @@ public void CatchUnhandledAction_Exception() eventAggregator .Setup(x => x.GetEvent()) - .Returns(new ExceptionEvent(Create().Object)); + .Returns(new ExceptionEvent(Create().Object, Create().Object)); var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); @@ -58,7 +58,7 @@ public void CatchUnhandledFunc_Exception() eventAggregator .Setup(x => x.GetEvent()) - .Returns(new ExceptionEvent(Create().Object)); + .Returns(new ExceptionEvent(Create().Object, Create().Object)); var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); @@ -103,7 +103,7 @@ public async Task CatchUnhandledFuncAsync_Exception() eventAggregator .Setup(x => x.GetEvent()) - .Returns(new ExceptionEvent(Create().Object)); + .Returns(new ExceptionEvent(Create().Object, Create().Object)); var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs index b1d780fa1..af15e0757 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Logging; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Eventing; using Speckle.InterfaceGenerator; using Speckle.Sdk; @@ -40,31 +41,30 @@ public TopLevelExceptionHandler(ILogger logger, IEvent /// The function to invoke and provide error handling for /// will be rethrown, these should be allowed to bubble up to the host app /// - public void CatchUnhandled(Action function) + public Result CatchUnhandled(Action function) { - _ = CatchUnhandled(() => + var r = CatchUnhandled(() => { - function(); - return null; + function(); + return true; }); + if (r.IsSuccess) + { + return new Result(); + } + return new Result(r.Exception); } /// /// return type /// A result pattern struct (where exceptions have been handled) - public Result CatchUnhandled(Func function) => - CatchUnhandledAsync(() => Task.FromResult(function.Invoke())).Result; //Safe to do a .Result because this as an already completed and non-async Task from the Task.FromResult - - /// - /// A result pattern struct (where exceptions have been handled) - public async Task CatchUnhandledAsync(Func function) + public Result CatchUnhandled(Func function) { try { try { - await function().ConfigureAwait(false); - return new Result(); + return new Result(function()); } catch (Exception ex) when (!ex.IsFatal()) { @@ -79,6 +79,21 @@ public async Task CatchUnhandledAsync(Func function) throw; } } + /// + /// A result pattern struct (where exceptions have been handled) + public async Task CatchUnhandledAsync(Func function) + { + var r = await CatchUnhandledAsync(async () => + { + await function().BackToCurrent(); + return true; + }).BackToCurrent(); + if (r.IsSuccess) + { + return new Result(); + } + return new Result(r.Exception); + } /// public async Task> CatchUnhandledAsync(Func> function) diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs index 1e731d987..5705795fa 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs @@ -1,4 +1,6 @@ -namespace Speckle.Connectors.DUI.Eventing; +using Speckle.Connectors.DUI.Bridge; + +namespace Speckle.Connectors.DUI.Eventing; public interface IEventSubscription { @@ -25,6 +27,7 @@ public class EventSubscription : IEventSubscription { private readonly IDelegateReference _actionReference; private readonly IDelegateReference _filterReference; + private readonly ITopLevelExceptionHandler _exceptionHandler; /// /// Creates a new instance of . @@ -34,7 +37,8 @@ public class EventSubscription : IEventSubscription ///When or are . ///When the target of is not of type , ///or the target of is not of type . - public EventSubscription(IDelegateReference actionReference, IDelegateReference filterReference) + public EventSubscription(IDelegateReference actionReference, IDelegateReference filterReference, + ITopLevelExceptionHandler exceptionHandler) { if (actionReference == null) { @@ -58,6 +62,7 @@ public EventSubscription(IDelegateReference actionReference, IDelegateReference _actionReference = actionReference; _filterReference = filterReference; + _exceptionHandler = exceptionHandler; } /// @@ -126,6 +131,6 @@ public virtual void InvokeAction(Action action, TPayload argument) throw new ArgumentNullException(nameof(action)); } - action(argument); + _exceptionHandler.CatchUnhandled(() => action(argument)); } } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs b/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs index fa4684fb3..bbab25d6d 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs @@ -1,5 +1,6 @@ using Speckle.Connectors.Common.Threading; +using Speckle.Connectors.DUI.Bridge; namespace Speckle.Connectors.DUI.Eventing; -public class ExceptionEvent(IThreadContext threadContext) : ThreadedEvent(threadContext); +public class ExceptionEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs index 8922989d9..61ea71f4d 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs @@ -1,13 +1,14 @@ using Speckle.Connectors.Common.Threading; +using Speckle.Connectors.DUI.Bridge; namespace Speckle.Connectors.DUI.Eventing; public class MainThreadEventSubscription( IDelegateReference actionReference, IDelegateReference filterReference, - IThreadContext threadContext -) : EventSubscription(actionReference, filterReference) + IThreadContext threadContext, + ITopLevelExceptionHandler exceptionHandler +) : EventSubscription(actionReference, filterReference, exceptionHandler) { - public override void InvokeAction(Action action, T payload) => - threadContext.RunOnMain(() => action.Invoke(payload)); + public override void InvokeAction(Action action, T payload) => threadContext.RunOnMain(() => action.Invoke(payload)); } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs index 20b8b2997..e76184fae 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs @@ -1,8 +1,9 @@ using Speckle.Connectors.Common.Threading; +using Speckle.Connectors.DUI.Bridge; namespace Speckle.Connectors.DUI.Eventing; -public class ThreadedEvent(IThreadContext threadContext) : PubSubEvent +public class ThreadedEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : PubSubEvent where T : notnull { public override SubscriptionToken Subscribe( @@ -34,14 +35,14 @@ public override SubscriptionToken Subscribe( switch (threadOption) { case ThreadOption.WorkerThread: - subscription = new WorkerEventSubscription(actionReference, filterReference, threadContext); + subscription = new WorkerEventSubscription(actionReference, filterReference, threadContext, exceptionHandler); break; case ThreadOption.MainThread: - subscription = new MainThreadEventSubscription(actionReference, filterReference, threadContext); + subscription = new MainThreadEventSubscription(actionReference, filterReference, threadContext, exceptionHandler); break; case ThreadOption.PublisherThread: default: - subscription = new EventSubscription(actionReference, filterReference); + subscription = new EventSubscription(actionReference, filterReference, exceptionHandler); break; } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs index 653cfabd7..a8a03518c 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs @@ -1,12 +1,14 @@ using Speckle.Connectors.Common.Threading; +using Speckle.Connectors.DUI.Bridge; namespace Speckle.Connectors.DUI.Eventing; public class WorkerEventSubscription( IDelegateReference actionReference, IDelegateReference filterReference, - IThreadContext threadContext -) : EventSubscription(actionReference, filterReference) + IThreadContext threadContext, + ITopLevelExceptionHandler exceptionHandler +) : EventSubscription(actionReference, filterReference, exceptionHandler) { public override void InvokeAction(Action action, TPayload argument) => threadContext.RunOnWorker(() => action(argument)); From 50228be7ee9a526d764eab8c18a9bfc97b4c3854 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 3 Dec 2024 11:03:28 +0000 Subject: [PATCH 10/16] add some rhino events --- .../Bindings/BasicConnectorBindingRevit.cs | 12 ++--- .../Bindings/RevitSendBinding.cs | 8 +++- .../HostApp/RevitDocumentStore.cs | 9 +++- .../Bindings/RhinoBasicConnectorBinding.cs | 16 +++---- .../Speckle.Connectors.RhinoShared/Events.cs | 22 +++++++++ .../HostApp/RhinoDocumentStore.cs | 12 ++--- .../Plugin/Speckle.Connectors.RhinoPlugin.cs | 3 ++ .../Speckle.Connectors.RhinoShared.projitems | 1 + .../ContainerRegistration.cs | 19 ++++++++ .../Speckle.Connectors.DUI/Eventing/Events.cs | 3 ++ .../Eventing/ISpeckleEvent.cs | 6 +++ .../Eventing/ThreadedEvent.cs | 46 ++++++++++++++++++- .../Models/DocumentModelStore.cs | 8 ---- 13 files changed, 132 insertions(+), 33 deletions(-) create mode 100644 Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs create mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/ISpeckleEvent.cs diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs index 0e7805b76..8def57081 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs @@ -1,5 +1,6 @@ using Autodesk.Revit.DB; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.RevitShared; @@ -27,7 +28,7 @@ public BasicConnectorBindingRevit( IBrowserBridge parent, RevitContext revitContext, ISpeckleApplication speckleApplication, - ITopLevelExceptionHandler topLevelExceptionHandler + IEventAggregator eventAggregator ) { Name = "baseBinding"; @@ -38,11 +39,10 @@ ITopLevelExceptionHandler topLevelExceptionHandler Commands = new BasicConnectorBindingCommands(parent); // POC: event binding? - _store.DocumentChanged += (_, _) => - topLevelExceptionHandler.FireAndForget(async () => - { - await Commands.NotifyDocumentChanged().ConfigureAwait(false); - }); + eventAggregator.GetEvent().Subscribe(async _ => + { + await Commands.NotifyDocumentChanged().ConfigureAwait(false); + }); } public string GetConnectorVersion() => _speckleApplication.SpeckleVersion; diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs index 3b6cce3ba..6be971914 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs @@ -8,6 +8,7 @@ using Speckle.Connectors.Common.Operations; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Exceptions; using Speckle.Connectors.DUI.Logging; using Speckle.Connectors.DUI.Models; @@ -60,6 +61,7 @@ public RevitSendBinding( ElementUnpacker elementUnpacker, IRevitConversionSettingsFactory revitConversionSettingsFactory, ISpeckleApplication speckleApplication, + IEventAggregator eventAggregator, ITopLevelExceptionHandler topLevelExceptionHandler ) : base("sendBinding", store, bridge, revitContext) @@ -81,8 +83,10 @@ ITopLevelExceptionHandler topLevelExceptionHandler revitContext.UIApplication.NotNull().Application.DocumentChanged += (_, e) => topLevelExceptionHandler.CatchUnhandled(() => DocChangeHandler(e)); - Store.DocumentChanged += (_, _) => - topLevelExceptionHandler.FireAndForget(async () => await OnDocumentChanged().ConfigureAwait(false)); + eventAggregator.GetEvent().Subscribe(async _ => + { + await OnDocumentChanged().ConfigureAwait(false); + }); } public List GetSendFilters() => diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs index 5b8629853..151f31789 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs @@ -3,6 +3,7 @@ using Autodesk.Revit.UI; using Autodesk.Revit.UI.Events; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Utils; using Speckle.Converters.RevitShared.Helpers; @@ -20,6 +21,7 @@ internal sealed class RevitDocumentStore : DocumentModelStore private readonly IAppIdleManager _idleManager; private readonly DocumentModelStorageSchema _documentModelStorageSchema; private readonly IdStorageSchema _idStorageSchema; + private readonly IEventAggregator _eventAggregator; public RevitDocumentStore( IAppIdleManager idleManager, @@ -27,6 +29,7 @@ public RevitDocumentStore( IJsonSerializer jsonSerializer, DocumentModelStorageSchema documentModelStorageSchema, IdStorageSchema idStorageSchema, + IEventAggregator eventAggregator, ITopLevelExceptionHandler topLevelExceptionHandler ) : base(jsonSerializer) @@ -35,6 +38,7 @@ ITopLevelExceptionHandler topLevelExceptionHandler _revitContext = revitContext; _documentModelStorageSchema = documentModelStorageSchema; _idStorageSchema = idStorageSchema; + _eventAggregator = eventAggregator; UIApplication uiApplication = _revitContext.UIApplication.NotNull(); @@ -49,7 +53,8 @@ ITopLevelExceptionHandler topLevelExceptionHandler // There is no event that we can hook here for double-click file open... // It is kind of harmless since we create this object as "SingleInstance". LoadState(); - OnDocumentChanged(); + + eventAggregator.GetEvent().Publish(new object()); } /// @@ -74,7 +79,7 @@ private void OnViewActivated(object? _, ViewActivatedEventArgs e) () => { LoadState(); - OnDocumentChanged(); + _eventAggregator.GetEvent().Publish(new object()); } ); } diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoBasicConnectorBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoBasicConnectorBinding.cs index 0cf61e606..664606953 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoBasicConnectorBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoBasicConnectorBinding.cs @@ -4,6 +4,7 @@ using Speckle.Connectors.Common.Caching; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.Rhino.Extensions; @@ -27,7 +28,7 @@ public RhinoBasicConnectorBinding( IBrowserBridge parent, ISendConversionCache sendConversionCache, ISpeckleApplication speckleApplication, - ITopLevelExceptionHandler topLevelExceptionHandler + IEventAggregator eventAggregator ) { _store = store; @@ -36,13 +37,12 @@ ITopLevelExceptionHandler topLevelExceptionHandler _speckleApplication = speckleApplication; Commands = new BasicConnectorBindingCommands(parent); - _store.DocumentChanged += (_, _) => - topLevelExceptionHandler.FireAndForget(async () => - { - await Commands.NotifyDocumentChanged().ConfigureAwait(false); - // Note: this prevents scaling issues when copy-pasting from one rhino doc to another in the same session. - _sendConversionCache.ClearCache(); - }); + eventAggregator.GetEvent().Subscribe(async _ => + { + await Commands.NotifyDocumentChanged().ConfigureAwait(false); + // Note: this prevents scaling issues when copy-pasting from one rhino doc to another in the same session. + _sendConversionCache.ClearCache(); + }); } public string GetConnectorVersion() => _speckleApplication.SpeckleVersion; diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs new file mode 100644 index 000000000..fe2e8423e --- /dev/null +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs @@ -0,0 +1,22 @@ +using Rhino; +using Speckle.Connectors.Common.Threading; +using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; + +namespace Speckle.Connectors.RhinoShared; + +public class BeginOpenDocument(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); +public class EndOpenDocument(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); + +public static class RhinoEvents +{ + public static void Register(IEventAggregator eventAggregator) + { + RhinoDoc.BeginOpenDocument += + (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.EndOpenDocument += + (_, e) => eventAggregator.GetEvent().Publish(e); + } +} diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoDocumentStore.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoDocumentStore.cs index a921eb153..30956afdc 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoDocumentStore.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoDocumentStore.cs @@ -1,7 +1,8 @@ using Rhino; -using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Utils; +using Speckle.Connectors.RhinoShared; namespace Speckle.Connectors.Rhino.HostApp; @@ -10,12 +11,11 @@ public class RhinoDocumentStore : DocumentModelStore private const string SPECKLE_KEY = "Speckle_DUI3"; public override bool IsDocumentInit { get; set; } = true; // Note: because of rhino implementation details regarding expiry checking of sender cards. - public RhinoDocumentStore(IJsonSerializer jsonSerializer, ITopLevelExceptionHandler topLevelExceptionHandler) + public RhinoDocumentStore(IJsonSerializer jsonSerializer, IEventAggregator eventAggregator) : base(jsonSerializer) { - RhinoDoc.BeginOpenDocument += (_, _) => topLevelExceptionHandler.CatchUnhandled(() => IsDocumentInit = false); - RhinoDoc.EndOpenDocument += (_, e) => - topLevelExceptionHandler.CatchUnhandled(() => + eventAggregator.GetEvent().Subscribe(_ => IsDocumentInit = false); + eventAggregator.GetEvent().Subscribe(e => { if (e.Merge) { @@ -29,7 +29,7 @@ public RhinoDocumentStore(IJsonSerializer jsonSerializer, ITopLevelExceptionHand IsDocumentInit = true; LoadState(); - OnDocumentChanged(); + eventAggregator.GetEvent().Publish(new object()); }); } diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Plugin/Speckle.Connectors.RhinoPlugin.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Plugin/Speckle.Connectors.RhinoPlugin.cs index a1158578e..0624402a9 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Plugin/Speckle.Connectors.RhinoPlugin.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Plugin/Speckle.Connectors.RhinoPlugin.cs @@ -1,7 +1,9 @@ using Microsoft.Extensions.DependencyInjection; using Rhino.PlugIns; using Speckle.Connectors.Common; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.Rhino.DependencyInjection; +using Speckle.Connectors.RhinoShared; using Speckle.Converters.Rhino; using Speckle.Sdk; using Speckle.Sdk.Host; @@ -52,6 +54,7 @@ protected override LoadReturnCode OnLoad(ref string errorMessage) // but the Rhino connector has `.rhp` as it is extension. Container = services.BuildServiceProvider(); + RhinoEvents.Register(Container.GetRequiredService()); // Resolve root plugin object and initialise. _rhinoPlugin = Container.GetRequiredService(); _rhinoPlugin.Initialise(); diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Speckle.Connectors.RhinoShared.projitems b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Speckle.Connectors.RhinoShared.projitems index 42d4d5842..95cf19b91 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Speckle.Connectors.RhinoShared.projitems +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Speckle.Connectors.RhinoShared.projitems @@ -21,6 +21,7 @@ + diff --git a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs index f3f3d946e..80b67373e 100644 --- a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs +++ b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs @@ -1,5 +1,6 @@ using System.Reflection; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; @@ -24,6 +25,8 @@ public static void AddDUI(this IServiceCollectio serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetAssembly(typeof(IdleCallManager))); serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetAssembly(typeof(IServerTransportFactory))); + serviceCollection.AddEventsAsTransient(Assembly.GetAssembly(typeof(TDocumentStore))); + serviceCollection.AddEventsAsTransient(Assembly.GetAssembly(typeof(IdleCallManager))); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(sp => @@ -33,4 +36,20 @@ public static void AddDUI(this IServiceCollectio serviceCollection.AddSingleton(); serviceCollection.AddTransient(); } + + public static IServiceCollection AddEventsAsTransient( + this IServiceCollection serviceCollection, + Assembly assembly + ) + { + foreach (var type in assembly.ExportedTypes.Where(t => t.IsNonAbstractClass())) + { + if (type.FindInterfaces((i, _) => i == typeof(ISpeckleEvent), null).Length != 0) + { + serviceCollection.TryAddTransient(type); + } + } + + return serviceCollection; + } } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs b/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs index bbab25d6d..06296d7eb 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs @@ -4,3 +4,6 @@ namespace Speckle.Connectors.DUI.Eventing; public class ExceptionEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); + +public class DocumentChangedEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/ISpeckleEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/ISpeckleEvent.cs new file mode 100644 index 000000000..0d8e00cc1 --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Eventing/ISpeckleEvent.cs @@ -0,0 +1,6 @@ +namespace Speckle.Connectors.DUI.Eventing; + +public interface ISpeckleEvent +{ + string Name { get; } +} diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs index e76184fae..c234accee 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs @@ -3,9 +3,53 @@ namespace Speckle.Connectors.DUI.Eventing; -public class ThreadedEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : PubSubEvent +public abstract class ThreadedEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : PubSubEvent, ISpeckleEvent where T : notnull { + public string Name { get; } = typeof(T).Name; + public SubscriptionToken Subscribe( + Func> action, + ThreadOption threadOption, + bool keepSubscriberReferenceAlive, + Predicate? filter + ) + { + IDelegateReference actionReference = new DelegateReference(action, keepSubscriberReferenceAlive); + IDelegateReference filterReference; + if (filter != null) + { + filterReference = new DelegateReference(filter, keepSubscriberReferenceAlive); + } + else + { + filterReference = new DelegateReference( + new Predicate( + delegate + { + return true; + } + ), + true + ); + } + EventSubscription subscription; + switch (threadOption) + { + case ThreadOption.WorkerThread: + subscription = new WorkerEventSubscription(actionReference, filterReference, threadContext, exceptionHandler); + break; + case ThreadOption.MainThread: + subscription = new MainThreadEventSubscription(actionReference, filterReference, threadContext, exceptionHandler); + break; + case ThreadOption.PublisherThread: + default: + subscription = new EventSubscription(actionReference, filterReference, exceptionHandler); + break; + } + + return InternalSubscribe(subscription); + } + public override SubscriptionToken Subscribe( Action action, ThreadOption threadOption, diff --git a/DUI3/Speckle.Connectors.DUI/Models/DocumentModelStore.cs b/DUI3/Speckle.Connectors.DUI/Models/DocumentModelStore.cs index 62c4a7984..9b6622c50 100644 --- a/DUI3/Speckle.Connectors.DUI/Models/DocumentModelStore.cs +++ b/DUI3/Speckle.Connectors.DUI/Models/DocumentModelStore.cs @@ -13,12 +13,6 @@ public abstract class DocumentModelStore(IJsonSerializer serializer) { private readonly List _models = new(); - /// - /// This event is triggered by each specific host app implementation of the document model store. - /// - // POC: unsure about the PublicAPI annotation, unsure if this changed handle should live here on the store... :/ - public event EventHandler? DocumentChanged; - //needed for javascript UI public IReadOnlyList Models { @@ -88,8 +82,6 @@ public void RemoveModel(ModelCard model) } } - protected void OnDocumentChanged() => DocumentChanged?.Invoke(this, EventArgs.Empty); - public IEnumerable GetSenders() { lock (_models) From 0816ad69aae177ddb3da64827d94a2d3465490df Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 3 Dec 2024 12:04:28 +0000 Subject: [PATCH 11/16] add more Rhino events and do Idle as OneTime with Id --- .../Bindings/RhinoSelectionBinding.cs | 13 +-- .../Bindings/RhinoSendBinding.cs | 90 +++++++++---------- .../Speckle.Connectors.RhinoShared/Events.cs | 51 ++++++++++- .../Speckle.Connectors.DUI/Eventing/Events.cs | 2 + .../Eventing/MainThreadEventSubscription.cs | 5 +- .../Eventing/OneTimeEventSubscription.cs | 20 +++++ .../Eventing/OneTimeThreadedEvent.cs | 64 +++++++++++++ .../Eventing/PubSubEvent.cs | 2 + .../Eventing/SubscriptionToken.cs | 2 + .../Eventing/ThreadedEvent.cs | 54 ++++------- .../Eventing/WorkerEventSubscription.cs | 5 +- 11 files changed, 210 insertions(+), 98 deletions(-) create mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/OneTimeEventSubscription.cs create mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSelectionBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSelectionBinding.cs index d2679b8b3..81120d80f 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSelectionBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSelectionBinding.cs @@ -2,6 +2,8 @@ using Rhino.DocObjects; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; +using Speckle.Connectors.RhinoShared; namespace Speckle.Connectors.Rhino.Bindings; @@ -13,17 +15,16 @@ public class RhinoSelectionBinding : ISelectionBinding public string Name => "selectionBinding"; public IBrowserBridge Parent { get; } - public RhinoSelectionBinding(IAppIdleManager idleManager, IBrowserBridge parent) + public RhinoSelectionBinding(IAppIdleManager idleManager, IBrowserBridge parent, IEventAggregator eventAggregator) { _idleManager = idleManager; Parent = parent; - - RhinoDoc.SelectObjects += OnSelectionChange; - RhinoDoc.DeselectObjects += OnSelectionChange; - RhinoDoc.DeselectAllObjects += OnSelectionChange; + eventAggregator.GetEvent().Subscribe(OnSelectionChange); + eventAggregator.GetEvent().Subscribe(OnSelectionChange); + eventAggregator.GetEvent().Subscribe(OnSelectionChange); } - private void OnSelectionChange(object? o, EventArgs eventArgs) => + private void OnSelectionChange(EventArgs eventArgs) => _idleManager.SubscribeToIdle(nameof(RhinoSelectionBinding), UpdateSelection); private void UpdateSelection() diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs index 8092841db..252c0e26c 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs @@ -8,14 +8,17 @@ using Speckle.Connectors.Common.Caching; using Speckle.Connectors.Common.Cancellation; using Speckle.Connectors.Common.Operations; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Exceptions; using Speckle.Connectors.DUI.Logging; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Connectors.DUI.Settings; +using Speckle.Connectors.RhinoShared; using Speckle.Converters.Common; using Speckle.Converters.Rhino; using Speckle.Sdk; @@ -38,7 +41,6 @@ public sealed class RhinoSendBinding : ISendBinding private readonly ISendConversionCache _sendConversionCache; private readonly IOperationProgressManager _operationProgressManager; private readonly ILogger _logger; - private readonly ITopLevelExceptionHandler _topLevelExceptionHandler; private readonly IRhinoConversionSettingsFactory _rhinoConversionSettingsFactory; private readonly ISpeckleApplication _speckleApplication; private readonly ISdkActivityFactory _activityFactory; @@ -67,7 +69,7 @@ public RhinoSendBinding( IRhinoConversionSettingsFactory rhinoConversionSettingsFactory, ISpeckleApplication speckleApplication, ISdkActivityFactory activityFactory, - ITopLevelExceptionHandler topLevelExceptionHandler + IEventAggregator eventAggregator ) { _store = store; @@ -80,15 +82,14 @@ ITopLevelExceptionHandler topLevelExceptionHandler _logger = logger; _rhinoConversionSettingsFactory = rhinoConversionSettingsFactory; _speckleApplication = speckleApplication; - _topLevelExceptionHandler = topLevelExceptionHandler; Parent = parent; Commands = new SendBindingUICommands(parent); // POC: Commands are tightly coupled with their bindings, at least for now, saves us injecting a factory. _activityFactory = activityFactory; PreviousUnitSystem = RhinoDoc.ActiveDoc.ModelUnitSystem; - SubscribeToRhinoEvents(); + SubscribeToRhinoEvents(eventAggregator); } - private void SubscribeToRhinoEvents() + private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) { Command.BeginCommand += (_, e) => { @@ -98,14 +99,13 @@ private void SubscribeToRhinoEvents() ChangedObjectIds[selectedObject.Id.ToString()] = 1; } }; - - RhinoDoc.ActiveDocumentChanged += (_, e) => + eventAggregator.GetEvent().Subscribe(e => { PreviousUnitSystem = e.Document.ModelUnitSystem; - }; - + }); + // NOTE: BE CAREFUL handling things in this event handler since it is triggered whenever we save something into file! - RhinoDoc.DocumentPropertiesChanged += async (_, e) => + eventAggregator.GetEvent().Subscribe(async e => { var newUnit = e.Document.ModelUnitSystem; if (newUnit != PreviousUnitSystem) @@ -114,40 +114,37 @@ private void SubscribeToRhinoEvents() await InvalidateAllSender().ConfigureAwait(false); } - }; + }); - RhinoDoc.AddRhinoObject += (_, e) => - _topLevelExceptionHandler.CatchUnhandled(() => - { - // NOTE: This does not work if rhino starts and opens a blank doc; - // These events always happen in a doc. Why guard agains a null doc? - // if (!_store.IsDocumentInit) - // { - // return; - // } - - ChangedObjectIds[e.ObjectId.ToString()] = 1; - _idleManager.SubscribeToIdle(nameof(RhinoSendBinding), RunExpirationChecks); - }); - RhinoDoc.DeleteRhinoObject += (_, e) => - _topLevelExceptionHandler.CatchUnhandled(() => - { - // NOTE: This does not work if rhino starts and opens a blank doc; - // These events always happen in a doc. Why guard agains a null doc? - // if (!_store.IsDocumentInit) - // { - // return; - // } + eventAggregator.GetEvent().Subscribe(e => + { + // NOTE: This does not work if rhino starts and opens a blank doc; + // These events always happen in a doc. Why guard agains a null doc? + // if (!_store.IsDocumentInit) + // { + // return; + // } + ChangedObjectIds[e.ObjectId.ToString()] = 1; + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), async () => await RunExpirationChecks().BackToAny()); + }); + + eventAggregator.GetEvent().Subscribe(e => + { + // NOTE: This does not work if rhino starts and opens a blank doc; + // These events always happen in a doc. Why guard agains a null doc? + // if (!_store.IsDocumentInit) + // { + // return; + // } - ChangedObjectIds[e.ObjectId.ToString()] = 1; - _idleManager.SubscribeToIdle(nameof(RhinoSendBinding), RunExpirationChecks); - }); + ChangedObjectIds[e.ObjectId.ToString()] = 1; + _idleManager.SubscribeToIdle(nameof(RhinoSendBinding), RunExpirationChecks); + }); // NOTE: Catches an object's material change from one user defined doc material to another. Does not catch (as the top event is not triggered) swapping material sources for an object or moving to/from the default material (this is handled below)! - RhinoDoc.RenderMaterialsTableEvent += (_, args) => - _topLevelExceptionHandler.CatchUnhandled(() => - { + eventAggregator.GetEvent().Subscribe(args => + { if (args is RhinoDoc.RenderMaterialAssignmentChangedEventArgs changedEventArgs) { ChangedObjectIds[changedEventArgs.ObjectId.ToString()] = 1; @@ -156,9 +153,8 @@ private void SubscribeToRhinoEvents() }); // Catches and stores changed material ids. These are then used in the expiry checks to invalidate all objects that have assigned any of those material ids. - RhinoDoc.MaterialTableEvent += (_, args) => - _topLevelExceptionHandler.CatchUnhandled(() => - { + eventAggregator.GetEvent().Subscribe(args => + { if (args.EventType == MaterialTableEventType.Modified) { ChangedMaterialIndexes[args.Index] = 1; @@ -166,9 +162,8 @@ private void SubscribeToRhinoEvents() } }); - RhinoDoc.ModifyObjectAttributes += (_, e) => - _topLevelExceptionHandler.CatchUnhandled(() => - { + eventAggregator.GetEvent().Subscribe(e => + { // NOTE: This does not work if rhino starts and opens a blank doc; // These events always happen in a doc. Why guard agains a null doc? // if (!_store.IsDocumentInit) @@ -189,9 +184,8 @@ private void SubscribeToRhinoEvents() } }); - RhinoDoc.ReplaceRhinoObject += (_, e) => - _topLevelExceptionHandler.CatchUnhandled(() => - { + eventAggregator.GetEvent().Subscribe(e => + { // NOTE: This does not work if rhino starts and opens a blank doc; // These events always happen in a doc. Why guard agains a null doc? // if (!_store.IsDocumentInit) diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs index fe2e8423e..737d6a17b 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs @@ -1,22 +1,71 @@ using Rhino; +using Rhino.DocObjects; +using Rhino.DocObjects.Tables; using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Eventing; namespace Speckle.Connectors.RhinoShared; - public class BeginOpenDocument(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); public class EndOpenDocument(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); +public class SelectObjects(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); +public class DeselectObjects(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); +public class DeselectAllObjects(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); + +public class ActiveDocumentChanged(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); +public class DocumentPropertiesChanged(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); +public class AddRhinoObject(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); +public class DeleteRhinoObject(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); +public class RenderMaterialsTableEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); +public class MaterialTableEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); +public class ModifyObjectAttributes(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); +public class ReplaceRhinoObject(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); public static class RhinoEvents { public static void Register(IEventAggregator eventAggregator) { + RhinoApp.Idle += + (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.BeginOpenDocument += (_, e) => eventAggregator.GetEvent().Publish(e); RhinoDoc.EndOpenDocument += (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.SelectObjects += + (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.DeselectObjects += + (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.DeselectAllObjects += + (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.ActiveDocumentChanged += + (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.DocumentPropertiesChanged += + (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.AddRhinoObject += + (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.DeleteRhinoObject += + (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.RenderMaterialsTableEvent += + (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.MaterialTableEvent += + (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.ModifyObjectAttributes += + (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.ReplaceRhinoObject += + (_, e) => eventAggregator.GetEvent().Publish(e); } } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs b/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs index 06296d7eb..ff0c52406 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs @@ -7,3 +7,5 @@ public class ExceptionEvent(IThreadContext threadContext, ITopLevelExceptionHand public class DocumentChangedEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); + +public class IdleEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : OneTimeThreadedEvent(threadContext, exceptionHandler); diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs index 61ea71f4d..3bb53079d 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs @@ -7,8 +7,9 @@ public class MainThreadEventSubscription( IDelegateReference actionReference, IDelegateReference filterReference, IThreadContext threadContext, - ITopLevelExceptionHandler exceptionHandler -) : EventSubscription(actionReference, filterReference, exceptionHandler) + ITopLevelExceptionHandler exceptionHandler, + bool isOnce +) : OneTimeEventSubscription(actionReference, filterReference, exceptionHandler, isOnce) { public override void InvokeAction(Action action, T payload) => threadContext.RunOnMain(() => action.Invoke(payload)); } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeEventSubscription.cs new file mode 100644 index 000000000..f58e102e6 --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeEventSubscription.cs @@ -0,0 +1,20 @@ +using Speckle.Connectors.DUI.Bridge; + +namespace Speckle.Connectors.DUI.Eventing; + +public class OneTimeEventSubscription( + IDelegateReference actionReference, + IDelegateReference filterReference, + ITopLevelExceptionHandler exceptionHandler, + bool isOnce +) : EventSubscription(actionReference, filterReference, exceptionHandler) +{ + public override void InvokeAction(Action action, T payload) + { + action.Invoke(payload); + if (isOnce) + { + SubscriptionToken.Dispose(); + } + } +} diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs new file mode 100644 index 000000000..2b2a29452 --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs @@ -0,0 +1,64 @@ +using Speckle.Connectors.Common.Threading; +using Speckle.Connectors.DUI.Bridge; + +namespace Speckle.Connectors.DUI.Eventing; + +public abstract class OneTimeThreadedEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler) + where T : notnull +{ + private readonly Dictionary _activeTokens = new(); + public SubscriptionToken OneTimeSubscribe( + string id, + Func action, + ThreadOption threadOption, + bool keepSubscriberReferenceAlive, + Predicate? filter + ) + { + return OneTimeInternal(id, t => action(t), threadOption, keepSubscriberReferenceAlive, filter); + } + + public SubscriptionToken OneTimeSubscribe( + string id, + Func action, + ThreadOption threadOption = ThreadOption.PublisherThread, + bool keepSubscriberReferenceAlive = false, + Predicate? filter = null + ) + { + return OneTimeInternal(id, _ => action(), threadOption, keepSubscriberReferenceAlive, filter); + } + + public SubscriptionToken OneTimeSubscribe( + string id, + Action action, + ThreadOption threadOption, + bool keepSubscriberReferenceAlive, + Predicate? filter) + { + return OneTimeInternal(id, action, threadOption, keepSubscriberReferenceAlive, filter); + } + + private SubscriptionToken OneTimeInternal( + string id, + Action action, + ThreadOption threadOption, + bool keepSubscriberReferenceAlive, + Predicate? filter) + { + lock (_activeTokens) + { + if (_activeTokens.TryGetValue(id, out var token)) + { + if (token.IsActive) + { + return token; + } + _activeTokens.Remove(id); + } + token = SubscribeOnceOrNot(action, threadOption, keepSubscriberReferenceAlive, filter, true); + _activeTokens.Add(id, token); + return token; + } + } +} diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs index 929015432..da3c0e27f 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs @@ -74,6 +74,8 @@ public SubscriptionToken Subscribe( bool keepSubscriberReferenceAlive ) => Subscribe(action, threadOption, keepSubscriberReferenceAlive, null); + + /// /// Subscribes a delegate to an event. /// diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/SubscriptionToken.cs b/DUI3/Speckle.Connectors.DUI/Eventing/SubscriptionToken.cs index d7dacbc2e..0fbf912af 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/SubscriptionToken.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/SubscriptionToken.cs @@ -29,6 +29,8 @@ public override bool Equals(object? obj) } public override int GetHashCode() => _token.GetHashCode(); + + public bool IsActive => _unsubscribeAction != null; public void Dispose() { diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs index c234accee..3223ee7f0 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs @@ -8,46 +8,13 @@ public abstract class ThreadedEvent(IThreadContext threadContext, ITopLevelEx { public string Name { get; } = typeof(T).Name; public SubscriptionToken Subscribe( - Func> action, + Func action, ThreadOption threadOption, bool keepSubscriberReferenceAlive, Predicate? filter ) { - IDelegateReference actionReference = new DelegateReference(action, keepSubscriberReferenceAlive); - IDelegateReference filterReference; - if (filter != null) - { - filterReference = new DelegateReference(filter, keepSubscriberReferenceAlive); - } - else - { - filterReference = new DelegateReference( - new Predicate( - delegate - { - return true; - } - ), - true - ); - } - EventSubscription subscription; - switch (threadOption) - { - case ThreadOption.WorkerThread: - subscription = new WorkerEventSubscription(actionReference, filterReference, threadContext, exceptionHandler); - break; - case ThreadOption.MainThread: - subscription = new MainThreadEventSubscription(actionReference, filterReference, threadContext, exceptionHandler); - break; - case ThreadOption.PublisherThread: - default: - subscription = new EventSubscription(actionReference, filterReference, exceptionHandler); - break; - } - - return InternalSubscribe(subscription); + return SubscribeOnceOrNot(t => action(t), threadOption, keepSubscriberReferenceAlive, filter, false); } public override SubscriptionToken Subscribe( @@ -56,6 +23,16 @@ public override SubscriptionToken Subscribe( bool keepSubscriberReferenceAlive, Predicate? filter ) + { + return SubscribeOnceOrNot(action, threadOption, keepSubscriberReferenceAlive, filter, false); + } + + + protected SubscriptionToken SubscribeOnceOrNot(Action action, + ThreadOption threadOption, + bool keepSubscriberReferenceAlive, + Predicate? filter, + bool isOnce) { IDelegateReference actionReference = new DelegateReference(action, keepSubscriberReferenceAlive); IDelegateReference filterReference; @@ -79,17 +56,16 @@ public override SubscriptionToken Subscribe( switch (threadOption) { case ThreadOption.WorkerThread: - subscription = new WorkerEventSubscription(actionReference, filterReference, threadContext, exceptionHandler); + subscription = new WorkerEventSubscription(actionReference, filterReference, threadContext, exceptionHandler, isOnce); break; case ThreadOption.MainThread: - subscription = new MainThreadEventSubscription(actionReference, filterReference, threadContext, exceptionHandler); + subscription = new MainThreadEventSubscription(actionReference, filterReference, threadContext, exceptionHandler, isOnce); break; case ThreadOption.PublisherThread: default: - subscription = new EventSubscription(actionReference, filterReference, exceptionHandler); + subscription = new OneTimeEventSubscription(actionReference, filterReference, exceptionHandler, isOnce); break; } - return InternalSubscribe(subscription); } } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs index a8a03518c..1083987be 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs @@ -7,8 +7,9 @@ public class WorkerEventSubscription( IDelegateReference actionReference, IDelegateReference filterReference, IThreadContext threadContext, - ITopLevelExceptionHandler exceptionHandler -) : EventSubscription(actionReference, filterReference, exceptionHandler) + ITopLevelExceptionHandler exceptionHandler, + bool isOnce +) : OneTimeEventSubscription(actionReference, filterReference, exceptionHandler, isOnce) { public override void InvokeAction(Action action, TPayload argument) => threadContext.RunOnWorker(() => action(argument)); From 20590238299d65e4c96a309a51e16effbd6a446f Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 3 Dec 2024 12:12:44 +0000 Subject: [PATCH 12/16] fix up rhino idle usages --- .../Bindings/RhinoSelectionBinding.cs | 8 +++--- .../Bindings/RhinoSendBinding.cs | 16 +++++------- .../HostApp/RhinoIdleManager.cs | 20 --------------- .../Plugin/RhinoPlugin.cs | 25 ------------------- .../Plugin/Speckle.Connectors.RhinoPlugin.cs | 5 ---- .../Registration/ServiceRegistration.cs | 5 ---- .../Speckle.Connectors.RhinoShared.projitems | 2 -- .../Eventing/OneTimeThreadedEvent.cs | 22 +++++++++++----- 8 files changed, 26 insertions(+), 77 deletions(-) delete mode 100644 Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoIdleManager.cs delete mode 100644 Connectors/Rhino/Speckle.Connectors.RhinoShared/Plugin/RhinoPlugin.cs diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSelectionBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSelectionBinding.cs index 81120d80f..35cdda0ea 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSelectionBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSelectionBinding.cs @@ -9,23 +9,23 @@ namespace Speckle.Connectors.Rhino.Bindings; public class RhinoSelectionBinding : ISelectionBinding { - private readonly IAppIdleManager _idleManager; private const string SELECTION_EVENT = "setSelection"; + private readonly IEventAggregator _eventAggregator; public string Name => "selectionBinding"; public IBrowserBridge Parent { get; } - public RhinoSelectionBinding(IAppIdleManager idleManager, IBrowserBridge parent, IEventAggregator eventAggregator) + public RhinoSelectionBinding(IBrowserBridge parent, IEventAggregator eventAggregator) { - _idleManager = idleManager; Parent = parent; + _eventAggregator = eventAggregator; eventAggregator.GetEvent().Subscribe(OnSelectionChange); eventAggregator.GetEvent().Subscribe(OnSelectionChange); eventAggregator.GetEvent().Subscribe(OnSelectionChange); } private void OnSelectionChange(EventArgs eventArgs) => - _idleManager.SubscribeToIdle(nameof(RhinoSelectionBinding), UpdateSelection); + _eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSelectionBinding), UpdateSelection); private void UpdateSelection() { diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs index 252c0e26c..7a2254161 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs @@ -8,7 +8,6 @@ using Speckle.Connectors.Common.Caching; using Speckle.Connectors.Common.Cancellation; using Speckle.Connectors.Common.Operations; -using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Eventing; @@ -34,7 +33,6 @@ public sealed class RhinoSendBinding : ISendBinding public IBrowserBridge Parent { get; } private readonly DocumentModelStore _store; - private readonly IAppIdleManager _idleManager; private readonly IServiceProvider _serviceProvider; private readonly List _sendFilters; private readonly CancellationManager _cancellationManager; @@ -58,7 +56,6 @@ public sealed class RhinoSendBinding : ISendBinding public RhinoSendBinding( DocumentModelStore store, - IAppIdleManager idleManager, IBrowserBridge parent, IEnumerable sendFilters, IServiceProvider serviceProvider, @@ -73,7 +70,6 @@ IEventAggregator eventAggregator ) { _store = store; - _idleManager = idleManager; _serviceProvider = serviceProvider; _sendFilters = sendFilters.ToList(); _cancellationManager = cancellationManager; @@ -126,7 +122,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) // return; // } ChangedObjectIds[e.ObjectId.ToString()] = 1; - eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), async () => await RunExpirationChecks().BackToAny()); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); }); eventAggregator.GetEvent().Subscribe(e => @@ -139,7 +135,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) // } ChangedObjectIds[e.ObjectId.ToString()] = 1; - _idleManager.SubscribeToIdle(nameof(RhinoSendBinding), RunExpirationChecks); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); }); // NOTE: Catches an object's material change from one user defined doc material to another. Does not catch (as the top event is not triggered) swapping material sources for an object or moving to/from the default material (this is handled below)! @@ -148,7 +144,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) if (args is RhinoDoc.RenderMaterialAssignmentChangedEventArgs changedEventArgs) { ChangedObjectIds[changedEventArgs.ObjectId.ToString()] = 1; - _idleManager.SubscribeToIdle(nameof(RhinoSendBinding), RunExpirationChecks); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); } }); @@ -158,7 +154,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) if (args.EventType == MaterialTableEventType.Modified) { ChangedMaterialIndexes[args.Index] = 1; - _idleManager.SubscribeToIdle(nameof(RhinoSendBinding), RunExpirationChecks); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); } }); @@ -180,7 +176,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) ) { ChangedObjectIds[e.RhinoObject.Id.ToString()] = 1; - _idleManager.SubscribeToIdle(nameof(RhinoSendBinding), RunExpirationChecks); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); } }); @@ -195,7 +191,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) ChangedObjectIds[e.NewRhinoObject.Id.ToString()] = 1; ChangedObjectIds[e.OldRhinoObject.Id.ToString()] = 1; - _idleManager.SubscribeToIdle(nameof(RhinoSendBinding), RunExpirationChecks); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); }); } diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoIdleManager.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoIdleManager.cs deleted file mode 100644 index f536f5786..000000000 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoIdleManager.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Rhino; -using Speckle.Connectors.DUI.Bridge; - -namespace Speckle.Connectors.Rhino.HostApp; - -/// -/// Rhino Idle Manager is a helper util to manage deferred actions. -/// -public sealed class RhinoIdleManager(IIdleCallManager idleCallManager) : AppIdleManager(idleCallManager) -{ - private readonly IIdleCallManager _idleCallManager = idleCallManager; - - protected override void AddEvent() - { - RhinoApp.Idle += RhinoAppOnIdle; - } - - private void RhinoAppOnIdle(object? sender, EventArgs e) => - _idleCallManager.AppOnIdle(() => RhinoApp.Idle -= RhinoAppOnIdle); -} diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Plugin/RhinoPlugin.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Plugin/RhinoPlugin.cs deleted file mode 100644 index 3a060c253..000000000 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Plugin/RhinoPlugin.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Rhino; -using Speckle.Connectors.DUI.Bridge; -using Speckle.Connectors.Rhino.Plugin; -using Speckle.InterfaceGenerator; - -namespace Speckle.Connectors.Rhino.DependencyInjection; - -[GenerateAutoInterface] -public class RhinoPlugin : IRhinoPlugin -{ - private readonly IAppIdleManager _idleManager; - - public RhinoPlugin(IAppIdleManager idleManager) - { - _idleManager = idleManager; - } - - public void Initialise() => - _idleManager.SubscribeToIdle( - nameof(RhinoPlugin), - () => RhinoApp.RunScript(SpeckleConnectorsRhinoCommand.Instance.EnglishName, false) - ); - - public void Shutdown() { } -} diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Plugin/Speckle.Connectors.RhinoPlugin.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Plugin/Speckle.Connectors.RhinoPlugin.cs index 0624402a9..61052675c 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Plugin/Speckle.Connectors.RhinoPlugin.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Plugin/Speckle.Connectors.RhinoPlugin.cs @@ -21,7 +21,6 @@ namespace Speckle.Connectors.Rhino.Plugin; /// public class SpeckleConnectorsRhinoPlugin : PlugIn { - private IRhinoPlugin? _rhinoPlugin; private IDisposable? _disposableLogger; protected override string LocalPlugInName => "Speckle (Beta) for Rhino"; @@ -55,9 +54,6 @@ protected override LoadReturnCode OnLoad(ref string errorMessage) Container = services.BuildServiceProvider(); RhinoEvents.Register(Container.GetRequiredService()); - // Resolve root plugin object and initialise. - _rhinoPlugin = Container.GetRequiredService(); - _rhinoPlugin.Initialise(); return LoadReturnCode.Success; } @@ -81,7 +77,6 @@ private HostAppVersion GetVersion() protected override void OnShutdown() { - _rhinoPlugin?.Shutdown(); _disposableLogger?.Dispose(); Container?.Dispose(); base.OnShutdown(); diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs index 88c7d03da..82bf48c49 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs @@ -11,7 +11,6 @@ using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI; using Speckle.Connectors.DUI.Bindings; -using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Connectors.DUI.WebView; using Speckle.Connectors.Rhino.Bindings; @@ -36,10 +35,6 @@ public static void AddRhino(this IServiceCollection serviceCollection) serviceCollection.AddDUI(); serviceCollection.AddDUIView(); - // Register other connector specific types - serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); - // Register bindings serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); // POC: Easier like this for now, should be cleaned up later diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Speckle.Connectors.RhinoShared.projitems b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Speckle.Connectors.RhinoShared.projitems index 95cf19b91..766cef7d8 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Speckle.Connectors.RhinoShared.projitems +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Speckle.Connectors.RhinoShared.projitems @@ -33,7 +33,6 @@ - @@ -44,7 +43,6 @@ - diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs index 2b2a29452..da5a84844 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs @@ -10,9 +10,9 @@ public abstract class OneTimeThreadedEvent(IThreadContext threadContext, ITop public SubscriptionToken OneTimeSubscribe( string id, Func action, - ThreadOption threadOption, - bool keepSubscriberReferenceAlive, - Predicate? filter + ThreadOption threadOption = ThreadOption.PublisherThread, + bool keepSubscriberReferenceAlive = false, + Predicate? filter = null ) { return OneTimeInternal(id, t => action(t), threadOption, keepSubscriberReferenceAlive, filter); @@ -32,12 +32,22 @@ public SubscriptionToken OneTimeSubscribe( public SubscriptionToken OneTimeSubscribe( string id, Action action, - ThreadOption threadOption, - bool keepSubscriberReferenceAlive, - Predicate? filter) + ThreadOption threadOption = ThreadOption.PublisherThread, + bool keepSubscriberReferenceAlive = false, + Predicate? filter = null) { return OneTimeInternal(id, action, threadOption, keepSubscriberReferenceAlive, filter); } + + public SubscriptionToken OneTimeSubscribe( + string id, + Action action, + ThreadOption threadOption = ThreadOption.PublisherThread, + bool keepSubscriberReferenceAlive = false, + Predicate? filter = null) + { + return OneTimeInternal(id, _ => action(), threadOption, keepSubscriberReferenceAlive, filter); + } private SubscriptionToken OneTimeInternal( string id, From 3f129bf3d22afe041fb490cb900c897ae3508aff Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 3 Dec 2024 12:14:11 +0000 Subject: [PATCH 13/16] fmt --- .../Bindings/BasicConnectorBindingRevit.cs | 10 +- .../Bindings/RevitSendBinding.cs | 10 +- .../HostApp/RevitDocumentStore.cs | 2 +- .../Bindings/RhinoBasicConnectorBinding.cs | 14 ++- .../Bindings/RhinoSelectionBinding.cs | 2 +- .../Bindings/RhinoSendBinding.cs | 103 ++++++++++-------- .../Speckle.Connectors.RhinoShared/Events.cs | 56 +++++----- .../HostApp/RhinoDocumentStore.cs | 4 +- .../Bridge/TopLevelExceptionHandler.cs | 16 +-- .../ContainerRegistration.cs | 7 +- .../Eventing/EventSubscription.cs | 7 +- .../Speckle.Connectors.DUI/Eventing/Events.cs | 8 +- .../Eventing/MainThreadEventSubscription.cs | 3 +- .../Eventing/OneTimeThreadedEvent.cs | 19 ++-- .../Eventing/PubSubEvent.cs | 2 - .../Eventing/SubscriptionToken.cs | 2 +- .../Eventing/ThreadedEvent.cs | 30 +++-- 17 files changed, 170 insertions(+), 125 deletions(-) diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs index 8def57081..df1f85198 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs @@ -39,10 +39,12 @@ IEventAggregator eventAggregator Commands = new BasicConnectorBindingCommands(parent); // POC: event binding? - eventAggregator.GetEvent().Subscribe(async _ => - { - await Commands.NotifyDocumentChanged().ConfigureAwait(false); - }); + eventAggregator + .GetEvent() + .Subscribe(async _ => + { + await Commands.NotifyDocumentChanged().ConfigureAwait(false); + }); } public string GetConnectorVersion() => _speckleApplication.SpeckleVersion; diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs index 6be971914..f9ffd2d1f 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs @@ -83,10 +83,12 @@ ITopLevelExceptionHandler topLevelExceptionHandler revitContext.UIApplication.NotNull().Application.DocumentChanged += (_, e) => topLevelExceptionHandler.CatchUnhandled(() => DocChangeHandler(e)); - eventAggregator.GetEvent().Subscribe(async _ => - { - await OnDocumentChanged().ConfigureAwait(false); - }); + eventAggregator + .GetEvent() + .Subscribe(async _ => + { + await OnDocumentChanged().ConfigureAwait(false); + }); } public List GetSendFilters() => diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs index 151f31789..8ddf7aa58 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs @@ -53,7 +53,7 @@ ITopLevelExceptionHandler topLevelExceptionHandler // There is no event that we can hook here for double-click file open... // It is kind of harmless since we create this object as "SingleInstance". LoadState(); - + eventAggregator.GetEvent().Publish(new object()); } diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoBasicConnectorBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoBasicConnectorBinding.cs index 664606953..d15cfb094 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoBasicConnectorBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoBasicConnectorBinding.cs @@ -37,12 +37,14 @@ IEventAggregator eventAggregator _speckleApplication = speckleApplication; Commands = new BasicConnectorBindingCommands(parent); - eventAggregator.GetEvent().Subscribe(async _ => - { - await Commands.NotifyDocumentChanged().ConfigureAwait(false); - // Note: this prevents scaling issues when copy-pasting from one rhino doc to another in the same session. - _sendConversionCache.ClearCache(); - }); + eventAggregator + .GetEvent() + .Subscribe(async _ => + { + await Commands.NotifyDocumentChanged().ConfigureAwait(false); + // Note: this prevents scaling issues when copy-pasting from one rhino doc to another in the same session. + _sendConversionCache.ClearCache(); + }); } public string GetConnectorVersion() => _speckleApplication.SpeckleVersion; diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSelectionBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSelectionBinding.cs index 35cdda0ea..98b1c9480 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSelectionBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSelectionBinding.cs @@ -25,7 +25,7 @@ public RhinoSelectionBinding(IBrowserBridge parent, IEventAggregator eventAggreg } private void OnSelectionChange(EventArgs eventArgs) => - _eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSelectionBinding), UpdateSelection); + _eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSelectionBinding), UpdateSelection); private void UpdateSelection() { diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs index 7a2254161..a74b5c053 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs @@ -95,52 +95,61 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) ChangedObjectIds[selectedObject.Id.ToString()] = 1; } }; - eventAggregator.GetEvent().Subscribe(e => - { - PreviousUnitSystem = e.Document.ModelUnitSystem; - }); - + eventAggregator + .GetEvent() + .Subscribe(e => + { + PreviousUnitSystem = e.Document.ModelUnitSystem; + }); + // NOTE: BE CAREFUL handling things in this event handler since it is triggered whenever we save something into file! - eventAggregator.GetEvent().Subscribe(async e => - { - var newUnit = e.Document.ModelUnitSystem; - if (newUnit != PreviousUnitSystem) + eventAggregator + .GetEvent() + .Subscribe(async e => { - PreviousUnitSystem = newUnit; + var newUnit = e.Document.ModelUnitSystem; + if (newUnit != PreviousUnitSystem) + { + PreviousUnitSystem = newUnit; - await InvalidateAllSender().ConfigureAwait(false); - } - }); + await InvalidateAllSender().ConfigureAwait(false); + } + }); + eventAggregator + .GetEvent() + .Subscribe(e => + { + // NOTE: This does not work if rhino starts and opens a blank doc; + // These events always happen in a doc. Why guard agains a null doc? + // if (!_store.IsDocumentInit) + // { + // return; + // } + ChangedObjectIds[e.ObjectId.ToString()] = 1; + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); + }); - eventAggregator.GetEvent().Subscribe(e => - { - // NOTE: This does not work if rhino starts and opens a blank doc; - // These events always happen in a doc. Why guard agains a null doc? - // if (!_store.IsDocumentInit) - // { - // return; - // } - ChangedObjectIds[e.ObjectId.ToString()] = 1; - eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); - }); - - eventAggregator.GetEvent().Subscribe(e => - { - // NOTE: This does not work if rhino starts and opens a blank doc; - // These events always happen in a doc. Why guard agains a null doc? - // if (!_store.IsDocumentInit) - // { - // return; - // } + eventAggregator + .GetEvent() + .Subscribe(e => + { + // NOTE: This does not work if rhino starts and opens a blank doc; + // These events always happen in a doc. Why guard agains a null doc? + // if (!_store.IsDocumentInit) + // { + // return; + // } - ChangedObjectIds[e.ObjectId.ToString()] = 1; - eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); - }); + ChangedObjectIds[e.ObjectId.ToString()] = 1; + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); + }); // NOTE: Catches an object's material change from one user defined doc material to another. Does not catch (as the top event is not triggered) swapping material sources for an object or moving to/from the default material (this is handled below)! - eventAggregator.GetEvent().Subscribe(args => - { + eventAggregator + .GetEvent() + .Subscribe(args => + { if (args is RhinoDoc.RenderMaterialAssignmentChangedEventArgs changedEventArgs) { ChangedObjectIds[changedEventArgs.ObjectId.ToString()] = 1; @@ -149,8 +158,10 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) }); // Catches and stores changed material ids. These are then used in the expiry checks to invalidate all objects that have assigned any of those material ids. - eventAggregator.GetEvent().Subscribe(args => - { + eventAggregator + .GetEvent() + .Subscribe(args => + { if (args.EventType == MaterialTableEventType.Modified) { ChangedMaterialIndexes[args.Index] = 1; @@ -158,8 +169,10 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) } }); - eventAggregator.GetEvent().Subscribe(e => - { + eventAggregator + .GetEvent() + .Subscribe(e => + { // NOTE: This does not work if rhino starts and opens a blank doc; // These events always happen in a doc. Why guard agains a null doc? // if (!_store.IsDocumentInit) @@ -180,8 +193,10 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) } }); - eventAggregator.GetEvent().Subscribe(e => - { + eventAggregator + .GetEvent() + .Subscribe(e => + { // NOTE: This does not work if rhino starts and opens a blank doc; // These events always happen in a doc. Why guard agains a null doc? // if (!_store.IsDocumentInit) diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs index 737d6a17b..d5639ed3f 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs @@ -6,31 +6,43 @@ using Speckle.Connectors.DUI.Eventing; namespace Speckle.Connectors.RhinoShared; + public class BeginOpenDocument(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); + public class EndOpenDocument(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); + public class SelectObjects(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); + public class DeselectObjects(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); + public class DeselectAllObjects(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); public class ActiveDocumentChanged(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); + public class DocumentPropertiesChanged(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); + public class AddRhinoObject(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); + public class DeleteRhinoObject(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); + public class RenderMaterialsTableEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); + public class MaterialTableEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); + public class ModifyObjectAttributes(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); + public class ReplaceRhinoObject(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); @@ -38,34 +50,20 @@ public static class RhinoEvents { public static void Register(IEventAggregator eventAggregator) { - RhinoApp.Idle += - (_, e) => eventAggregator.GetEvent().Publish(e); - - RhinoDoc.BeginOpenDocument += - (_, e) => eventAggregator.GetEvent().Publish(e); - RhinoDoc.EndOpenDocument += - (_, e) => eventAggregator.GetEvent().Publish(e); - RhinoDoc.SelectObjects += - (_, e) => eventAggregator.GetEvent().Publish(e); - RhinoDoc.DeselectObjects += - (_, e) => eventAggregator.GetEvent().Publish(e); - RhinoDoc.DeselectAllObjects += - (_, e) => eventAggregator.GetEvent().Publish(e); - RhinoDoc.ActiveDocumentChanged += - (_, e) => eventAggregator.GetEvent().Publish(e); - RhinoDoc.DocumentPropertiesChanged += - (_, e) => eventAggregator.GetEvent().Publish(e); - RhinoDoc.AddRhinoObject += - (_, e) => eventAggregator.GetEvent().Publish(e); - RhinoDoc.DeleteRhinoObject += - (_, e) => eventAggregator.GetEvent().Publish(e); - RhinoDoc.RenderMaterialsTableEvent += - (_, e) => eventAggregator.GetEvent().Publish(e); - RhinoDoc.MaterialTableEvent += - (_, e) => eventAggregator.GetEvent().Publish(e); - RhinoDoc.ModifyObjectAttributes += - (_, e) => eventAggregator.GetEvent().Publish(e); - RhinoDoc.ReplaceRhinoObject += - (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoApp.Idle += (_, e) => eventAggregator.GetEvent().Publish(e); + + RhinoDoc.BeginOpenDocument += (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.EndOpenDocument += (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.SelectObjects += (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.DeselectObjects += (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.DeselectAllObjects += (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.ActiveDocumentChanged += (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.DocumentPropertiesChanged += (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.AddRhinoObject += (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.DeleteRhinoObject += (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.RenderMaterialsTableEvent += (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.MaterialTableEvent += (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.ModifyObjectAttributes += (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.ReplaceRhinoObject += (_, e) => eventAggregator.GetEvent().Publish(e); } } diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoDocumentStore.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoDocumentStore.cs index 30956afdc..2af952d34 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoDocumentStore.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoDocumentStore.cs @@ -15,7 +15,9 @@ public RhinoDocumentStore(IJsonSerializer jsonSerializer, IEventAggregator event : base(jsonSerializer) { eventAggregator.GetEvent().Subscribe(_ => IsDocumentInit = false); - eventAggregator.GetEvent().Subscribe(e => + eventAggregator + .GetEvent() + .Subscribe(e => { if (e.Merge) { diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs index af15e0757..321a63e3c 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs @@ -45,8 +45,8 @@ public Result CatchUnhandled(Action function) { var r = CatchUnhandled(() => { - function(); - return true; + function(); + return true; }); if (r.IsSuccess) { @@ -79,15 +79,17 @@ public Result CatchUnhandled(Func function) throw; } } + /// /// A result pattern struct (where exceptions have been handled) public async Task CatchUnhandledAsync(Func function) { var r = await CatchUnhandledAsync(async () => - { - await function().BackToCurrent(); - return true; - }).BackToCurrent(); + { + await function().BackToCurrent(); + return true; + }) + .BackToCurrent(); if (r.IsSuccess) { return new Result(); @@ -117,7 +119,7 @@ public async Task> CatchUnhandledAsync(Func> function) throw; } } - + /// /// Triggers an async action without explicitly needing to await it.
/// Any thrown by invoking will be handled by the
diff --git a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs index 80b67373e..e9771e951 100644 --- a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs +++ b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs @@ -36,11 +36,8 @@ public static void AddDUI(this IServiceCollectio serviceCollection.AddSingleton(); serviceCollection.AddTransient(); } - - public static IServiceCollection AddEventsAsTransient( - this IServiceCollection serviceCollection, - Assembly assembly - ) + + public static IServiceCollection AddEventsAsTransient(this IServiceCollection serviceCollection, Assembly assembly) { foreach (var type in assembly.ExportedTypes.Where(t => t.IsNonAbstractClass())) { diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs index 5705795fa..25543e4cd 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs @@ -37,8 +37,11 @@ public class EventSubscription : IEventSubscription ///When or are . ///When the target of is not of type , ///or the target of is not of type . - public EventSubscription(IDelegateReference actionReference, IDelegateReference filterReference, - ITopLevelExceptionHandler exceptionHandler) + public EventSubscription( + IDelegateReference actionReference, + IDelegateReference filterReference, + ITopLevelExceptionHandler exceptionHandler + ) { if (actionReference == null) { diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs b/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs index ff0c52406..61354309f 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/Events.cs @@ -3,9 +3,11 @@ namespace Speckle.Connectors.DUI.Eventing; -public class ExceptionEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); +public class ExceptionEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); -public class DocumentChangedEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) +public class DocumentChangedEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); -public class IdleEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : OneTimeThreadedEvent(threadContext, exceptionHandler); +public class IdleEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : OneTimeThreadedEvent(threadContext, exceptionHandler); diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs index 3bb53079d..c524f027f 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs @@ -11,5 +11,6 @@ public class MainThreadEventSubscription( bool isOnce ) : OneTimeEventSubscription(actionReference, filterReference, exceptionHandler, isOnce) { - public override void InvokeAction(Action action, T payload) => threadContext.RunOnMain(() => action.Invoke(payload)); + public override void InvokeAction(Action action, T payload) => + threadContext.RunOnMain(() => action.Invoke(payload)); } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs index da5a84844..db3270e79 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs @@ -3,10 +3,12 @@ namespace Speckle.Connectors.DUI.Eventing; -public abstract class OneTimeThreadedEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler) +public abstract class OneTimeThreadedEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler) where T : notnull { private readonly Dictionary _activeTokens = new(); + public SubscriptionToken OneTimeSubscribe( string id, Func action, @@ -17,7 +19,7 @@ public SubscriptionToken OneTimeSubscribe( { return OneTimeInternal(id, t => action(t), threadOption, keepSubscriberReferenceAlive, filter); } - + public SubscriptionToken OneTimeSubscribe( string id, Func action, @@ -28,23 +30,25 @@ public SubscriptionToken OneTimeSubscribe( { return OneTimeInternal(id, _ => action(), threadOption, keepSubscriberReferenceAlive, filter); } - + public SubscriptionToken OneTimeSubscribe( string id, Action action, ThreadOption threadOption = ThreadOption.PublisherThread, bool keepSubscriberReferenceAlive = false, - Predicate? filter = null) + Predicate? filter = null + ) { return OneTimeInternal(id, action, threadOption, keepSubscriberReferenceAlive, filter); } - + public SubscriptionToken OneTimeSubscribe( string id, Action action, ThreadOption threadOption = ThreadOption.PublisherThread, bool keepSubscriberReferenceAlive = false, - Predicate? filter = null) + Predicate? filter = null + ) { return OneTimeInternal(id, _ => action(), threadOption, keepSubscriberReferenceAlive, filter); } @@ -54,7 +58,8 @@ private SubscriptionToken OneTimeInternal( Action action, ThreadOption threadOption, bool keepSubscriberReferenceAlive, - Predicate? filter) + Predicate? filter + ) { lock (_activeTokens) { diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs index da3c0e27f..929015432 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs @@ -74,8 +74,6 @@ public SubscriptionToken Subscribe( bool keepSubscriberReferenceAlive ) => Subscribe(action, threadOption, keepSubscriberReferenceAlive, null); - - /// /// Subscribes a delegate to an event. /// diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/SubscriptionToken.cs b/DUI3/Speckle.Connectors.DUI/Eventing/SubscriptionToken.cs index 0fbf912af..64f92b127 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/SubscriptionToken.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/SubscriptionToken.cs @@ -29,7 +29,7 @@ public override bool Equals(object? obj) } public override int GetHashCode() => _token.GetHashCode(); - + public bool IsActive => _unsubscribeAction != null; public void Dispose() diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs index 3223ee7f0..30d8ed2de 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs @@ -3,10 +3,13 @@ namespace Speckle.Connectors.DUI.Eventing; -public abstract class ThreadedEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : PubSubEvent, ISpeckleEvent +public abstract class ThreadedEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : PubSubEvent, + ISpeckleEvent where T : notnull { public string Name { get; } = typeof(T).Name; + public SubscriptionToken Subscribe( Func action, ThreadOption threadOption, @@ -16,7 +19,7 @@ public SubscriptionToken Subscribe( { return SubscribeOnceOrNot(t => action(t), threadOption, keepSubscriberReferenceAlive, filter, false); } - + public override SubscriptionToken Subscribe( Action action, ThreadOption threadOption, @@ -27,12 +30,13 @@ public override SubscriptionToken Subscribe( return SubscribeOnceOrNot(action, threadOption, keepSubscriberReferenceAlive, filter, false); } - - protected SubscriptionToken SubscribeOnceOrNot(Action action, + protected SubscriptionToken SubscribeOnceOrNot( + Action action, ThreadOption threadOption, bool keepSubscriberReferenceAlive, Predicate? filter, - bool isOnce) + bool isOnce + ) { IDelegateReference actionReference = new DelegateReference(action, keepSubscriberReferenceAlive); IDelegateReference filterReference; @@ -56,10 +60,22 @@ protected SubscriptionToken SubscribeOnceOrNot(Action action, switch (threadOption) { case ThreadOption.WorkerThread: - subscription = new WorkerEventSubscription(actionReference, filterReference, threadContext, exceptionHandler, isOnce); + subscription = new WorkerEventSubscription( + actionReference, + filterReference, + threadContext, + exceptionHandler, + isOnce + ); break; case ThreadOption.MainThread: - subscription = new MainThreadEventSubscription(actionReference, filterReference, threadContext, exceptionHandler, isOnce); + subscription = new MainThreadEventSubscription( + actionReference, + filterReference, + threadContext, + exceptionHandler, + isOnce + ); break; case ThreadOption.PublisherThread: default: From 75d8c9ab0f7413c3b6a4a3544a7aea8fd934916a Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 5 Dec 2024 13:13:42 +0000 Subject: [PATCH 14/16] Fixes --- .../Bindings/ArcGISSendBinding.cs | 14 +++++++++----- .../Bindings/BasicConnectorBinding.cs | 11 +++++------ .../Utils/ArcGisDocumentStore.cs | 10 +++++++--- .../Bindings/AutocadBasicConnectorBinding.cs | 8 +++++--- .../Bindings/AutocadSendBaseBinding.cs | 10 +++++----- .../Bindings/AutocadSendBinding.cs | 7 +++++-- .../HostApp/AutocadDocumentModelStore.cs | 9 +++++++-- .../Bindings/Civil3dSendBinding.cs | 7 +++++-- .../Bindings/TeklaBasicConnectorBinding.cs | 8 +++++--- .../HostApp/TeklaDocumentModelStore.cs | 8 +++++--- .../Bindings/OperationProgressManager.cs | 2 +- .../Bridge/BrowserBridge.cs | 2 +- .../Bridge/IBrowserBridge.cs | 1 - .../Bridge/TopLevelExceptionHandler.cs | 16 +++++----------- .../Eventing/MainThreadEventSubscription.cs | 2 +- .../Eventing/WorkerEventSubscription.cs | 2 +- 16 files changed, 67 insertions(+), 50 deletions(-) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs index 288b90c9d..2d54c184a 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs @@ -14,6 +14,7 @@ using Speckle.Connectors.Common.Operations; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Exceptions; using Speckle.Connectors.DUI.Logging; using Speckle.Connectors.DUI.Models; @@ -67,7 +68,8 @@ public ArcGISSendBinding( ILogger logger, IArcGISConversionSettingsFactory arcGisConversionSettingsFactory, ITopLevelExceptionHandler topLevelExceptionHandler, - MapMembersUtils mapMemberUtils + MapMembersUtils mapMemberUtils, + IEventAggregator eventAggregator ) { _store = store; @@ -84,10 +86,12 @@ MapMembersUtils mapMemberUtils Parent = parent; Commands = new SendBindingUICommands(parent); SubscribeToArcGISEvents(); - _store.DocumentChanged += (_, _) => - { - _sendConversionCache.ClearCache(); - }; + eventAggregator + .GetEvent() + .Subscribe(_ => + { + _sendConversionCache.ClearCache(); + }); } private void SubscribeToArcGISEvents() diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs index 627ab22d0..49b51a384 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs @@ -3,6 +3,7 @@ using Speckle.Connectors.ArcGIS.Utils; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; using Speckle.Sdk; @@ -25,7 +26,7 @@ public BasicConnectorBinding( DocumentModelStore store, IBrowserBridge parent, ISpeckleApplication speckleApplication, - ITopLevelExceptionHandler topLevelExceptionHandler + IEventAggregator eventAggregator ) { _store = store; @@ -33,11 +34,9 @@ ITopLevelExceptionHandler topLevelExceptionHandler Parent = parent; Commands = new BasicConnectorBindingCommands(parent); - _store.DocumentChanged += (_, _) => - topLevelExceptionHandler.FireAndForget(async () => - { - await Commands.NotifyDocumentChanged().ConfigureAwait(false); - }); + eventAggregator + .GetEvent() + .Subscribe(async _ => await Commands.NotifyDocumentChanged().ConfigureAwait(false)); } public string GetSourceApplicationName() => _speckleApplication.Slug; diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs index 0dd2e7abe..833b28039 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs @@ -4,6 +4,7 @@ using ArcGIS.Desktop.Mapping.Events; using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Utils; @@ -12,15 +13,18 @@ namespace Speckle.Connectors.ArcGIS.Utils; public class ArcGISDocumentStore : DocumentModelStore { private readonly IThreadContext _threadContext; + private readonly IEventAggregator _eventAggregator; public ArcGISDocumentStore( IJsonSerializer jsonSerializer, ITopLevelExceptionHandler topLevelExceptionHandler, - IThreadContext threadContext + IThreadContext threadContext, + IEventAggregator eventAggregator ) : base(jsonSerializer) { _threadContext = threadContext; + _eventAggregator = eventAggregator; ActiveMapViewChangedEvent.Subscribe(a => topLevelExceptionHandler.CatchUnhandled(() => OnMapViewChanged(a)), true); ProjectSavingEvent.Subscribe( _ => @@ -44,7 +48,7 @@ IThreadContext threadContext { IsDocumentInit = true; LoadState(); - OnDocumentChanged(); + eventAggregator.GetEvent().Publish(new object()); } } @@ -78,7 +82,7 @@ private void OnMapViewChanged(ActiveMapViewChangedEventArgs args) IsDocumentInit = true; LoadState(); - OnDocumentChanged(); + _eventAggregator.GetEvent().Publish(new object()); } protected override void HostAppSaveState(string modelCardState) => diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs index 65ff9c7f1..8e16322c7 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs @@ -4,6 +4,7 @@ using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; using Speckle.Sdk; @@ -31,7 +32,7 @@ public AutocadBasicConnectorBinding( IAccountManager accountManager, ISpeckleApplication speckleApplication, ILogger logger, - ITopLevelExceptionHandler topLevelExceptionHandler, + IEventAggregator eventAggregator, IThreadContext threadContext ) { @@ -40,8 +41,9 @@ IThreadContext threadContext _accountManager = accountManager; _speckleApplication = speckleApplication; Commands = new BasicConnectorBindingCommands(parent); - _store.DocumentChanged += (_, _) => - topLevelExceptionHandler.FireAndForget(async () => + eventAggregator + .GetEvent() + .Subscribe(async _ => { await Commands.NotifyDocumentChanged().ConfigureAwait(false); }); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs index 77048c950..eba1d47e0 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs @@ -11,6 +11,7 @@ using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Exceptions; using Speckle.Connectors.DUI.Logging; using Speckle.Connectors.DUI.Models; @@ -61,7 +62,8 @@ protected AutocadSendBaseBinding( ILogger logger, ISpeckleApplication speckleApplication, ITopLevelExceptionHandler topLevelExceptionHandler, - IThreadContext threadContext + IThreadContext threadContext, + IEventAggregator eventAggregator ) { _store = store; @@ -87,10 +89,8 @@ IThreadContext threadContext SubscribeToObjectChanges(Application.DocumentManager.CurrentDocument); } // Since ids of the objects generates from same seed, we should clear the cache always whenever doc swapped. - _store.DocumentChanged += (_, _) => - { - _sendConversionCache.ClearCache(); - }; + + eventAggregator.GetEvent().Subscribe(_ => _sendConversionCache.ClearCache()); } private readonly List _docSubsTracker = new(); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs index 65b14ab1a..e222636c6 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs @@ -6,6 +6,7 @@ using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Converters.Autocad; @@ -31,7 +32,8 @@ public AutocadSendBinding( IAutocadConversionSettingsFactory autocadConversionSettingsFactory, ISpeckleApplication speckleApplication, ITopLevelExceptionHandler topLevelExceptionHandler, - IThreadContext threadContext + IThreadContext threadContext, + IEventAggregator eventAggregator ) : base( store, @@ -45,7 +47,8 @@ IThreadContext threadContext logger, speckleApplication, topLevelExceptionHandler, - threadContext + threadContext, + eventAggregator ) { _autocadConversionSettingsFactory = autocadConversionSettingsFactory; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadDocumentModelStore.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadDocumentModelStore.cs index c8319d638..04c68ab29 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadDocumentModelStore.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadDocumentModelStore.cs @@ -1,4 +1,5 @@ using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Utils; @@ -9,15 +10,18 @@ public class AutocadDocumentStore : DocumentModelStore private readonly string _nullDocumentName = "Null Doc"; private string _previousDocName; private readonly AutocadDocumentManager _autocadDocumentManager; + private readonly IEventAggregator _eventAggregator; public AutocadDocumentStore( IJsonSerializer jsonSerializer, AutocadDocumentManager autocadDocumentManager, - ITopLevelExceptionHandler topLevelExceptionHandler + ITopLevelExceptionHandler topLevelExceptionHandler, + IEventAggregator eventAggregator ) : base(jsonSerializer) { _autocadDocumentManager = autocadDocumentManager; + _eventAggregator = eventAggregator; _previousDocName = _nullDocumentName; // POC: Will be addressed to move it into AutocadContext! @@ -48,7 +52,8 @@ private void OnDocChangeInternal(Document? doc) _previousDocName = currentDocName; LoadState(); - OnDocumentChanged(); + LoadState(); + _eventAggregator.GetEvent().Publish(new object()); } protected override void LoadState() diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs index 57a120595..3ff8e014e 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs @@ -7,6 +7,7 @@ using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Converters.Autocad; @@ -35,7 +36,8 @@ public Civil3dSendBinding( IAutocadConversionSettingsFactory autocadConversionSettingsFactory, ISpeckleApplication speckleApplication, ITopLevelExceptionHandler topLevelExceptionHandler, - IThreadContext threadContext + IThreadContext threadContext, + IEventAggregator eventAggregator ) : base( store, @@ -49,7 +51,8 @@ IThreadContext threadContext logger, speckleApplication, topLevelExceptionHandler, - threadContext + threadContext, + eventAggregator ) { _civil3dConversionSettingsFactory = civil3dConversionSettingsFactory; diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaBasicConnectorBinding.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaBasicConnectorBinding.cs index 60f3f13a9..0856f6996 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaBasicConnectorBinding.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaBasicConnectorBinding.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Logging; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; using Speckle.Sdk; @@ -25,7 +26,7 @@ public TeklaBasicConnectorBinding( ISpeckleApplication speckleApplication, DocumentModelStore store, ILogger logger, - ITopLevelExceptionHandler topLevelExceptionHandler, + IEventAggregator eventAggregator, TSM.Model model ) { @@ -35,8 +36,9 @@ TSM.Model model _logger = logger; _model = model; Commands = new BasicConnectorBindingCommands(parent); - _store.DocumentChanged += (_, _) => - topLevelExceptionHandler.FireAndForget(async () => + eventAggregator + .GetEvent() + .Subscribe(async _ => { await Commands.NotifyDocumentChanged().ConfigureAwait(false); }); diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/HostApp/TeklaDocumentModelStore.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/HostApp/TeklaDocumentModelStore.cs index bae477566..253d1d2ec 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/HostApp/TeklaDocumentModelStore.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/HostApp/TeklaDocumentModelStore.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Logging; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Utils; using Speckle.Sdk; @@ -18,7 +19,8 @@ public class TeklaDocumentModelStore : DocumentModelStore public TeklaDocumentModelStore( IJsonSerializer jsonSerializer, ILogger logger, - ISqLiteJsonCacheManagerFactory jsonCacheManagerFactory + ISqLiteJsonCacheManagerFactory jsonCacheManagerFactory, + IEventAggregator eventAggregator ) : base(jsonSerializer) { @@ -31,13 +33,13 @@ ISqLiteJsonCacheManagerFactory jsonCacheManagerFactory { GenerateKey(); LoadState(); - OnDocumentChanged(); + eventAggregator.GetEvent().Publish(new object()); }; _events.Register(); if (SpeckleTeklaPanelHost.IsInitialized) { LoadState(); - OnDocumentChanged(); + eventAggregator.GetEvent().Publish(new object()); } } diff --git a/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs b/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs index 1fa0b57fe..d5923dc30 100644 --- a/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs +++ b/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs @@ -11,7 +11,7 @@ namespace Speckle.Connectors.DUI.Bindings; /// This class requires a specific bridge in its binding, so registering it will create random bridge which we don't want to. /// [GenerateAutoInterface] -public class OperationProgressManager(ITopLevelExceptionHandler topLevelExceptionHandler) : IOperationProgressManager +public class OperationProgressManager : IOperationProgressManager { private class NonUIThreadProgress(Action handler) : IProgress { diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 437fe004f..6b72c6e99 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -134,7 +134,7 @@ public void RunMethod(string methodName, string requestId, string methodArgs) => .RunOnThreadAsync( async () => { - var task = await TopLevelExceptionHandler + var task = await _topLevelExceptionHandler .CatchUnhandledAsync(async () => { var result = await ExecuteMethod(methodName, methodArgs).ConfigureAwait(false); diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs index 65ec766df..20c85708f 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs @@ -42,5 +42,4 @@ public Task Send(string eventName, T data, CancellationToken cancellationToke public void Send2(string eventName, T data) where T : class; - public ITopLevelExceptionHandler TopLevelExceptionHandler { get; } } diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs index 2c3726a49..f386d6926 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.Logging; using Speckle.Connectors.Common.Threading; -using Speckle.Connectors.DUI.Bindings; +using Speckle.Connectors.DUI.Eventing; using Speckle.InterfaceGenerator; using Speckle.Sdk; @@ -64,19 +64,12 @@ public Result CatchUnhandled(Func function) { try { - await function().BackToCurrent(); - return new Result(); + return new Result(function()); } catch (Exception ex) when (!ex.IsFatal()) { _logger.LogError(ex, UNHANDLED_LOGGER_TEMPLATE); - await SetGlobalNotification( - ToastNotificationType.DANGER, - "Unhandled Exception Occured", - ex.ToFormattedString(), - false - ) - .BackToCurrent(); + _eventAggregator.GetEvent().Publish(ex); return new(ex); } } @@ -115,7 +108,8 @@ public async Task> CatchUnhandledAsync(Func> function) } catch (Exception ex) when (!ex.IsFatal()) { - await HandleException(ex).BackToCurrent(); + _logger.LogError(ex, UNHANDLED_LOGGER_TEMPLATE); + _eventAggregator.GetEvent().Publish(ex); return new(ex); } } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs index c524f027f..1b9519e49 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs @@ -12,5 +12,5 @@ bool isOnce ) : OneTimeEventSubscription(actionReference, filterReference, exceptionHandler, isOnce) { public override void InvokeAction(Action action, T payload) => - threadContext.RunOnMain(() => action.Invoke(payload)); + threadContext.RunOnMain(() => action.Invoke(payload)).BackToCurrent(); } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs index 1083987be..82d9c74ea 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs @@ -12,5 +12,5 @@ bool isOnce ) : OneTimeEventSubscription(actionReference, filterReference, exceptionHandler, isOnce) { public override void InvokeAction(Action action, TPayload argument) => - threadContext.RunOnWorker(() => action(argument)); + threadContext.RunOnWorker(() => action(argument)).BackToCurrent(); } From 03a11b9eff22a16763fd15f15438212663c40296 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 5 Dec 2024 13:31:15 +0000 Subject: [PATCH 15/16] Convert tekla --- .../Bindings/TeklaSelectionBinding.cs | 15 +++++---- .../Bindings/TeklaSendBinding.cs | 31 ++++-------------- .../Speckle.Connector.TeklaShared/Events.cs | 27 ++++++++++++++++ .../HostApp/TeklaDocumentModelStore.cs | 18 +++++------ .../HostApp/TeklaIdleManager.cs | 32 ------------------- .../ServiceRegistration.cs | 2 -- .../Speckle.Connectors.TeklaShared.projitems | 2 +- .../SpeckleTeklaPanelHost.cs | 3 ++ 8 files changed, 54 insertions(+), 76 deletions(-) create mode 100644 Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs delete mode 100644 Connectors/Tekla/Speckle.Connector.TeklaShared/HostApp/TeklaIdleManager.cs diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs index 5a416e14d..e8261c8be 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs @@ -1,5 +1,7 @@ using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; +using Speckle.Connectors.RhinoShared; using Tekla.Structures.Model; namespace Speckle.Connectors.TeklaShared.Bindings; @@ -8,9 +10,9 @@ public class TeklaSelectionBinding : ISelectionBinding { private readonly IAppIdleManager _idleManager; private const string SELECTION_EVENT = "setSelection"; - private readonly Tekla.Structures.Model.Events _events; private readonly object _selectionEventHandlerLock = new object(); private readonly Tekla.Structures.Model.UI.ModelObjectSelector _selector; + private readonly IEventAggregator _eventAggregator; public string Name => "selectionBinding"; public IBrowserBridge Parent { get; } @@ -18,24 +20,23 @@ public class TeklaSelectionBinding : ISelectionBinding public TeklaSelectionBinding( IAppIdleManager idleManager, IBrowserBridge parent, - Events events, - Tekla.Structures.Model.UI.ModelObjectSelector selector + Tekla.Structures.Model.UI.ModelObjectSelector selector, + IEventAggregator eventAggregator ) { _idleManager = idleManager; Parent = parent; - _events = events; _selector = selector; + _eventAggregator = eventAggregator; - _events.SelectionChange += Events_SelectionChangeEvent; - _events.Register(); + eventAggregator.GetEvent().Subscribe(_ => Events_SelectionChangeEvent()); } private void Events_SelectionChangeEvent() { lock (_selectionEventHandlerLock) { - _idleManager.SubscribeToIdle(nameof(TeklaSelectionBinding), UpdateSelection); + _eventAggregator.GetEvent().OneTimeSubscribe(nameof(TeklaSelectionBinding), UpdateSelection); } } diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs index 54d99146e..495458cd2 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs @@ -6,12 +6,14 @@ using Speckle.Connectors.Common.Operations; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Exceptions; using Speckle.Connectors.DUI.Logging; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Connectors.DUI.Settings; +using Speckle.Connectors.RhinoShared; using Speckle.Connectors.TeklaShared.Operations.Send.Settings; using Speckle.Converters.Common; using Speckle.Converters.TeklaShared; @@ -24,14 +26,13 @@ namespace Speckle.Connectors.TeklaShared.Bindings; -public sealed class TeklaSendBinding : ISendBinding, IDisposable +public sealed class TeklaSendBinding : ISendBinding { public string Name => "sendBinding"; public SendBindingUICommands Commands { get; } public IBrowserBridge Parent { get; } private readonly DocumentModelStore _store; - private readonly IAppIdleManager _idleManager; private readonly IServiceProvider _serviceProvider; private readonly List _sendFilters; private readonly CancellationManager _cancellationManager; @@ -42,14 +43,12 @@ public sealed class TeklaSendBinding : ISendBinding, IDisposable private readonly ISpeckleApplication _speckleApplication; private readonly ISdkActivityFactory _activityFactory; private readonly Model _model; - private readonly Events _events; private readonly ToSpeckleSettingsManager _toSpeckleSettingsManager; private ConcurrentDictionary ChangedObjectIds { get; set; } = new(); public TeklaSendBinding( DocumentModelStore store, - IAppIdleManager idleManager, IBrowserBridge parent, IEnumerable sendFilters, IServiceProvider serviceProvider, @@ -60,11 +59,11 @@ public TeklaSendBinding( ITeklaConversionSettingsFactory teklaConversionSettingsFactory, ISpeckleApplication speckleApplication, ISdkActivityFactory activityFactory, - ToSpeckleSettingsManager toSpeckleSettingsManager + ToSpeckleSettingsManager toSpeckleSettingsManager, + IEventAggregator eventAggregator ) { _store = store; - _idleManager = idleManager; _serviceProvider = serviceProvider; _sendFilters = sendFilters.ToList(); _cancellationManager = cancellationManager; @@ -79,14 +78,7 @@ ToSpeckleSettingsManager toSpeckleSettingsManager _toSpeckleSettingsManager = toSpeckleSettingsManager; _model = new Model(); - _events = new Events(); - SubscribeToTeklaEvents(); - } - - private void SubscribeToTeklaEvents() - { - _events.ModelObjectChanged += ModelHandler_OnChange; - _events.Register(); + eventAggregator.GetEvent().Subscribe(ModelHandler_OnChange); } // subscribes the all changes in a modelobject @@ -198,15 +190,4 @@ private async Task RunExpirationChecks() ChangedObjectIds = new ConcurrentDictionary(); } - - private bool _disposed; - - public void Dispose() - { - if (!_disposed) - { - _events.UnRegister(); - _disposed = true; - } - } } diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs new file mode 100644 index 000000000..964ac2acc --- /dev/null +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs @@ -0,0 +1,27 @@ +using Speckle.Connectors.Common.Threading; +using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Eventing; + +namespace Speckle.Connectors.RhinoShared; + +public class SelectionChange(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); + +public class ModelObjectChanged(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent>(threadContext, exceptionHandler); + +public class ModelLoad(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); + +public static class TeklaEvents +{ + public static void Register(Tekla.Structures.Model.Events events, IEventAggregator eventAggregator) + { + events.UnRegister(); + events.ModelSave += () => eventAggregator.GetEvent().Publish(new object()); + events.SelectionChange += () => eventAggregator.GetEvent().Publish(new object()); + events.ModelObjectChanged += x => eventAggregator.GetEvent().Publish(x); + events.ModelLoad += () => eventAggregator.GetEvent().Publish(new object()); + events.Register(); + } +} diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/HostApp/TeklaDocumentModelStore.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/HostApp/TeklaDocumentModelStore.cs index 253d1d2ec..5cd425b1f 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/HostApp/TeklaDocumentModelStore.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/HostApp/TeklaDocumentModelStore.cs @@ -2,6 +2,7 @@ using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Utils; +using Speckle.Connectors.RhinoShared; using Speckle.Sdk; using Speckle.Sdk.Helpers; using Speckle.Sdk.SQLite; @@ -12,7 +13,6 @@ public class TeklaDocumentModelStore : DocumentModelStore { private readonly ILogger _logger; private readonly ISqLiteJsonCacheManager _jsonCacheManager; - private readonly TSM.Events _events; private readonly TSM.Model _model; private string? _modelKey; @@ -26,16 +26,16 @@ IEventAggregator eventAggregator { _logger = logger; _jsonCacheManager = jsonCacheManagerFactory.CreateForUser("ConnectorsFileData"); - _events = new TSM.Events(); _model = new TSM.Model(); GenerateKey(); - _events.ModelLoad += () => - { - GenerateKey(); - LoadState(); - eventAggregator.GetEvent().Publish(new object()); - }; - _events.Register(); + eventAggregator + .GetEvent() + .Publish(() => + { + GenerateKey(); + LoadState(); + eventAggregator.GetEvent().Publish(new object()); + }); if (SpeckleTeklaPanelHost.IsInitialized) { LoadState(); diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/HostApp/TeklaIdleManager.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/HostApp/TeklaIdleManager.cs deleted file mode 100644 index 851020e61..000000000 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/HostApp/TeklaIdleManager.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Speckle.Connectors.DUI.Bridge; -using Tekla.Structures.Model; - -namespace Speckle.Connectors.TeklaShared.HostApp; - -public sealed class TeklaIdleManager : AppIdleManager -{ - private readonly IIdleCallManager _idleCallManager; - private readonly Events _events; - - public TeklaIdleManager(IIdleCallManager idleCallManager, Events events) - : base(idleCallManager) - { - _idleCallManager = idleCallManager; - _events = events; - } - - protected override void AddEvent() - { - _events.ModelSave += TeklaEventsOnIdle; - _events.Register(); - } - - private void TeklaEventsOnIdle() - { - _idleCallManager.AppOnIdle(() => - { - _events.ModelSave -= TeklaEventsOnIdle; - _events.UnRegister(); - }); - } -} diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs index e7f5f0620..f058061e8 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs @@ -35,8 +35,6 @@ public static IServiceCollection AddTekla(this IServiceCollection services) services.AddDUI(); services.AddDUIView(); - services.AddSingleton(); - services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Speckle.Connectors.TeklaShared.projitems b/Connectors/Tekla/Speckle.Connector.TeklaShared/Speckle.Connectors.TeklaShared.projitems index e9782ec4d..330527ed7 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Speckle.Connectors.TeklaShared.projitems +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Speckle.Connectors.TeklaShared.projitems @@ -17,13 +17,13 @@ + - diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/SpeckleTeklaPanelHost.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/SpeckleTeklaPanelHost.cs index e957a4d17..b7a938698 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/SpeckleTeklaPanelHost.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/SpeckleTeklaPanelHost.cs @@ -5,7 +5,9 @@ using System.Windows.Forms.Integration; using Microsoft.Extensions.DependencyInjection; using Speckle.Connectors.Common; +using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.DUI.WebView; +using Speckle.Connectors.RhinoShared; using Speckle.Converters.TeklaShared; using Speckle.Sdk.Host; using Tekla.Structures.Dialog; @@ -89,6 +91,7 @@ private void InitializeInstance() services.AddTeklaConverters(); Container = services.BuildServiceProvider(); + TeklaEvents.Register(Container.GetRequiredService(), Container.GetRequiredService()); Model = new Model(); if (!Model.GetConnectionStatus()) From b99206bf8f2ed45124fad5f09d7b1686be9fefb0 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 5 Dec 2024 13:46:22 +0000 Subject: [PATCH 16/16] selection event is used without idle --- .../Bindings/TeklaSelectionBinding.cs | 7 ++----- Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs index e8261c8be..5cfd403c9 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs @@ -8,7 +8,6 @@ namespace Speckle.Connectors.TeklaShared.Bindings; public class TeklaSelectionBinding : ISelectionBinding { - private readonly IAppIdleManager _idleManager; private const string SELECTION_EVENT = "setSelection"; private readonly object _selectionEventHandlerLock = new object(); private readonly Tekla.Structures.Model.UI.ModelObjectSelector _selector; @@ -18,13 +17,11 @@ public class TeklaSelectionBinding : ISelectionBinding public IBrowserBridge Parent { get; } public TeklaSelectionBinding( - IAppIdleManager idleManager, IBrowserBridge parent, Tekla.Structures.Model.UI.ModelObjectSelector selector, IEventAggregator eventAggregator ) { - _idleManager = idleManager; Parent = parent; _selector = selector; _eventAggregator = eventAggregator; @@ -36,14 +33,14 @@ private void Events_SelectionChangeEvent() { lock (_selectionEventHandlerLock) { - _eventAggregator.GetEvent().OneTimeSubscribe(nameof(TeklaSelectionBinding), UpdateSelection); + UpdateSelection(); } } private void UpdateSelection() { SelectionInfo selInfo = GetSelection(); - Parent.Send(SELECTION_EVENT, selInfo); + Parent.Send2(SELECTION_EVENT, selInfo); } public SelectionInfo GetSelection() diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs index 964ac2acc..24b749eef 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs @@ -18,7 +18,6 @@ public static class TeklaEvents public static void Register(Tekla.Structures.Model.Events events, IEventAggregator eventAggregator) { events.UnRegister(); - events.ModelSave += () => eventAggregator.GetEvent().Publish(new object()); events.SelectionChange += () => eventAggregator.GetEvent().Publish(new object()); events.ModelObjectChanged += x => eventAggregator.GetEvent().Publish(x); events.ModelLoad += () => eventAggregator.GetEvent().Publish(new object());