From c09fd83b2c7b0b1dfacb0377eb2238ba16194f53 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 21 Nov 2024 08:36:01 +0000 Subject: [PATCH 01/65] Remove Dataflow usage --- .../Bridge/IdleCallManagerTests.cs | 2 +- .../Bridge/BrowserBridge.cs | 68 +++++-------------- .../Bridge/TopLevelExceptionHandler.cs | 31 +++++++-- 3 files changed, 43 insertions(+), 58 deletions(-) diff --git a/DUI3/Speckle.Connectors.DUI.Tests/Bridge/IdleCallManagerTests.cs b/DUI3/Speckle.Connectors.DUI.Tests/Bridge/IdleCallManagerTests.cs index ecbb6ebaa..9c8397023 100644 --- a/DUI3/Speckle.Connectors.DUI.Tests/Bridge/IdleCallManagerTests.cs +++ b/DUI3/Speckle.Connectors.DUI.Tests/Bridge/IdleCallManagerTests.cs @@ -56,7 +56,7 @@ public async Task AppOnIdleInternalTest() handler .Setup(m => m.CatchUnhandledAsync(It.IsAny>())) .Callback>(a => a.Invoke()) - .Returns(Task.CompletedTask); + .ReturnsAsync(new Result()); var removeEvent = Create(); removeEvent.Setup(x => x.Invoke()); diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 376070bfc..812182f03 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -3,7 +3,6 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.InteropServices; -using System.Threading.Tasks.Dataflow; using Microsoft.Extensions.Logging; using Speckle.Connectors.DUI.Bindings; using Speckle.Newtonsoft.Json; @@ -33,8 +32,6 @@ public sealed class BrowserBridge : IBrowserBridge private readonly IBrowserScriptExecutor _browserScriptExecutor; private IReadOnlyDictionary _bindingMethodCache = new Dictionary(); - - private ActionBlock? _actionBlock; private IBinding? _binding; private Type? _bindingType; @@ -100,30 +97,9 @@ public void AssociateWithBinding(IBinding binding) bindingMethodCache[m.Name] = m; } _bindingMethodCache = bindingMethodCache; - - // Whenever the ui will call run method inside .net, it will post a message to this action block. - // This conveniently executes the code outside the UI thread and does not block during long operations (such as sending). - _actionBlock = new ActionBlock( - OnActionBlock, - new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1000 } - ); - _logger.LogInformation("Bridge bound to front end name {FrontEndName}", binding.Name); } - - private async Task OnActionBlock(RunMethodArgs args) - { - Result result = await TopLevelExceptionHandler - .CatchUnhandledAsync(async () => await ExecuteMethod(args.MethodName, args.MethodArgs).ConfigureAwait(false)) - .ConfigureAwait(false); - - string resultJson = result.IsSuccess - ? JsonConvert.SerializeObject(result.Value, _serializerOptions) - : SerializeFormattedException(result.Exception); - - await NotifyUIMethodCallResultReady(args.RequestId, resultJson).ConfigureAwait(false); - } - + /// /// Used by the Frontend bridge logic to understand which methods are available. /// @@ -141,32 +117,25 @@ public string[] GetBindingsMethodNames() /// /// /// - public void RunMethod(string methodName, string requestId, string args) - { - TopLevelExceptionHandler.CatchUnhandled(Post); - return; - - void Post() + public void RunMethod(string methodName, string requestId, string args) => + _mainThreadContext.Post(async x => { - bool wasAccepted = _actionBlock - .NotNull() - .Post( - new RunMethodArgs - { - MethodName = methodName, - RequestId = requestId, - MethodArgs = args - } - ); - if (!wasAccepted) + var runMethodArgs = (RunMethodArgs)x; + var task = await TopLevelExceptionHandler.CatchUnhandledAsync(async () => { - throw new InvalidOperationException($"Action block declined to Post ({methodName} {requestId} {args})"); + var result = await ExecuteMethod(runMethodArgs.MethodName, runMethodArgs.MethodArgs).ConfigureAwait(false); + + string resultJson = JsonConvert.SerializeObject(result, _serializerOptions); + await NotifyUIMethodCallResultReady(runMethodArgs.RequestId, resultJson).ConfigureAwait(false); + }).ConfigureAwait(false); + if (task.Exception is not null) + { + string resultJson = SerializeFormattedException(task.Exception); + await NotifyUIMethodCallResultReady(runMethodArgs.RequestId, resultJson).ConfigureAwait(false); } - } - } + }, new RunMethodArgs { MethodName = methodName, RequestId = requestId, MethodArgs = args }); - public void RunOnMainThread(Action action) - { + public void RunOnMainThread(Action action) => _mainThreadContext.Post( _ => { @@ -175,17 +144,14 @@ public void RunOnMainThread(Action action) }, null ); - } - public async Task RunOnMainThreadAsync(Func action) - { + public async Task RunOnMainThreadAsync(Func action) => await RunOnMainThreadAsync(async () => { await action.Invoke().ConfigureAwait(false); return null; }) .ConfigureAwait(false); - } [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] public Task RunOnMainThreadAsync(Func> action) diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs index a39ff0bc2..730c24f27 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs @@ -58,14 +58,33 @@ public Result CatchUnhandled(Func function) => /// /// A result pattern struct (where exceptions have been handled) - public async Task CatchUnhandledAsync(Func function) + public async Task CatchUnhandledAsync(Func function) { - _ = await CatchUnhandledAsync(async () => + try + { + try { - await function().ConfigureAwait(false); - return null; - }) - .ConfigureAwait(false); + await function().ConfigureAwait(false); + return new Result(); + } + catch (Exception ex) when (!ex.IsFatal()) + { + _logger.LogError(ex, UNHANDLED_LOGGER_TEMPLATE); + await SetGlobalNotification( + ToastNotificationType.DANGER, + "Unhandled Exception Occured", + ex.ToFormattedString(), + false + ) + .ConfigureAwait(false); + return new(ex); + } + } + catch (Exception ex) + { + _logger.LogCritical(ex, UNHANDLED_LOGGER_TEMPLATE); + throw; + } } /// From 01cd963381168b749a01464aa72aec1820770d31 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 21 Nov 2024 08:38:31 +0000 Subject: [PATCH 02/65] format and remove dep --- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 9 +---- .../packages.lock.json | 18 +-------- .../Bridge/BrowserBridge.cs | 38 ++++++++++++------- .../Bridge/TopLevelExceptionHandler.cs | 4 +- .../Speckle.Connectors.DUI.csproj | 1 - .../Speckle.Connectors.DUI/packages.lock.json | 6 --- Directory.Packages.props | 1 - 27 files changed, 49 insertions(+), 208 deletions(-) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json index 4c6216f4c..9480fc911 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json @@ -242,8 +242,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -328,12 +327,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } }, "net6.0-windows7.0/win-x64": { diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json index 18ad52afa..522fc2527 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json @@ -275,8 +275,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -367,12 +366,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json index ee5fae814..6e8c11b5c 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json @@ -275,8 +275,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -367,12 +366,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json index 186d76755..c19180674 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json @@ -275,8 +275,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -368,12 +367,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json index 6f245f17a..0355bd0b7 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json @@ -231,8 +231,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -323,12 +322,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } }, "net8.0-windows7.0/win-x64": { diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json index 39cc05f8f..d96f3f2bd 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json @@ -284,8 +284,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -377,12 +376,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json index 8b4ecf135..6fd6ec9e2 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json @@ -284,8 +284,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -377,12 +376,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json index 1fb27a375..efc612093 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json @@ -284,8 +284,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -377,12 +376,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json index 96510ed1e..0e9d82023 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json @@ -240,8 +240,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -333,12 +332,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } }, "net8.0-windows7.0/win-x64": { diff --git a/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json index 400a783ea..f2aa57210 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json @@ -303,8 +303,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.logging": { @@ -388,12 +387,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json index cdd6206b0..337e01dc6 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json @@ -303,8 +303,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.logging": { @@ -388,12 +387,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json index 672b6ab49..5cb8ae73d 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json @@ -303,8 +303,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.logging": { @@ -388,12 +387,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json index bc762b175..f4a103850 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json @@ -253,8 +253,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -350,12 +349,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } }, "net8.0-windows7.0/win-x64": { diff --git a/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json b/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json index 2ca68e848..dad99fb1f 100644 --- a/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json +++ b/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json @@ -284,8 +284,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -376,12 +375,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json b/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json index 37c844493..e2777aca9 100644 --- a/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json +++ b/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json @@ -284,8 +284,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -376,12 +375,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json b/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json index dbfa29c21..22ae3cbc2 100644 --- a/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json +++ b/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json @@ -343,8 +343,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -427,12 +426,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json b/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json index e8c4528c0..cbe6d938d 100644 --- a/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json +++ b/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json @@ -424,8 +424,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -508,12 +507,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json b/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json index 05ed55d7b..8fe5d5283 100644 --- a/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json +++ b/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json @@ -275,8 +275,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -360,12 +359,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json b/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json index f432d48fa..09937fd1a 100644 --- a/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json +++ b/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json @@ -231,8 +231,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -315,12 +314,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json b/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json index 8912af827..47a84e789 100644 --- a/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json +++ b/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json @@ -240,8 +240,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.dui.webview": { @@ -324,12 +323,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json b/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json index 10774f4b4..f1b61f855 100644 --- a/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json +++ b/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json @@ -335,8 +335,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.logging": { @@ -406,12 +405,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json b/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json index ca439243f..09bd07198 100644 --- a/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json +++ b/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json @@ -275,8 +275,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.logging": { @@ -340,12 +339,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } }, "net6.0-windows7.0": { @@ -583,8 +576,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" } }, "speckle.connectors.logging": { @@ -648,12 +640,6 @@ "requested": "[3.1.0-dev.190, )", "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 812182f03..641e80833 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -99,7 +99,7 @@ public void AssociateWithBinding(IBinding binding) _bindingMethodCache = bindingMethodCache; _logger.LogInformation("Bridge bound to front end name {FrontEndName}", binding.Name); } - + /// /// Used by the Frontend bridge logic to understand which methods are available. /// @@ -118,22 +118,32 @@ public string[] GetBindingsMethodNames() /// /// public void RunMethod(string methodName, string requestId, string args) => - _mainThreadContext.Post(async x => - { - var runMethodArgs = (RunMethodArgs)x; - var task = await TopLevelExceptionHandler.CatchUnhandledAsync(async () => + _mainThreadContext.Post( + async x => { - var result = await ExecuteMethod(runMethodArgs.MethodName, runMethodArgs.MethodArgs).ConfigureAwait(false); - - string resultJson = JsonConvert.SerializeObject(result, _serializerOptions); - await NotifyUIMethodCallResultReady(runMethodArgs.RequestId, resultJson).ConfigureAwait(false); - }).ConfigureAwait(false); - if (task.Exception is not null) + var runMethodArgs = (RunMethodArgs)x; + var task = await TopLevelExceptionHandler + .CatchUnhandledAsync(async () => + { + var result = await ExecuteMethod(runMethodArgs.MethodName, runMethodArgs.MethodArgs).ConfigureAwait(false); + + string resultJson = JsonConvert.SerializeObject(result, _serializerOptions); + await NotifyUIMethodCallResultReady(runMethodArgs.RequestId, resultJson).ConfigureAwait(false); + }) + .ConfigureAwait(false); + if (task.Exception is not null) + { + string resultJson = SerializeFormattedException(task.Exception); + await NotifyUIMethodCallResultReady(runMethodArgs.RequestId, resultJson).ConfigureAwait(false); + } + }, + new RunMethodArgs { - string resultJson = SerializeFormattedException(task.Exception); - await NotifyUIMethodCallResultReady(runMethodArgs.RequestId, resultJson).ConfigureAwait(false); + MethodName = methodName, + RequestId = requestId, + MethodArgs = args } - }, new RunMethodArgs { MethodName = methodName, RequestId = requestId, MethodArgs = args }); + ); public void RunOnMainThread(Action action) => _mainThreadContext.Post( diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs index 730c24f27..569440a4e 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs @@ -64,8 +64,8 @@ public async Task CatchUnhandledAsync(Func function) { try { - await function().ConfigureAwait(false); - return new Result(); + await function().ConfigureAwait(false); + return new Result(); } catch (Exception ex) when (!ex.IsFatal()) { diff --git a/DUI3/Speckle.Connectors.DUI/Speckle.Connectors.DUI.csproj b/DUI3/Speckle.Connectors.DUI/Speckle.Connectors.DUI.csproj index 8f3048e1a..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 01c09bfaa..e54d1dc45 100644 --- a/DUI3/Speckle.Connectors.DUI/packages.lock.json +++ b/DUI3/Speckle.Connectors.DUI/packages.lock.json @@ -71,12 +71,6 @@ "resolved": "3.1.0-dev.190", "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" }, - "System.Threading.Tasks.Dataflow": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" - }, "GraphQL.Client": { "type": "Transitive", "resolved": "6.0.0", diff --git a/Directory.Packages.props b/Directory.Packages.props index 954c4d097..6e5b79e07 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -43,7 +43,6 @@ - From 6074b2c141f4dcdcad1bf7eba897c1f9449d2bc2 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Fri, 22 Nov 2024 13:36:42 +0000 Subject: [PATCH 03/65] merge fixes --- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 20 +--------- .../packages.lock.json | 40 +------------------ 22 files changed, 23 insertions(+), 437 deletions(-) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json index 84572fe6e..799418a57 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json @@ -241,14 +241,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -330,21 +324,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } }, "net6.0-windows7.0/win-x64": { diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json index 8f5c76d5e..9b609a864 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2022/packages.lock.json @@ -274,14 +274,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -369,21 +363,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json index e84341a13..58ea7b115 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json @@ -274,14 +274,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -369,21 +363,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json index e69deffed..3bc403f8a 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2024/packages.lock.json @@ -274,14 +274,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -370,21 +364,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json index 72880782e..1aee6c3f6 100644 --- a/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Autocad2025/packages.lock.json @@ -230,14 +230,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -325,21 +319,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } }, "net8.0-windows7.0/win-x64": { diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json index 21a573fd4..cbc7ac0e8 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json @@ -283,14 +283,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -379,21 +373,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json index 374358609..a972919e7 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2023/packages.lock.json @@ -283,14 +283,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -379,21 +373,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json index 41640fa23..56e899a69 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json @@ -283,14 +283,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -379,21 +373,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json index c3d226612..39e7784d6 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json +++ b/Connectors/Autocad/Speckle.Connectors.Civil3d2025/packages.lock.json @@ -239,14 +239,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -335,21 +329,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } }, "net8.0-windows7.0/win-x64": { diff --git a/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json index 1fe273d48..df10fbbf6 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json @@ -302,14 +302,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.logging": { @@ -390,21 +384,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json index ec7127a69..683f72be5 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json @@ -302,14 +302,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.logging": { @@ -390,21 +384,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json index 9a52f68a4..7a06d5018 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2024/packages.lock.json @@ -302,14 +302,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.logging": { @@ -390,21 +384,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json index 921a15efc..a6a50a2a6 100644 --- a/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json +++ b/Connectors/Revit/Speckle.Connectors.Revit2025/packages.lock.json @@ -252,14 +252,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -352,21 +346,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } }, "net8.0-windows7.0/win-x64": { diff --git a/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json b/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json index ddfe75f72..3c282d2c0 100644 --- a/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json +++ b/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json @@ -283,14 +283,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -378,21 +372,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json b/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json index 07495b4ea..ac4cdc25a 100644 --- a/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json +++ b/Connectors/Rhino/Speckle.Connectors.Rhino8/packages.lock.json @@ -283,14 +283,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -378,21 +372,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json b/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json index 084fd4fba..7c6b247b2 100644 --- a/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json +++ b/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json @@ -342,14 +342,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -429,21 +423,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json b/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json index 8f9e2e3e1..690d09321 100644 --- a/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json +++ b/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json @@ -423,14 +423,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -510,21 +504,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json b/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json index 563b4dfdf..5522e91b8 100644 --- a/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json +++ b/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json @@ -274,14 +274,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -362,21 +356,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json b/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json index 57d704482..0a1d0dc26 100644 --- a/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json +++ b/Converters/Autocad/Speckle.Converters.Autocad2025/packages.lock.json @@ -230,14 +230,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -317,21 +311,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json b/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json index 04e73ea2f..05b39494a 100644 --- a/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json +++ b/Converters/Civil3d/Speckle.Converters.Civil3d2025/packages.lock.json @@ -239,14 +239,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.dui.webview": { @@ -326,21 +320,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json b/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json index 1088566dd..a0dfc350a 100644 --- a/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json +++ b/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json @@ -334,14 +334,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.logging": { @@ -408,21 +402,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } diff --git a/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json b/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json index aa83aaf63..73bbf36e7 100644 --- a/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json +++ b/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json @@ -274,14 +274,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.logging": { @@ -342,21 +336,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } }, "net6.0-windows7.0": { @@ -593,14 +575,8 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", -<<<<<<< HEAD - "Speckle.Sdk": "[3.1.0-dev.190, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.190, )" -======= "Speckle.Sdk": "[3.1.0-dev.191, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" ->>>>>>> dev + "Speckle.Sdk.Dependencies": "[3.1.0-dev.191, )" } }, "speckle.connectors.logging": { @@ -661,21 +637,9 @@ }, "Speckle.Sdk.Dependencies": { "type": "CentralTransitive", -<<<<<<< HEAD - "requested": "[3.1.0-dev.190, )", - "resolved": "3.1.0-dev.190", - "contentHash": "XMGAV/+82xWCyFneE1UN9hwItVUMTKvziG7A7b4iZSCQZKPnziB+oTwotD8HecBeA6fQlfteDDyfYz0+UJV+Kg==" -======= "requested": "[3.1.0-dev.191, )", "resolved": "3.1.0-dev.191", "contentHash": "EmEOyjsGsNi56Z/ZoBOn8WirTmIT2yqWvlUeUh0BSPX2TDMZXHTKOM/kHmP6HSd10KVFn2Zo/ItY7/K9iRtL1Q==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" ->>>>>>> dev } } } From 49de3d1afcc981bcc579fc924471cbde8affab0a Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Fri, 22 Nov 2024 13:38:42 +0000 Subject: [PATCH 04/65] Fix serializer --- DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 7840f4f37..74eb9fd0f 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -134,8 +134,7 @@ public void RunMethod(string methodName, string requestId, string args) => .CatchUnhandledAsync(async () => { var result = await ExecuteMethod(runMethodArgs.MethodName, runMethodArgs.MethodArgs).ConfigureAwait(false); - - string resultJson = JsonConvert.SerializeObject(result, _serializerOptions); + string resultJson = _jsonSerializer.Serialize(result); await NotifyUIMethodCallResultReady(runMethodArgs.RequestId, resultJson).ConfigureAwait(false); }) .ConfigureAwait(false); From 0ffdf6c1932ee75e3609fac3e4030d05baf7ce23 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Fri, 22 Nov 2024 14:09:04 +0000 Subject: [PATCH 05/65] Add MainThreadContext --- .../SpeckleModule.cs | 2 - .../Bindings/AutocadBasicConnectorBinding.cs | 10 +- .../Bindings/AutocadSelectionBinding.cs | 7 +- .../Bindings/AutocadSendBaseBinding.cs | 8 +- .../Bindings/AutocadSendBinding.cs | 5 +- .../Plugin/AutocadCommand.cs | 2 - .../Bindings/Civil3dSendBinding.cs | 5 +- .../Plugin/RevitExternalApplication.cs | 2 - .../Plugin/Speckle.Connectors.RhinoPlugin.cs | 2 - .../Bridge/BrowserBridge.cs | 92 ++----------------- .../Bridge/IBrowserBridge.cs | 15 --- .../Bridge/SyncToUIThread.cs | 19 +--- .../ContainerRegistration.cs | 23 +---- .../Threading/MainThreadContext.cs | 57 ++++++++++++ 14 files changed, 94 insertions(+), 155 deletions(-) create mode 100644 DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/SpeckleModule.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/SpeckleModule.cs index 64370fdf2..1d5eee795 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/SpeckleModule.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/SpeckleModule.cs @@ -2,7 +2,6 @@ using Microsoft.Extensions.DependencyInjection; using Speckle.Connectors.ArcGIS.DependencyInjection; using Speckle.Connectors.Common; -using Speckle.Connectors.DUI; using Speckle.Converters.ArcGIS3; using Speckle.Sdk.Host; using Module = ArcGIS.Desktop.Framework.Contracts.Module; @@ -35,7 +34,6 @@ public SpeckleModule() services.AddArcGIS(); services.AddArcGISConverters(); Container = services.BuildServiceProvider(); - Container.UseDUI(); } private HostAppVersion GetVersion() diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs index dbc34f1b6..65a8d5eb9 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs @@ -5,6 +5,7 @@ using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; +using Speckle.Connectors.DUI.Threading; using Speckle.Sdk; using Speckle.Sdk.Common; using Speckle.Sdk.Credentials; @@ -19,6 +20,7 @@ public class AutocadBasicConnectorBinding : IBasicConnectorBinding private readonly DocumentModelStore _store; private readonly ISpeckleApplication _speckleApplication; + private readonly IMainThreadContext _mainThreadContext; private readonly ILogger _logger; public BasicConnectorBindingCommands Commands { get; } @@ -28,8 +30,7 @@ public AutocadBasicConnectorBinding( IBrowserBridge parent, IAccountManager accountManager, ISpeckleApplication speckleApplication, - ILogger logger - ) + ILogger logger, IMainThreadContext mainThreadContext) { _store = store; Parent = parent; @@ -42,6 +43,7 @@ ILogger logger await Commands.NotifyDocumentChanged().ConfigureAwait(false); }); _logger = logger; + _mainThreadContext = mainThreadContext; } public string GetConnectorVersion() => _speckleApplication.SpeckleVersion; @@ -129,12 +131,12 @@ private async Task HighlightObjectsOnView(ObjectId[] objectIds, string? modelCar { var doc = Application.DocumentManager.MdiActiveDocument; - await Parent + await _mainThreadContext .RunOnMainThreadAsync(async () => { try { - doc.Editor.SetImpliedSelection(Array.Empty()); // Deselects + doc.Editor.SetImpliedSelection([]); // Deselects try { doc.Editor.SetImpliedSelection(objectIds); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs index 0be4d5611..54ab2811e 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs @@ -3,6 +3,7 @@ using Speckle.Connectors.Autocad.HostApp.Extensions; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Threading; namespace Speckle.Connectors.Autocad.Bindings; @@ -10,16 +11,18 @@ public class AutocadSelectionBinding : ISelectionBinding { private const string SELECTION_EVENT = "setSelection"; private readonly ITopLevelExceptionHandler _topLevelExceptionHandler; + private readonly IMainThreadContext _mainThreadContext; private readonly HashSet _visitedDocuments = new(); public string Name => "selectionBinding"; public IBrowserBridge Parent { get; } - public AutocadSelectionBinding(IBrowserBridge parent) + public AutocadSelectionBinding(IBrowserBridge parent, IMainThreadContext mainThreadContext) { _topLevelExceptionHandler = parent.TopLevelExceptionHandler; Parent = parent; + _mainThreadContext = mainThreadContext; // POC: Use here Context for doc. In converters it's OK but we are still lacking to use context into bindings. // It is with the case of if binding created with already a document @@ -42,7 +45,7 @@ private void TryRegisterDocumentForSelection(Document? document) { document.ImpliedSelectionChanged += (_, _) => _topLevelExceptionHandler.FireAndForget( - async () => await Parent.RunOnMainThreadAsync(OnSelectionChanged).ConfigureAwait(false) + async () => await _mainThreadContext.RunOnMainThreadAsync(OnSelectionChanged).ConfigureAwait(false) ); _visitedDocuments.Add(document); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs index 11f840f92..e621b0e94 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs @@ -16,6 +16,7 @@ using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Connectors.DUI.Settings; +using Speckle.Connectors.DUI.Threading; using Speckle.Sdk; using Speckle.Sdk.Common; @@ -38,6 +39,7 @@ public abstract class AutocadSendBaseBinding : ISendBinding private readonly ILogger _logger; private readonly ITopLevelExceptionHandler _topLevelExceptionHandler; private readonly ISpeckleApplication _speckleApplication; + private readonly IMainThreadContext _mainThreadContext; /// /// Used internally to aggregate the changed objects' id. Note we're using a concurrent dictionary here as the expiry check method is not thread safe, and this was causing problems. See: @@ -57,8 +59,7 @@ protected AutocadSendBaseBinding( ISendConversionCache sendConversionCache, IOperationProgressManager operationProgressManager, ILogger logger, - ISpeckleApplication speckleApplication - ) + ISpeckleApplication speckleApplication, IMainThreadContext mainThreadContext) { _store = store; _idleManager = idleManager; @@ -69,6 +70,7 @@ ISpeckleApplication speckleApplication _operationProgressManager = operationProgressManager; _logger = logger; _speckleApplication = speckleApplication; + _mainThreadContext = mainThreadContext; _topLevelExceptionHandler = parent.TopLevelExceptionHandler; Parent = parent; Commands = new SendBindingUICommands(parent); @@ -144,7 +146,7 @@ private async Task RunExpirationChecks() public List GetSendSettings() => []; public async Task Send(string modelCardId) => - await Parent + await _mainThreadContext .RunOnMainThreadAsync(async () => await SendInternal(modelCardId).ConfigureAwait(false)) .ConfigureAwait(false); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs index bc2a28a96..ad6c7c732 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs @@ -7,6 +7,7 @@ using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card.SendFilter; +using Speckle.Connectors.DUI.Threading; using Speckle.Converters.Autocad; using Speckle.Converters.Common; using Speckle.Sdk; @@ -28,7 +29,7 @@ public AutocadSendBinding( IOperationProgressManager operationProgressManager, ILogger logger, IAutocadConversionSettingsFactory autocadConversionSettingsFactory, - ISpeckleApplication speckleApplication + ISpeckleApplication speckleApplication, IMainThreadContext mainThreadContext ) : base( store, @@ -40,7 +41,7 @@ ISpeckleApplication speckleApplication sendConversionCache, operationProgressManager, logger, - speckleApplication + speckleApplication, mainThreadContext ) { _autocadConversionSettingsFactory = autocadConversionSettingsFactory; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Plugin/AutocadCommand.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Plugin/AutocadCommand.cs index f3c177540..cbc69d098 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Plugin/AutocadCommand.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Plugin/AutocadCommand.cs @@ -3,7 +3,6 @@ using Autodesk.AutoCAD.Windows; using Microsoft.Extensions.DependencyInjection; using Speckle.Connectors.Common; -using Speckle.Connectors.DUI; using Speckle.Connectors.DUI.WebView; #if AUTOCAD using Speckle.Connectors.Autocad.DependencyInjection; @@ -48,7 +47,6 @@ public void Command() services.AddCivil3dConverters(); #endif Container = services.BuildServiceProvider(); - Container.UseDUI(); var panelWebView = Container.GetRequiredService(); diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs index a1aa571b0..9aa62cea1 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs @@ -8,6 +8,7 @@ using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card.SendFilter; +using Speckle.Connectors.DUI.Threading; using Speckle.Converters.Autocad; using Speckle.Converters.Civil3dShared; using Speckle.Converters.Common; @@ -32,7 +33,7 @@ public Civil3dSendBinding( ILogger logger, ICivil3dConversionSettingsFactory civil3dConversionSettingsFactory, IAutocadConversionSettingsFactory autocadConversionSettingsFactory, - ISpeckleApplication speckleApplication + ISpeckleApplication speckleApplication, IMainThreadContext mainThreadContext ) : base( store, @@ -44,7 +45,7 @@ ISpeckleApplication speckleApplication sendConversionCache, operationProgressManager, logger, - speckleApplication + speckleApplication, mainThreadContext ) { _civil3dConversionSettingsFactory = civil3dConversionSettingsFactory; diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitExternalApplication.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitExternalApplication.cs index 0cd5c1b60..3eb15365b 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitExternalApplication.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitExternalApplication.cs @@ -2,7 +2,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Speckle.Connectors.Common; -using Speckle.Connectors.DUI; using Speckle.Connectors.Revit.DependencyInjection; using Speckle.Converters.RevitShared; using Speckle.Sdk; @@ -48,7 +47,6 @@ public Result OnStartup(UIControlledApplication application) services.AddRevitConverters(); services.AddSingleton(application); _container = services.BuildServiceProvider(); - _container.UseDUI(); // resolve root object _revitPlugin = _container.GetRequiredService(); 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 a172c693e..a1158578e 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,6 @@ using Microsoft.Extensions.DependencyInjection; using Rhino.PlugIns; using Speckle.Connectors.Common; -using Speckle.Connectors.DUI; using Speckle.Connectors.Rhino.DependencyInjection; using Speckle.Converters.Rhino; using Speckle.Sdk; @@ -52,7 +51,6 @@ protected override LoadReturnCode OnLoad(ref string errorMessage) // but the Rhino connector has `.rhp` as it is extension. Container = services.BuildServiceProvider(); - Container.UseDUI(); // Resolve root plugin object and initialise. _rhinoPlugin = Container.GetRequiredService(); diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 74eb9fd0f..8db6905d2 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -5,6 +5,7 @@ using System.Runtime.InteropServices; using Microsoft.Extensions.Logging; using Speckle.Connectors.DUI.Bindings; +using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.DUI.Utils; using Speckle.Newtonsoft.Json; using Speckle.Sdk.Common; @@ -26,8 +27,8 @@ public sealed class BrowserBridge : IBrowserBridge /// private readonly ConcurrentDictionary _resultsStore = new(); - private readonly SynchronizationContext _mainThreadContext; public ITopLevelExceptionHandler TopLevelExceptionHandler { get; } + private readonly IMainThreadContext _mainThreadContext; private readonly IBrowserScriptExecutor _browserScriptExecutor; private readonly IJsonSerializer _jsonSerializer; @@ -53,26 +54,19 @@ private set _binding = value; } } - - private struct RunMethodArgs - { - public string MethodName; - public string RequestId; - public string MethodArgs; - } - public BrowserBridge( + IMainThreadContext mainThreadContext, IJsonSerializer jsonSerializer, ILogger logger, ILogger topLogger, IBrowserScriptExecutor browserScriptExecutor ) { + _mainThreadContext = mainThreadContext; _jsonSerializer = jsonSerializer; _logger = logger; TopLevelExceptionHandler = new TopLevelExceptionHandler(topLogger, this); // Capture the main thread's SynchronizationContext - _mainThreadContext = SynchronizationContext.Current.NotNull("No UI thread to capture?"); _browserScriptExecutor = browserScriptExecutor; } @@ -95,19 +89,6 @@ public void AssociateWithBinding(IBinding binding) _logger.LogInformation("Bridge bound to front end name {FrontEndName}", binding.Name); } - private async Task OnActionBlock(RunMethodArgs args) - { - Result result = await TopLevelExceptionHandler - .CatchUnhandledAsync(async () => await ExecuteMethod(args.MethodName, args.MethodArgs).ConfigureAwait(false)) - .ConfigureAwait(false); - - string resultJson = result.IsSuccess - ? _jsonSerializer.Serialize(result.Value) - : SerializeFormattedException(result.Exception); - - await NotifyUIMethodCallResultReady(args.RequestId, resultJson).ConfigureAwait(false); - } - /// /// Used by the Frontend bridge logic to understand which methods are available. /// @@ -119,80 +100,27 @@ public string[] GetBindingsMethodNames() return bindingNames; } - /// - /// This method posts the requested call to our action block executor. - /// - /// - /// - /// - public void RunMethod(string methodName, string requestId, string args) => - _mainThreadContext.Post( - async x => + public void RunMethod(string methodName, string requestId, string methodArgs) => + _mainThreadContext.RunOnMainThreadAsync( + async () => { - var runMethodArgs = (RunMethodArgs)x; var task = await TopLevelExceptionHandler .CatchUnhandledAsync(async () => { - var result = await ExecuteMethod(runMethodArgs.MethodName, runMethodArgs.MethodArgs).ConfigureAwait(false); + var result = await ExecuteMethod(methodName, methodArgs).ConfigureAwait(false); string resultJson = _jsonSerializer.Serialize(result); - await NotifyUIMethodCallResultReady(runMethodArgs.RequestId, resultJson).ConfigureAwait(false); + await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); }) .ConfigureAwait(false); if (task.Exception is not null) { string resultJson = SerializeFormattedException(task.Exception); - await NotifyUIMethodCallResultReady(runMethodArgs.RequestId, resultJson).ConfigureAwait(false); + await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); } - }, - new RunMethodArgs - { - MethodName = methodName, - RequestId = requestId, - MethodArgs = args } ); - public void RunOnMainThread(Action action) => - _mainThreadContext.Post( - _ => - { - // Execute the action on the main thread - TopLevelExceptionHandler.CatchUnhandled(action); - }, - null - ); - - public async Task RunOnMainThreadAsync(Func action) => - await RunOnMainThreadAsync(async () => - { - await action.Invoke().ConfigureAwait(false); - return null; - }) - .ConfigureAwait(false); - - [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] - public Task RunOnMainThreadAsync(Func> action) - { - TaskCompletionSource tcs = new(); - - _mainThreadContext.Post( - async _ => - { - try - { - T result = await action.Invoke().ConfigureAwait(false); - tcs.SetResult(result); - } - catch (Exception ex) - { - tcs.SetException(ex); - } - }, - null - ); - return tcs.Task; - } /// /// Used by the action block to invoke the actual method called by the UI. diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs index 7bd772978..e88b6831e 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs @@ -29,21 +29,6 @@ public interface IBrowserBridge /// public void RunMethod(string methodName, string requestId, string args); - /// - /// Posts an onto the main thread - /// Some applications might need to run some operations on main thread as deferred actions. - /// - /// An awaitable - /// Action to run on the main thread - public Task RunOnMainThreadAsync(Func> action); - - /// - /// Posts an onto the main thread - /// Some applications might need to run some operations on main thread as deferred actions. - /// - /// An awaitable - /// Action to run on the main thread - public Task RunOnMainThreadAsync(Func action); /// /// Bridge was not initialized with a binding diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/SyncToUIThread.cs b/DUI3/Speckle.Connectors.DUI/Bridge/SyncToUIThread.cs index bb7bbe0c3..5f282702b 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/SyncToUIThread.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/SyncToUIThread.cs @@ -1,18 +1 @@ -using System.Diagnostics.CodeAnalysis; -using Speckle.Connectors.Common.Operations; - -namespace Speckle.Connectors.DUI.Bridge; - -public class SyncToUIThread : ISyncToThread -{ - private readonly IBrowserBridge _bridge; - - public SyncToUIThread(IBrowserBridge bridge) - { - _bridge = bridge; - } - - [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Task Completion Source")] - public async Task RunOnThread(Func> func) => - await _bridge.RunOnMainThreadAsync(func).ConfigureAwait(false); -} + \ No newline at end of file diff --git a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs index f9f76d551..210e09c22 100644 --- a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs +++ b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs @@ -3,40 +3,25 @@ using Speckle.Connectors.Common.Operations; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Threading; using Speckle.Sdk; using Speckle.Sdk.Transports; namespace Speckle.Connectors.DUI; public static class ContainerRegistration -{ /* - public static void AddDUI(this SpeckleContainerBuilder speckleContainerBuilder) - { - // send operation and dependencies - speckleContainerBuilder.AddSingletonInstance(); - speckleContainerBuilder.AddSingleton(); - speckleContainerBuilder.AddTransient(); // POC: Each binding should have it's own bridge instance - speckleContainerBuilder.AddSingleton(GetJsonSerializerSettings()); - speckleContainerBuilder.ScanAssemblyOfType(); - speckleContainerBuilder.ScanAssemblyOfType(); - } -*/ +{ public static void AddDUI(this IServiceCollection serviceCollection) { // send operation and dependencies - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(new MainThreadContext()); serviceCollection.AddSingleton(); serviceCollection.AddTransient(); // POC: Each binding should have it's own bridge instance serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetAssembly(typeof(IdleCallManager))); serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetAssembly(typeof(IServerTransportFactory))); } - - public static void UseDUI(this IServiceProvider serviceProvider) - { - serviceProvider.GetRequiredService(); - } - + public static void RegisterTopLevelExceptionHandler(this IServiceCollection serviceCollection) { serviceCollection.AddSingleton(sp => diff --git a/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs b/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs new file mode 100644 index 000000000..ed371a815 --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs @@ -0,0 +1,57 @@ +using System.Diagnostics.CodeAnalysis; +using Speckle.InterfaceGenerator; +using Speckle.Sdk.Common; + +namespace Speckle.Connectors.DUI.Threading; + +[GenerateAutoInterface] +public class MainThreadContext: IMainThreadContext +{ + private readonly SynchronizationContext _mainThreadContext; + + public MainThreadContext( ) + { + _mainThreadContext = SynchronizationContext.Current.NotNull("No UI thread to capture?"); + } + + public void RunOnMainThread(Action action) => + _mainThreadContext.Post( + _ => + { + action(); + }, + null + ); + + public async Task RunOnMainThreadAsync(Func action) => + await RunOnMainThreadAsync(async () => + { + await action.Invoke().ConfigureAwait(false); + return null; + }) + .ConfigureAwait(false); + + [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] + public Task RunOnMainThreadAsync(Func> action) + { + TaskCompletionSource tcs = new(); + + _mainThreadContext.Post( + async _ => + { + try + { + T result = await action.Invoke().ConfigureAwait(false); + tcs.SetResult(result); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }, + null + ); + + return tcs.Task; + } +} From 684a295512a3574fdba1412bf09df5744cc80133 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Fri, 22 Nov 2024 14:32:51 +0000 Subject: [PATCH 06/65] add some main context detection --- .../Bindings/BasicConnectorBindingRevit.cs | 5 +++++ .../HostApp/RevitDocumentStore.cs | 9 +++++++++ .../Plugin/RevitIdleManager.cs | 5 +++++ .../Threading/MainThreadContext.cs | 6 ++++++ 4 files changed, 25 insertions(+) diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs index d118b513c..99857f9e7 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs @@ -4,6 +4,7 @@ using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; +using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.Revit.HostApp; using Speckle.Connectors.RevitShared; using Speckle.Connectors.RevitShared.Operations.Send.Filters; @@ -184,6 +185,10 @@ private async Task HighlightObjectsOnView(List objectIds) _revitContext.UIApplication?.ActiveUIDocument ?? throw new SpeckleException("Unable to retrieve active UI document"); + if (!MainThreadContext.IsMainThread) + { + Console.WriteLine("Running async on a non-main thread!"); + } // UiDocument operations should be wrapped into RevitTask, otherwise doesn't work on other tasks. await RevitTask .RunAsync(() => diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs index c14e993de..f341d8be6 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs @@ -6,6 +6,7 @@ using Revit.Async; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; +using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.DUI.Utils; using Speckle.Connectors.Revit.Plugin; using Speckle.Converters.RevitShared.Helpers; @@ -97,8 +98,16 @@ public override void WriteToFile() return; } + if (!MainThreadContext.IsMainThread) + { + Console.WriteLine("Running async on a non-main thread!"); + } RevitTask.RunAsync(() => { + if (!MainThreadContext.IsMainThread) + { + Console.WriteLine("Running async on a non-main thread!"); + } using Transaction t = new(doc, "Speckle Write State"); t.Start(); using DataStorage ds = GetSettingsDataStorage(doc) ?? DataStorage.Create(doc); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs index cce89b5dd..330bfb5fd 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs @@ -1,6 +1,7 @@ using Autodesk.Revit.UI; using Autodesk.Revit.UI.Events; using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Threading; using Speckle.Converters.RevitShared.Helpers; using Speckle.Sdk.Common; @@ -45,6 +46,10 @@ private void RevitAppOnIdle(object? sender, IdlingEventArgs e) => public void RunAsync(Action action) { + if (!MainThreadContext.IsMainThread) + { + Console.WriteLine("Running async on a non-main thread!"); + } #if REVIT2025 global::Revit.Async.RevitTask.RunAsync(action); #else diff --git a/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs b/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs index ed371a815..f30f2d06f 100644 --- a/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs +++ b/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs @@ -9,11 +9,17 @@ public class MainThreadContext: IMainThreadContext { private readonly SynchronizationContext _mainThreadContext; + // Do this when you start your application + private static int s_mainThreadId; + public MainThreadContext( ) { _mainThreadContext = SynchronizationContext.Current.NotNull("No UI thread to capture?"); + s_mainThreadId = Environment.CurrentManagedThreadId; } + public static bool IsMainThread => Environment.CurrentManagedThreadId == s_mainThreadId; + public void RunOnMainThread(Action action) => _mainThreadContext.Post( _ => From ecbaed1be68cd154d85f619f1268f6a3a84980fd Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Fri, 22 Nov 2024 14:49:13 +0000 Subject: [PATCH 07/65] add RevitMainThreadContext --- .../RevitConnectorModule.cs | 2 +- .../HostApp/RevitDocumentStore.cs | 35 ++++++------------- .../Plugin/RevitIdleManager.cs | 9 +++++ .../Plugin/RevitMainThreadContext.cs | 11 ++++++ .../ContainerRegistration.cs | 5 +-- .../Threading/MainThreadContext.cs | 20 +++++++++-- 6 files changed, 52 insertions(+), 30 deletions(-) create mode 100644 Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitMainThreadContext.cs diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs index f6f532d35..91961da60 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs @@ -26,7 +26,7 @@ public static class ServiceRegistration public static void AddRevit(this IServiceCollection serviceCollection) { serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); RegisterUiDependencies(serviceCollection); // register diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs index f341d8be6..9884b659a 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs @@ -3,10 +3,8 @@ using Autodesk.Revit.DB.ExtensibleStorage; using Autodesk.Revit.UI; using Autodesk.Revit.UI.Events; -using Revit.Async; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; -using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.DUI.Utils; using Speckle.Connectors.Revit.Plugin; using Speckle.Converters.RevitShared.Helpers; @@ -98,31 +96,20 @@ public override void WriteToFile() return; } - if (!MainThreadContext.IsMainThread) - { - Console.WriteLine("Running async on a non-main thread!"); - } - RevitTask.RunAsync(() => - { - if (!MainThreadContext.IsMainThread) - { - Console.WriteLine("Running async on a non-main thread!"); - } - using Transaction t = new(doc, "Speckle Write State"); - t.Start(); - using DataStorage ds = GetSettingsDataStorage(doc) ?? DataStorage.Create(doc); + using Transaction t = new(doc, "Speckle Write State"); + t.Start(); + using DataStorage ds = GetSettingsDataStorage(doc) ?? DataStorage.Create(doc); - using Entity stateEntity = new(_documentModelStorageSchema.GetSchema()); - string serializedModels = Serialize(); - stateEntity.Set("contents", serializedModels); + using Entity stateEntity = new(_documentModelStorageSchema.GetSchema()); + string serializedModels = Serialize(); + stateEntity.Set("contents", serializedModels); - using Entity idEntity = new(_idStorageSchema.GetSchema()); - idEntity.Set("Id", s_revitDocumentStoreId); + using Entity idEntity = new(_idStorageSchema.GetSchema()); + idEntity.Set("Id", s_revitDocumentStoreId); - ds.SetEntity(idEntity); - ds.SetEntity(stateEntity); - t.Commit(); - }); + ds.SetEntity(idEntity); + ds.SetEntity(stateEntity); + t.Commit(); } public override void ReadFromFile() diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs index 330bfb5fd..f79a1cd28 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs @@ -1,5 +1,6 @@ using Autodesk.Revit.UI; using Autodesk.Revit.UI.Events; +using Revit.Async; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Threading; using Speckle.Converters.RevitShared.Helpers; @@ -7,6 +8,14 @@ namespace Speckle.Connectors.Revit.Plugin; +public class RevitMainThreadContext : MainThreadContext +{ + public override void RunContext(Action action) => + RevitTask.RunAsync(action); + + public override Task RunContext(Func> action) => + RevitTask.RunAsync(action); +} public interface IRevitIdleManager : IAppIdleManager { public void RunAsync(Action action); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitMainThreadContext.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitMainThreadContext.cs new file mode 100644 index 000000000..73f756718 --- /dev/null +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitMainThreadContext.cs @@ -0,0 +1,11 @@ +#nullable enable +namespace Speckle.Connectors.Revit.Plugin; + +public class RevitMainThreadContext : MainThreadContext +{ + public override void RunContext(Action action) => + RevitTask.RunAsync(action); + + public override Task RunContext(Func> action) => + RevitTask.RunAsync(action); +} diff --git a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs index 210e09c22..08a150647 100644 --- a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs +++ b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs @@ -11,10 +11,11 @@ namespace Speckle.Connectors.DUI; public static class ContainerRegistration { - public static void AddDUI(this IServiceCollection serviceCollection) + public static void AddDUI(this IServiceCollection serviceCollection) + where TMainThreadContext : IMainThreadContext, new() { // send operation and dependencies - serviceCollection.AddSingleton(new MainThreadContext()); + serviceCollection.AddSingleton(new TMainThreadContext()); serviceCollection.AddSingleton(); serviceCollection.AddTransient(); // POC: Each binding should have it's own bridge instance diff --git a/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs b/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs index f30f2d06f..9a2f49930 100644 --- a/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs +++ b/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs @@ -20,14 +20,23 @@ public MainThreadContext( ) public static bool IsMainThread => Environment.CurrentManagedThreadId == s_mainThreadId; - public void RunOnMainThread(Action action) => + public virtual void RunContext(Action action) => action(); + + public void RunOnMainThread(Action action) + { + if (IsMainThread) + { + RunContext(action); + return; + } _mainThreadContext.Post( _ => { - action(); + RunContext(action); }, null ); + } public async Task RunOnMainThreadAsync(Func action) => await RunOnMainThreadAsync(async () => @@ -37,9 +46,14 @@ public async Task RunOnMainThreadAsync(Func action) => }) .ConfigureAwait(false); + public virtual Task RunContext(Func> action) => action(); [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] public Task RunOnMainThreadAsync(Func> action) { + if (IsMainThread) + { + return RunContext(action); + } TaskCompletionSource tcs = new(); _mainThreadContext.Post( @@ -47,7 +61,7 @@ public Task RunOnMainThreadAsync(Func> action) { try { - T result = await action.Invoke().ConfigureAwait(false); + T result = await RunContext(action).ConfigureAwait(false); tcs.SetResult(result); } catch (Exception ex) From c1ddbc31aacd4bd64c347da28c43b40d8dac44b9 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Fri, 22 Nov 2024 14:49:24 +0000 Subject: [PATCH 08/65] remove revit async? --- .../ArcGISConnectorModule.cs | 3 +- .../DependencyInjection/SharedRegistration.cs | 3 +- .../Bindings/BasicConnectorBindingRevit.cs | 34 ++++++------------- .../Bindings/RevitSendBinding.cs | 9 ++--- .../Bindings/SelectionBinding.cs | 7 ++-- .../RevitConnectorModule.cs | 2 +- .../HostApp/RevitDocumentStore.cs | 9 ++--- .../Plugin/RevitIdleManager.cs | 29 +--------------- .../Plugin/RevitMainThreadContext.cs | 4 ++- .../Speckle.Connectors.RevitShared.projitems | 1 + .../Registration/ServiceRegistration.cs | 3 +- .../ServiceRegistration.cs | 3 +- 12 files changed, 32 insertions(+), 75 deletions(-) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs index c9d61bbe0..2f92779de 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs @@ -14,6 +14,7 @@ using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card.SendFilter; +using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.DUI.WebView; using Speckle.Converters.Common; using Speckle.Sdk.Models.GraphTraversal; @@ -28,7 +29,7 @@ public static class ArcGISConnectorModule public static void AddArcGIS(this IServiceCollection serviceCollection) { serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); serviceCollection.AddDUIView(); serviceCollection.AddSingleton(); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs index 865963b20..6dea8e887 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs @@ -15,6 +15,7 @@ using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card.SendFilter; +using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.DUI.WebView; using Speckle.Sdk.Models.GraphTraversal; @@ -25,7 +26,7 @@ public static class SharedRegistration public static void AddAutocadBase(this IServiceCollection serviceCollection) { serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); serviceCollection.AddDUIView(); // Register other connector specific types diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs index 99857f9e7..9e2c34802 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs @@ -1,10 +1,8 @@ using Autodesk.Revit.DB; using Microsoft.Extensions.Logging; -using Revit.Async; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; -using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.Revit.HostApp; using Speckle.Connectors.RevitShared; using Speckle.Connectors.RevitShared.Operations.Send.Filters; @@ -154,49 +152,37 @@ await Commands return; } - await HighlightObjectsOnView(elementIds).ConfigureAwait(false); + HighlightObjectsOnView(elementIds); } /// /// Highlights the objects from the given ids. /// /// UniqueId's of the DB.Elements. - public async Task HighlightObjects(IReadOnlyList objectIds) + public Task HighlightObjects(IReadOnlyList objectIds) { var activeUIDoc = _revitContext.UIApplication?.ActiveUIDocument ?? throw new SpeckleException("Unable to retrieve active UI document"); - await HighlightObjectsOnView( - objectIds - .Select(uid => ElementIdHelper.GetElementIdFromUniqueId(activeUIDoc.Document, uid)) - .Where(el => el is not null) - .Cast() - .ToList() - ) - .ConfigureAwait(false); - ; + HighlightObjectsOnView( + objectIds + .Select(uid => ElementIdHelper.GetElementIdFromUniqueId(activeUIDoc.Document, uid)) + .Where(el => el is not null) + .Cast() + .ToList()); + return Task.CompletedTask; } - private async Task HighlightObjectsOnView(List objectIds) + private void HighlightObjectsOnView(List objectIds) { // POC: don't know if we can rely on storing the ActiveUIDocument, hence getting it each time var activeUIDoc = _revitContext.UIApplication?.ActiveUIDocument ?? throw new SpeckleException("Unable to retrieve active UI document"); - if (!MainThreadContext.IsMainThread) - { - Console.WriteLine("Running async on a non-main thread!"); - } - // UiDocument operations should be wrapped into RevitTask, otherwise doesn't work on other tasks. - await RevitTask - .RunAsync(() => - { activeUIDoc.Selection.SetElementIds(objectIds); activeUIDoc.ShowElements(objectIds); - }) - .ConfigureAwait(false); ; } } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs index f4c724515..425f17d8a 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs @@ -16,7 +16,6 @@ using Speckle.Connectors.DUI.Settings; using Speckle.Connectors.Revit.HostApp; using Speckle.Connectors.Revit.Operations.Send.Settings; -using Speckle.Connectors.Revit.Plugin; using Speckle.Connectors.RevitShared.Operations.Send.Filters; using Speckle.Converters.Common; using Speckle.Converters.RevitShared.Helpers; @@ -28,7 +27,7 @@ namespace Speckle.Connectors.Revit.Bindings; internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding { - private readonly IRevitIdleManager _idleManager; + private readonly IAppIdleManager _idleManager; private readonly APIContext _apiContext; private readonly CancellationManager _cancellationManager; private readonly IServiceProvider _serviceProvider; @@ -49,7 +48,7 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding private ConcurrentDictionary ChangedObjectIds { get; set; } = new(); public RevitSendBinding( - IRevitIdleManager idleManager, + IAppIdleManager idleManager, RevitContext revitContext, APIContext apiContext, DocumentModelStore store, @@ -82,11 +81,9 @@ ISpeckleApplication speckleApplication Commands = new SendBindingUICommands(bridge); // TODO expiry events // TODO filters need refresh events - _idleManager.RunAsync(() => - { + revitContext.UIApplication.NotNull().Application.DocumentChanged += (_, e) => topLevelExceptionHandler.CatchUnhandled(() => DocChangeHandler(e)); - }); Store.DocumentChanged += (_, _) => topLevelExceptionHandler.FireAndForget(async () => await OnDocumentChanged().ConfigureAwait(false)); } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SelectionBinding.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SelectionBinding.cs index 174131ee2..37c230500 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SelectionBinding.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SelectionBinding.cs @@ -1,7 +1,6 @@ using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; -using Speckle.Connectors.Revit.Plugin; using Speckle.Converters.RevitShared.Helpers; using Speckle.Sdk.Common; @@ -17,7 +16,7 @@ internal sealed class SelectionBinding : RevitBaseBinding, ISelectionBinding, ID public SelectionBinding( RevitContext revitContext, DocumentModelStore store, - IRevitIdleManager revitIdleManager, + IAppIdleManager revitIdleManager, IBrowserBridge parent ) : base("selectionBinding", store, parent, revitContext) @@ -28,11 +27,9 @@ IBrowserBridge parent _selectionTimer.Elapsed += (_, _) => parent.TopLevelExceptionHandler.CatchUnhandled(OnSelectionChanged); _selectionTimer.Start(); #else - revitIdleManager.RunAsync(() => - { + RevitContext.UIApplication.NotNull().SelectionChanged += (_, _) => revitIdleManager.SubscribeToIdle(nameof(SelectionBinding), OnSelectionChanged); - }); #endif } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs index 91961da60..b0ea49153 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs @@ -45,7 +45,7 @@ public static void AddRevit(this IServiceCollection serviceCollection) serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.RegisterTopLevelExceptionHandler(); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs index 9884b659a..a8aed3ee8 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs @@ -6,7 +6,6 @@ using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Utils; -using Speckle.Connectors.Revit.Plugin; using Speckle.Converters.RevitShared.Helpers; using Speckle.Sdk; using Speckle.Sdk.Common; @@ -20,12 +19,12 @@ internal sealed class RevitDocumentStore : DocumentModelStore private static readonly Guid s_revitDocumentStoreId = new("D35B3695-EDC9-4E15-B62A-D3FC2CB83FA3"); private readonly RevitContext _revitContext; - private readonly IRevitIdleManager _idleManager; + private readonly IAppIdleManager _idleManager; private readonly DocumentModelStorageSchema _documentModelStorageSchema; private readonly IdStorageSchema _idStorageSchema; public RevitDocumentStore( - IRevitIdleManager idleManager, + IAppIdleManager idleManager, RevitContext revitContext, IJsonSerializer jsonSerializer, DocumentModelStorageSchema documentModelStorageSchema, @@ -39,8 +38,7 @@ ITopLevelExceptionHandler topLevelExceptionHandler _documentModelStorageSchema = documentModelStorageSchema; _idStorageSchema = idStorageSchema; - _idleManager.RunAsync(() => - { + UIApplication uiApplication = _revitContext.UIApplication.NotNull(); uiApplication.ViewActivated += (s, e) => topLevelExceptionHandler.CatchUnhandled(() => OnViewActivated(s, e)); @@ -50,7 +48,6 @@ ITopLevelExceptionHandler topLevelExceptionHandler uiApplication.Application.DocumentOpened += (_, _) => topLevelExceptionHandler.CatchUnhandled(() => IsDocumentInit = false); - }); Models.CollectionChanged += (_, _) => topLevelExceptionHandler.CatchUnhandled(WriteToFile); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs index f79a1cd28..43091de2d 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs @@ -1,27 +1,13 @@ using Autodesk.Revit.UI; using Autodesk.Revit.UI.Events; -using Revit.Async; using Speckle.Connectors.DUI.Bridge; -using Speckle.Connectors.DUI.Threading; using Speckle.Converters.RevitShared.Helpers; using Speckle.Sdk.Common; namespace Speckle.Connectors.Revit.Plugin; -public class RevitMainThreadContext : MainThreadContext -{ - public override void RunContext(Action action) => - RevitTask.RunAsync(action); - - public override Task RunContext(Func> action) => - RevitTask.RunAsync(action); -} -public interface IRevitIdleManager : IAppIdleManager -{ - public void RunAsync(Action action); -} -public sealed class RevitIdleManager : AppIdleManager, IRevitIdleManager +public sealed class RevitIdleManager : AppIdleManager { private readonly UIApplication _uiApplication; private readonly IIdleCallManager _idleCallManager; @@ -52,17 +38,4 @@ protected override void AddEvent() private void RevitAppOnIdle(object? sender, IdlingEventArgs e) => _idleCallManager.AppOnIdle(() => OnIdle -= RevitAppOnIdle); - - public void RunAsync(Action action) - { - if (!MainThreadContext.IsMainThread) - { - Console.WriteLine("Running async on a non-main thread!"); - } -#if REVIT2025 - global::Revit.Async.RevitTask.RunAsync(action); -#else - action(); -#endif - } } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitMainThreadContext.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitMainThreadContext.cs index 73f756718..a2f8071e4 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitMainThreadContext.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitMainThreadContext.cs @@ -1,4 +1,6 @@ -#nullable enable +using Revit.Async; +using Speckle.Connectors.DUI.Threading; + namespace Speckle.Connectors.Revit.Plugin; public class RevitMainThreadContext : MainThreadContext diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Speckle.Connectors.RevitShared.projitems b/Connectors/Revit/Speckle.Connectors.RevitShared/Speckle.Connectors.RevitShared.projitems index 350c552f7..c482085b3 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Speckle.Connectors.RevitShared.projitems +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Speckle.Connectors.RevitShared.projitems @@ -49,6 +49,7 @@ + diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs index daf21e89f..9966a078e 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs @@ -13,6 +13,7 @@ using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card.SendFilter; +using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.DUI.WebView; using Speckle.Connectors.Rhino.Bindings; using Speckle.Connectors.Rhino.Filters; @@ -33,7 +34,7 @@ public static void AddRhino(this IServiceCollection serviceCollection) serviceCollection.AddSingleton(SpeckleConnectorsRhinoCommand.Instance); serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); serviceCollection.AddDUIView(); // POC: Overwriting the SyncToMainThread to SyncToCurrentThread for Rhino! diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs index 71da6f5c4..fa3d51dbb 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs @@ -14,6 +14,7 @@ using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card.SendFilter; +using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.DUI.WebView; using Speckle.Converter.Tekla2024; using Speckle.Converters.Common; @@ -32,7 +33,7 @@ public static IServiceCollection AddTekla(this IServiceCollection services) services.AddSingleton(); services.AddConnectorUtils(); - services.AddDUI(); + services.AddDUI(); services.AddDUIView(); services.AddSingleton(); From d03a3f1110c3a757a210bf5140e5ade347f415a5 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 25 Nov 2024 16:24:16 +0000 Subject: [PATCH 09/65] formatting --- .../Bindings/AutocadBasicConnectorBinding.cs | 4 ++- .../Bindings/AutocadSendBaseBinding.cs | 4 ++- .../Bindings/AutocadSendBinding.cs | 6 ++-- .../Bindings/Civil3dSendBinding.cs | 6 ++-- .../Bindings/BasicConnectorBindingRevit.cs | 7 +++-- .../Bindings/RevitSendBinding.cs | 4 +-- .../Bindings/SelectionBinding.cs | 4 +-- .../HostApp/RevitDocumentStore.cs | 13 ++++---- .../Plugin/RevitIdleManager.cs | 1 - .../Plugin/RevitMainThreadContext.cs | 6 ++-- .../Bridge/BrowserBridge.cs | 31 +++++++++---------- .../Bridge/IBrowserBridge.cs | 1 - .../ContainerRegistration.cs | 6 ++-- .../Threading/MainThreadContext.cs | 11 ++++--- 14 files changed, 53 insertions(+), 51 deletions(-) diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs index 65a8d5eb9..5e78829d0 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs @@ -30,7 +30,9 @@ public AutocadBasicConnectorBinding( IBrowserBridge parent, IAccountManager accountManager, ISpeckleApplication speckleApplication, - ILogger logger, IMainThreadContext mainThreadContext) + ILogger logger, + IMainThreadContext mainThreadContext + ) { _store = store; Parent = parent; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs index e621b0e94..38ce8c9aa 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs @@ -59,7 +59,9 @@ protected AutocadSendBaseBinding( ISendConversionCache sendConversionCache, IOperationProgressManager operationProgressManager, ILogger logger, - ISpeckleApplication speckleApplication, IMainThreadContext mainThreadContext) + ISpeckleApplication speckleApplication, + IMainThreadContext mainThreadContext + ) { _store = store; _idleManager = idleManager; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs index ad6c7c732..d1c16aa83 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs @@ -29,7 +29,8 @@ public AutocadSendBinding( IOperationProgressManager operationProgressManager, ILogger logger, IAutocadConversionSettingsFactory autocadConversionSettingsFactory, - ISpeckleApplication speckleApplication, IMainThreadContext mainThreadContext + ISpeckleApplication speckleApplication, + IMainThreadContext mainThreadContext ) : base( store, @@ -41,7 +42,8 @@ public AutocadSendBinding( sendConversionCache, operationProgressManager, logger, - speckleApplication, mainThreadContext + speckleApplication, + mainThreadContext ) { _autocadConversionSettingsFactory = autocadConversionSettingsFactory; diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs index 9aa62cea1..b11f54c6f 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs @@ -33,7 +33,8 @@ public Civil3dSendBinding( ILogger logger, ICivil3dConversionSettingsFactory civil3dConversionSettingsFactory, IAutocadConversionSettingsFactory autocadConversionSettingsFactory, - ISpeckleApplication speckleApplication, IMainThreadContext mainThreadContext + ISpeckleApplication speckleApplication, + IMainThreadContext mainThreadContext ) : base( store, @@ -45,7 +46,8 @@ public Civil3dSendBinding( sendConversionCache, operationProgressManager, logger, - speckleApplication, mainThreadContext + speckleApplication, + mainThreadContext ) { _civil3dConversionSettingsFactory = civil3dConversionSettingsFactory; diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs index 9e2c34802..ac794396f 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs @@ -170,7 +170,8 @@ public Task HighlightObjects(IReadOnlyList objectIds) .Select(uid => ElementIdHelper.GetElementIdFromUniqueId(activeUIDoc.Document, uid)) .Where(el => el is not null) .Cast() - .ToList()); + .ToList() + ); return Task.CompletedTask; } @@ -181,8 +182,8 @@ private void HighlightObjectsOnView(List objectIds) _revitContext.UIApplication?.ActiveUIDocument ?? throw new SpeckleException("Unable to retrieve active UI document"); - activeUIDoc.Selection.SetElementIds(objectIds); - activeUIDoc.ShowElements(objectIds); + activeUIDoc.Selection.SetElementIds(objectIds); + activeUIDoc.ShowElements(objectIds); ; } } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs index 425f17d8a..d0974aa38 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs @@ -82,8 +82,8 @@ ISpeckleApplication speckleApplication // TODO expiry events // TODO filters need refresh events - revitContext.UIApplication.NotNull().Application.DocumentChanged += (_, e) => - topLevelExceptionHandler.CatchUnhandled(() => DocChangeHandler(e)); + revitContext.UIApplication.NotNull().Application.DocumentChanged += (_, e) => + topLevelExceptionHandler.CatchUnhandled(() => DocChangeHandler(e)); Store.DocumentChanged += (_, _) => topLevelExceptionHandler.FireAndForget(async () => await OnDocumentChanged().ConfigureAwait(false)); } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SelectionBinding.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SelectionBinding.cs index 37c230500..eabb03f7f 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SelectionBinding.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SelectionBinding.cs @@ -28,8 +28,8 @@ IBrowserBridge parent _selectionTimer.Start(); #else - RevitContext.UIApplication.NotNull().SelectionChanged += (_, _) => - revitIdleManager.SubscribeToIdle(nameof(SelectionBinding), OnSelectionChanged); + RevitContext.UIApplication.NotNull().SelectionChanged += (_, _) => + revitIdleManager.SubscribeToIdle(nameof(SelectionBinding), OnSelectionChanged); #endif } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs index a8aed3ee8..f965f7c3e 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs @@ -38,16 +38,15 @@ ITopLevelExceptionHandler topLevelExceptionHandler _documentModelStorageSchema = documentModelStorageSchema; _idStorageSchema = idStorageSchema; + UIApplication uiApplication = _revitContext.UIApplication.NotNull(); - UIApplication uiApplication = _revitContext.UIApplication.NotNull(); + uiApplication.ViewActivated += (s, e) => topLevelExceptionHandler.CatchUnhandled(() => OnViewActivated(s, e)); - uiApplication.ViewActivated += (s, e) => topLevelExceptionHandler.CatchUnhandled(() => OnViewActivated(s, e)); + uiApplication.Application.DocumentOpening += (_, _) => + topLevelExceptionHandler.CatchUnhandled(() => IsDocumentInit = false); - uiApplication.Application.DocumentOpening += (_, _) => - topLevelExceptionHandler.CatchUnhandled(() => IsDocumentInit = false); - - uiApplication.Application.DocumentOpened += (_, _) => - topLevelExceptionHandler.CatchUnhandled(() => IsDocumentInit = false); + uiApplication.Application.DocumentOpened += (_, _) => + topLevelExceptionHandler.CatchUnhandled(() => IsDocumentInit = false); Models.CollectionChanged += (_, _) => topLevelExceptionHandler.CatchUnhandled(WriteToFile); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs index 43091de2d..3154fb3bd 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs @@ -6,7 +6,6 @@ namespace Speckle.Connectors.Revit.Plugin; - public sealed class RevitIdleManager : AppIdleManager { private readonly UIApplication _uiApplication; diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitMainThreadContext.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitMainThreadContext.cs index a2f8071e4..37aff2f86 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitMainThreadContext.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitMainThreadContext.cs @@ -5,9 +5,7 @@ namespace Speckle.Connectors.Revit.Plugin; public class RevitMainThreadContext : MainThreadContext { - public override void RunContext(Action action) => - RevitTask.RunAsync(action); + public override void RunContext(Action action) => RevitTask.RunAsync(action); - public override Task RunContext(Func> action) => - RevitTask.RunAsync(action); + public override Task RunContext(Func> action) => RevitTask.RunAsync(action); } diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 8db6905d2..5d6b0f201 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -54,6 +54,7 @@ private set _binding = value; } } + public BrowserBridge( IMainThreadContext mainThreadContext, IJsonSerializer jsonSerializer, @@ -101,26 +102,22 @@ public string[] GetBindingsMethodNames() } public void RunMethod(string methodName, string requestId, string methodArgs) => - _mainThreadContext.RunOnMainThreadAsync( - async () => - { - var task = await TopLevelExceptionHandler - .CatchUnhandledAsync(async () => - { - var result = await ExecuteMethod(methodName, methodArgs).ConfigureAwait(false); - string resultJson = _jsonSerializer.Serialize(result); - await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); - }) - .ConfigureAwait(false); - if (task.Exception is not null) + _mainThreadContext.RunOnMainThreadAsync(async () => + { + var task = await TopLevelExceptionHandler + .CatchUnhandledAsync(async () => { - string resultJson = SerializeFormattedException(task.Exception); + var result = await ExecuteMethod(methodName, methodArgs).ConfigureAwait(false); + string resultJson = _jsonSerializer.Serialize(result); await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); - } + }) + .ConfigureAwait(false); + if (task.Exception is not null) + { + string resultJson = SerializeFormattedException(task.Exception); + await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); } - ); - - + }); /// /// Used by the action block to invoke the actual method called by the UI. diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs index e88b6831e..f968bf3ef 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs @@ -29,7 +29,6 @@ public interface IBrowserBridge /// public void RunMethod(string methodName, string requestId, string args); - /// /// Bridge was not initialized with a binding public Task Send(string eventName, CancellationToken cancellationToken = default); diff --git a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs index 08a150647..5d8e5bd03 100644 --- a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs +++ b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs @@ -10,9 +10,9 @@ namespace Speckle.Connectors.DUI; public static class ContainerRegistration -{ +{ public static void AddDUI(this IServiceCollection serviceCollection) - where TMainThreadContext : IMainThreadContext, new() + where TMainThreadContext : IMainThreadContext, new() { // send operation and dependencies serviceCollection.AddSingleton(new TMainThreadContext()); @@ -22,7 +22,7 @@ public static void AddDUI(this IServiceCollection serviceCol serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetAssembly(typeof(IdleCallManager))); serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetAssembly(typeof(IServerTransportFactory))); } - + public static void RegisterTopLevelExceptionHandler(this IServiceCollection serviceCollection) { serviceCollection.AddSingleton(sp => diff --git a/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs b/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs index 9a2f49930..1ea910abc 100644 --- a/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs +++ b/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs @@ -5,21 +5,21 @@ namespace Speckle.Connectors.DUI.Threading; [GenerateAutoInterface] -public class MainThreadContext: IMainThreadContext +public class MainThreadContext : IMainThreadContext { private readonly SynchronizationContext _mainThreadContext; // Do this when you start your application private static int s_mainThreadId; - public MainThreadContext( ) + public MainThreadContext() { _mainThreadContext = SynchronizationContext.Current.NotNull("No UI thread to capture?"); s_mainThreadId = Environment.CurrentManagedThreadId; } - + public static bool IsMainThread => Environment.CurrentManagedThreadId == s_mainThreadId; - + public virtual void RunContext(Action action) => action(); public void RunOnMainThread(Action action) @@ -45,8 +45,9 @@ public async Task RunOnMainThreadAsync(Func action) => return null; }) .ConfigureAwait(false); - + public virtual Task RunContext(Func> action) => action(); + [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] public Task RunOnMainThreadAsync(Func> action) { From cc5e99f194dc175026d6099f5a965d143dca75a3 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 25 Nov 2024 16:29:40 +0000 Subject: [PATCH 10/65] use mainThreadContext --- .../Receive/AutocadHostObjectBuilder.cs | 89 +++++++------------ .../Bridge/SyncToUIThread.cs | 1 - .../Operations/ISyncToThread.cs | 6 -- 3 files changed, 32 insertions(+), 64 deletions(-) delete mode 100644 DUI3/Speckle.Connectors.DUI/Bridge/SyncToUIThread.cs delete mode 100644 Sdk/Speckle.Connectors.Common/Operations/ISyncToThread.cs diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs index c9bdc4ee9..39186e091 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs @@ -5,6 +5,7 @@ using Speckle.Connectors.Common.Conversion; using Speckle.Connectors.Common.Operations; using Speckle.Connectors.Common.Operations.Receive; +using Speckle.Connectors.DUI.Threading; using Speckle.Converters.Common; using Speckle.Sdk; using Speckle.Sdk.Models; @@ -17,41 +18,18 @@ namespace Speckle.Connectors.Autocad.Operations.Receive; /// /// Expects to be a scoped dependency per receive operation. /// -public class AutocadHostObjectBuilder : IHostObjectBuilder +public class AutocadHostObjectBuilder( + IRootToHostConverter converter, + AutocadLayerBaker layerBaker, + AutocadGroupBaker groupBaker, + AutocadInstanceBaker instanceBaker, + AutocadMaterialBaker materialBaker, + AutocadColorBaker colorBaker, + AutocadContext autocadContext, + RootObjectUnpacker rootObjectUnpacker, + IMainThreadContext mainThreadContext +) : IHostObjectBuilder { - private readonly AutocadLayerBaker _layerBaker; - private readonly IRootToHostConverter _converter; - private readonly ISyncToThread _syncToThread; - private readonly AutocadGroupBaker _groupBaker; - private readonly AutocadMaterialBaker _materialBaker; - private readonly AutocadColorBaker _colorBaker; - private readonly AutocadInstanceBaker _instanceBaker; - private readonly AutocadContext _autocadContext; - private readonly RootObjectUnpacker _rootObjectUnpacker; - - public AutocadHostObjectBuilder( - IRootToHostConverter converter, - AutocadLayerBaker layerBaker, - AutocadGroupBaker groupBaker, - AutocadInstanceBaker instanceBaker, - AutocadMaterialBaker materialBaker, - AutocadColorBaker colorBaker, - ISyncToThread syncToThread, - AutocadContext autocadContext, - RootObjectUnpacker rootObjectUnpacker - ) - { - _converter = converter; - _layerBaker = layerBaker; - _groupBaker = groupBaker; - _instanceBaker = instanceBaker; - _materialBaker = materialBaker; - _colorBaker = colorBaker; - _syncToThread = syncToThread; - _autocadContext = autocadContext; - _rootObjectUnpacker = rootObjectUnpacker; - } - public async Task Build( Base rootObject, string projectName, @@ -62,8 +40,8 @@ CancellationToken _ { // NOTE: This is the only place we apply ISyncToThread across connectors. We need to sync up with main thread here // after GetObject and Deserialization. It is anti-pattern now. Happiness level 3/10 but works. - return await _syncToThread - .RunOnThread( + return await mainThreadContext + .RunOnMainThreadAsync( async () => await BuildImpl(rootObject, projectName, modelName, onOperationProgressed).ConfigureAwait(false) ) .ConfigureAwait(false); @@ -80,21 +58,21 @@ IProgress onOperationProgressed onOperationProgressed.Report(new("Converting", null)); // Layer filter for received commit with project and model name - _layerBaker.CreateLayerFilter(projectName, modelName); + layerBaker.CreateLayerFilter(projectName, modelName); // 0 - Clean then Rock n Roll! - string baseLayerPrefix = _autocadContext.RemoveInvalidChars($"SPK-{projectName}-{modelName}-"); + string baseLayerPrefix = autocadContext.RemoveInvalidChars($"SPK-{projectName}-{modelName}-"); PreReceiveDeepClean(baseLayerPrefix); // 1 - Unpack objects and proxies from root commit object - var unpackedRoot = _rootObjectUnpacker.Unpack(rootObject); + var unpackedRoot = rootObjectUnpacker.Unpack(rootObject); // 2 - Split atomic objects and instance components with their path - var (atomicObjects, instanceComponents) = _rootObjectUnpacker.SplitAtomicObjectsAndInstances( + var (atomicObjects, instanceComponents) = rootObjectUnpacker.SplitAtomicObjectsAndInstances( unpackedRoot.ObjectsToConvert ); - var atomicObjectsWithPath = _layerBaker.GetAtomicObjectsWithPath(atomicObjects); - var instanceComponentsWithPath = _layerBaker.GetInstanceComponentsWithPath(instanceComponents); + var atomicObjectsWithPath = layerBaker.GetAtomicObjectsWithPath(atomicObjects); + var instanceComponentsWithPath = layerBaker.GetInstanceComponentsWithPath(instanceComponents); // POC: these are not captured by traversal, so we need to re-add them here if (unpackedRoot.DefinitionProxies != null && unpackedRoot.DefinitionProxies.Count > 0) @@ -108,14 +86,14 @@ IProgress onOperationProgressed // 3 - Bake materials and colors, as they are used later down the line by layers and objects if (unpackedRoot.RenderMaterialProxies != null) { - await _materialBaker + await materialBaker .ParseAndBakeRenderMaterials(unpackedRoot.RenderMaterialProxies, baseLayerPrefix, onOperationProgressed) .ConfigureAwait(true); } if (unpackedRoot.ColorProxies != null) { - await _colorBaker.ParseColors(unpackedRoot.ColorProxies, onOperationProgressed).ConfigureAwait(true); + await colorBaker.ParseColors(unpackedRoot.ColorProxies, onOperationProgressed).ConfigureAwait(true); } // 5 - Convert atomic objects @@ -152,7 +130,7 @@ await _materialBaker } // 6 - Convert instances - var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = await _instanceBaker + var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = await instanceBaker .BakeInstances(instanceComponentsWithPath, applicationIdMap, baseLayerPrefix, onOperationProgressed) .ConfigureAwait(true); @@ -164,10 +142,7 @@ await _materialBaker // 7 - Create groups if (unpackedRoot.GroupProxies != null) { - List groupResults = _groupBaker.CreateGroups( - unpackedRoot.GroupProxies, - applicationIdMap - ); + List groupResults = groupBaker.CreateGroups(unpackedRoot.GroupProxies, applicationIdMap); results.AddRange(groupResults); } @@ -176,20 +151,20 @@ await _materialBaker private void PreReceiveDeepClean(string baseLayerPrefix) { - _layerBaker.DeleteAllLayersByPrefix(baseLayerPrefix); - _instanceBaker.PurgeInstances(baseLayerPrefix); - _materialBaker.PurgeMaterials(baseLayerPrefix); + layerBaker.DeleteAllLayersByPrefix(baseLayerPrefix); + instanceBaker.PurgeInstances(baseLayerPrefix); + materialBaker.PurgeMaterials(baseLayerPrefix); } private async Task> ConvertObject(Base obj, Collection[] layerPath, string baseLayerNamePrefix) { - string layerName = _layerBaker.CreateLayerForReceive(layerPath, baseLayerNamePrefix); + string layerName = layerBaker.CreateLayerForReceive(layerPath, baseLayerNamePrefix); var convertedEntities = new List(); using var tr = Application.DocumentManager.CurrentDocument.Database.TransactionManager.StartTransaction(); // 1: convert - var converted = _converter.Convert(obj); + var converted = converter.Convert(obj); // 2: handle result if (converted is Entity entity) @@ -211,12 +186,12 @@ private async Task> ConvertObject(Base obj, Collection[] layerPath, private Entity BakeObject(Entity entity, Base originalObject, string layerName, Base? parentObject = null) { var objId = originalObject.applicationId ?? originalObject.id; - if (_colorBaker.ObjectColorsIdMap.TryGetValue(objId, out AutocadColor? color)) + if (colorBaker.ObjectColorsIdMap.TryGetValue(objId, out AutocadColor? color)) { entity.Color = color; } - if (_materialBaker.TryGetMaterialId(originalObject, parentObject, out ObjectId matId)) + if (materialBaker.TryGetMaterialId(originalObject, parentObject, out ObjectId matId)) { entity.MaterialId = matId; } @@ -251,7 +226,7 @@ string baseLayerName var groupDictionary = (DBDictionary) tr.GetObject(Application.DocumentManager.CurrentDocument.Database.GroupDictionaryId, OpenMode.ForWrite); - var groupName = _autocadContext.RemoveInvalidChars( + var groupName = autocadContext.RemoveInvalidChars( $@"{parentObject.speckle_type.Split('.').Last()} - {parentObject.applicationId ?? parentObject.id} ({baseLayerName})" ); diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/SyncToUIThread.cs b/DUI3/Speckle.Connectors.DUI/Bridge/SyncToUIThread.cs deleted file mode 100644 index 5f282702b..000000000 --- a/DUI3/Speckle.Connectors.DUI/Bridge/SyncToUIThread.cs +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/Sdk/Speckle.Connectors.Common/Operations/ISyncToThread.cs b/Sdk/Speckle.Connectors.Common/Operations/ISyncToThread.cs deleted file mode 100644 index 2440e642f..000000000 --- a/Sdk/Speckle.Connectors.Common/Operations/ISyncToThread.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Speckle.Connectors.Common.Operations; - -public interface ISyncToThread -{ - public Task RunOnThread(Func> func); -} From 5a5de7565fc130f0426d800b7d6aaa90c9b368cc Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 25 Nov 2024 16:45:19 +0000 Subject: [PATCH 11/65] Use more MainThreadContext --- .../Receive/RevitHostObjectBuilder.cs | 137 +++++++----------- .../Operations/Send/RevitRootObjectBuilder.cs | 74 ++++------ .../Threading/MainThreadContext.cs | 11 +- 3 files changed, 94 insertions(+), 128 deletions(-) diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs index 6734d1219..8dfcbf0c1 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs @@ -1,11 +1,11 @@ using Autodesk.Revit.DB; using Microsoft.Extensions.Logging; -using Revit.Async; using Speckle.Connectors.Common.Builders; using Speckle.Connectors.Common.Conversion; using Speckle.Connectors.Common.Instances; using Speckle.Connectors.Common.Operations; using Speckle.Connectors.Common.Operations.Receive; +using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.Revit.HostApp; using Speckle.Converters.Common; using Speckle.Converters.Common.Objects; @@ -23,51 +23,21 @@ namespace Speckle.Connectors.Revit.Operations.Receive; -internal sealed class RevitHostObjectBuilder : IHostObjectBuilder, IDisposable +internal sealed class RevitHostObjectBuilder( + IRootToHostConverter converter, + IConverterSettingsStore converterSettings, + ITransactionManager transactionManager, + ISdkActivityFactory activityFactory, + ILocalToGlobalUnpacker localToGlobalUnpacker, + RevitGroupBaker groupManager, + RevitMaterialBaker materialBaker, + RootObjectUnpacker rootObjectUnpacker, + ILogger logger, + RevitToHostCacheSingleton revitToHostCacheSingleton, + ITypedConverter<(Base atomicObject, List matrix), DirectShape> localToGlobalDirectShapeConverter, + IMainThreadContext mainThreadContext) + : IHostObjectBuilder, IDisposable { - private readonly IRootToHostConverter _converter; - private readonly IConverterSettingsStore _converterSettings; - private readonly RevitToHostCacheSingleton _revitToHostCacheSingleton; - private readonly ITransactionManager _transactionManager; - private readonly ILocalToGlobalUnpacker _localToGlobalUnpacker; - private readonly RevitGroupBaker _groupBaker; - private readonly RevitMaterialBaker _materialBaker; - private readonly ILogger _logger; - private readonly ITypedConverter< - (Base atomicObject, List matrix), - DirectShape - > _localToGlobalDirectShapeConverter; - - private readonly RootObjectUnpacker _rootObjectUnpacker; - private readonly ISdkActivityFactory _activityFactory; - - public RevitHostObjectBuilder( - IRootToHostConverter converter, - IConverterSettingsStore converterSettings, - ITransactionManager transactionManager, - ISdkActivityFactory activityFactory, - ILocalToGlobalUnpacker localToGlobalUnpacker, - RevitGroupBaker groupManager, - RevitMaterialBaker materialBaker, - RootObjectUnpacker rootObjectUnpacker, - ILogger logger, - RevitToHostCacheSingleton revitToHostCacheSingleton, - ITypedConverter<(Base atomicObject, List matrix), DirectShape> localToGlobalDirectShapeConverter - ) - { - _converter = converter; - _converterSettings = converterSettings; - _transactionManager = transactionManager; - _localToGlobalUnpacker = localToGlobalUnpacker; - _groupBaker = groupManager; - _materialBaker = materialBaker; - _rootObjectUnpacker = rootObjectUnpacker; - _logger = logger; - _revitToHostCacheSingleton = revitToHostCacheSingleton; - _localToGlobalDirectShapeConverter = localToGlobalDirectShapeConverter; - _activityFactory = activityFactory; - } - public Task Build( Base rootObject, string projectName, @@ -75,7 +45,12 @@ public Task Build( IProgress onOperationProgressed, CancellationToken cancellationToken ) => - RevitTask.RunAsync(() => BuildSync(rootObject, projectName, modelName, onOperationProgressed, cancellationToken)); + mainThreadContext.RunOnMainThreadAsync(async () => + { + var ret = BuildSync(rootObject, projectName, modelName, onOperationProgressed, cancellationToken); + await Task.Delay(100, cancellationToken).ConfigureAwait(false); + return ret; + }); private HostObjectBuilderResult BuildSync( Base rootObject, @@ -88,27 +63,27 @@ CancellationToken cancellationToken var baseGroupName = $"Project {projectName}: Model {modelName}"; // TODO: unify this across connectors! onOperationProgressed.Report(new("Converting", null)); - using var activity = _activityFactory.Start("Build"); + using var activity = activityFactory.Start("Build"); // 0 - Clean then Rock n Roll! 🎸 { - _activityFactory.Start("Pre receive clean"); - _transactionManager.StartTransaction(true, "Pre receive clean"); + activityFactory.Start("Pre receive clean"); + transactionManager.StartTransaction(true, "Pre receive clean"); try { PreReceiveDeepClean(baseGroupName); } catch (Exception ex) when (!ex.IsFatal()) { - _logger.LogError(ex, "Failed to clean up before receive in Revit"); + logger.LogError(ex, "Failed to clean up before receive in Revit"); } - _transactionManager.CommitTransaction(); + transactionManager.CommitTransaction(); } // 1 - Unpack objects and proxies from root commit object - var unpackedRoot = _rootObjectUnpacker.Unpack(rootObject); - var localToGlobalMaps = _localToGlobalUnpacker.Unpack( + var unpackedRoot = rootObjectUnpacker.Unpack(rootObject); + var localToGlobalMaps = localToGlobalUnpacker.Unpack( unpackedRoot.DefinitionProxies, unpackedRoot.ObjectsToConvert.ToList() ); @@ -116,14 +91,14 @@ CancellationToken cancellationToken // 2 - Bake materials if (unpackedRoot.RenderMaterialProxies != null) { - _transactionManager.StartTransaction(true, "Baking materials"); - _materialBaker.MapLayersRenderMaterials(unpackedRoot); - var map = _materialBaker.BakeMaterials(unpackedRoot.RenderMaterialProxies, baseGroupName); + transactionManager.StartTransaction(true, "Baking materials"); + materialBaker.MapLayersRenderMaterials(unpackedRoot); + var map = materialBaker.BakeMaterials(unpackedRoot.RenderMaterialProxies, baseGroupName); foreach (var kvp in map) { - _revitToHostCacheSingleton.MaterialsByObjectId.Add(kvp.Key, kvp.Value); + revitToHostCacheSingleton.MaterialsByObjectId.Add(kvp.Key, kvp.Value); } - _transactionManager.CommitTransaction(); + transactionManager.CommitTransaction(); } // 3 - Bake objects @@ -132,26 +107,26 @@ CancellationToken cancellationToken List<(DirectShape res, string applicationId)> postBakePaintTargets ) conversionResults; { - using var _ = _activityFactory.Start("Baking objects"); - _transactionManager.StartTransaction(true, "Baking objects"); + using var _ = activityFactory.Start("Baking objects"); + transactionManager.StartTransaction(true, "Baking objects"); conversionResults = BakeObjects(localToGlobalMaps, onOperationProgressed, cancellationToken); - _transactionManager.CommitTransaction(); + transactionManager.CommitTransaction(); } // 4 - Paint solids { - using var _ = _activityFactory.Start("Painting solids"); - _transactionManager.StartTransaction(true, "Painting solids"); + using var _ = activityFactory.Start("Painting solids"); + transactionManager.StartTransaction(true, "Painting solids"); PostBakePaint(conversionResults.postBakePaintTargets); - _transactionManager.CommitTransaction(); + transactionManager.CommitTransaction(); } // 5 - Create group { - using var _ = _activityFactory.Start("Grouping"); - _transactionManager.StartTransaction(true, "Grouping"); - _groupBaker.BakeGroupForTopLevel(baseGroupName); - _transactionManager.CommitTransaction(); + using var _ = activityFactory.Start("Grouping"); + transactionManager.StartTransaction(true, "Grouping"); + groupManager.BakeGroupForTopLevel(baseGroupName); + transactionManager.CommitTransaction(); } return conversionResults.builderResult; @@ -166,7 +141,7 @@ CancellationToken cancellationToken CancellationToken cancellationToken ) { - using var _ = _activityFactory.Start("BakeObjects"); + using var _ = activityFactory.Start("BakeObjects"); var conversionResults = new List(); var bakedObjectIds = new List(); int count = 0; @@ -178,7 +153,7 @@ CancellationToken cancellationToken cancellationToken.ThrowIfCancellationRequested(); try { - using var activity = _activityFactory.Start("BakeObject"); + using var activity = activityFactory.Start("BakeObject"); // POC hack of the ages: try to pre transform curves, points and meshes before baking // we need to bypass the local to global converter as there we don't have access to what we want. that service will/should stop existing. @@ -199,17 +174,17 @@ localToGlobalMap.AtomicObject is ITransformable transformable // and ICurve } // actual conversion happens here! - var result = _converter.Convert(localToGlobalMap.AtomicObject); + var result = converter.Convert(localToGlobalMap.AtomicObject); onOperationProgressed.Report(new("Converting", (double)++count / localToGlobalMaps.Count)); if (result is DirectShapeDefinitionWrapper) { // direct shape creation happens here - DirectShape directShapes = _localToGlobalDirectShapeConverter.Convert( + DirectShape directShapes = localToGlobalDirectShapeConverter.Convert( (localToGlobalMap.AtomicObject, localToGlobalMap.Matrix) ); bakedObjectIds.Add(directShapes.UniqueId); - _groupBaker.AddToTopLevelGroup(directShapes); + groupManager.AddToTopLevelGroup(directShapes); if (localToGlobalMap.AtomicObject is IRawEncodedObject and Base myBase) { @@ -228,7 +203,7 @@ localToGlobalMap.AtomicObject is ITransformable transformable // and ICurve catch (Exception ex) when (!ex.IsFatal()) { conversionResults.Add(new(Status.ERROR, localToGlobalMap.AtomicObject, null, null, ex)); - _logger.LogError(ex, $"Failed to convert object of type {localToGlobalMap.AtomicObject.speckle_type}"); + logger.LogError(ex, $"Failed to convert object of type {localToGlobalMap.AtomicObject.speckle_type}"); } } return (new(bakedObjectIds, conversionResults), postBakePaintTargets); @@ -244,7 +219,7 @@ private void PostBakePaint(List<(DirectShape res, string applicationId)> paintTa { var elGeometry = res.get_Geometry(new Options() { DetailLevel = ViewDetailLevel.Undefined }); var materialId = ElementId.InvalidElementId; - if (_revitToHostCacheSingleton.MaterialsByObjectId.TryGetValue(applicationId, out var mappedElementId)) + if (revitToHostCacheSingleton.MaterialsByObjectId.TryGetValue(applicationId, out var mappedElementId)) { materialId = mappedElementId; } @@ -261,7 +236,7 @@ private void PostBakePaint(List<(DirectShape res, string applicationId)> paintTa { foreach (Face face in s.Faces) { - _converterSettings.Current.Document.Paint(res.Id, face, materialId); + converterSettings.Current.Document.Paint(res.Id, face, materialId); } } } @@ -270,12 +245,12 @@ private void PostBakePaint(List<(DirectShape res, string applicationId)> paintTa private void PreReceiveDeepClean(string baseGroupName) { - DirectShapeLibrary.GetDirectShapeLibrary(_converterSettings.Current.Document).Reset(); // Note: this needs to be cleared, as it is being used in the converter + DirectShapeLibrary.GetDirectShapeLibrary(converterSettings.Current.Document).Reset(); // Note: this needs to be cleared, as it is being used in the converter - _revitToHostCacheSingleton.MaterialsByObjectId.Clear(); // Massive hack! - _groupBaker.PurgeGroups(baseGroupName); - _materialBaker.PurgeMaterials(baseGroupName); + revitToHostCacheSingleton.MaterialsByObjectId.Clear(); // Massive hack! + groupManager.PurgeGroups(baseGroupName); + materialBaker.PurgeMaterials(baseGroupName); } - public void Dispose() => _transactionManager?.Dispose(); + public void Dispose() => transactionManager?.Dispose(); } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs index 2b374c37d..8d9b784d6 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs @@ -1,62 +1,46 @@ using Autodesk.Revit.DB; using Microsoft.Extensions.Logging; -using Revit.Async; using Speckle.Connectors.Common.Builders; using Speckle.Connectors.Common.Caching; using Speckle.Connectors.Common.Conversion; using Speckle.Connectors.Common.Extensions; using Speckle.Connectors.Common.Operations; using Speckle.Connectors.DUI.Exceptions; +using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.Revit.HostApp; using Speckle.Converters.Common; using Speckle.Converters.RevitShared.Helpers; using Speckle.Converters.RevitShared.Settings; -using Speckle.Converters.RevitShared.ToSpeckle; using Speckle.Sdk; using Speckle.Sdk.Models; using Speckle.Sdk.Models.Collections; namespace Speckle.Connectors.Revit.Operations.Send; -public class RevitRootObjectBuilder : IRootObjectBuilder +public class RevitRootObjectBuilder( + IRootToSpeckleConverter converter, + IConverterSettingsStore converterSettings, + ISendConversionCache sendConversionCache, + ElementUnpacker elementUnpacker, + SendCollectionManager sendCollectionManager, + ILogger logger, + RevitToSpeckleCacheSingleton revitToSpeckleCacheSingleton, + IMainThreadContext mainThreadContext) + : IRootObjectBuilder { // POC: SendSelection and RevitConversionContextStack should be interfaces, former needs interfaces - private readonly IRootToSpeckleConverter _converter; - private readonly IConverterSettingsStore _converterSettings; - private readonly ISendConversionCache _sendConversionCache; - private readonly ElementUnpacker _elementUnpacker; - private readonly SendCollectionManager _sendCollectionManager; - private readonly RevitToSpeckleCacheSingleton _revitToSpeckleCacheSingleton; - private readonly ILogger _logger; - private readonly ParameterDefinitionHandler _parameterDefinitionHandler; - - public RevitRootObjectBuilder( - IRootToSpeckleConverter converter, - IConverterSettingsStore converterSettings, - ISendConversionCache sendConversionCache, - ElementUnpacker elementUnpacker, - SendCollectionManager sendCollectionManager, - ILogger logger, - ParameterDefinitionHandler parameterDefinitionHandler, - RevitToSpeckleCacheSingleton revitToSpeckleCacheSingleton - ) - { - _converter = converter; - _converterSettings = converterSettings; - _sendConversionCache = sendConversionCache; - _elementUnpacker = elementUnpacker; - _sendCollectionManager = sendCollectionManager; - _revitToSpeckleCacheSingleton = revitToSpeckleCacheSingleton; - _logger = logger; - _parameterDefinitionHandler = parameterDefinitionHandler; - } - public async Task Build( + public Task Build( IReadOnlyList objects, SendInfo sendInfo, IProgress onOperationProgressed, CancellationToken ct = default - ) => await RevitTask.RunAsync(() => BuildSync(objects, sendInfo, onOperationProgressed, ct)).ConfigureAwait(false); + ) => mainThreadContext.RunOnMainThreadAsync(async () => + { + var ret = BuildSync(objects, sendInfo, onOperationProgressed, ct); + await Task.Delay(100, ct).ConfigureAwait(false); + return ret; + }); private RootObjectBuilderResult BuildSync( IReadOnlyList objects, @@ -65,7 +49,7 @@ private RootObjectBuilderResult BuildSync( CancellationToken ct = default ) { - var doc = _converterSettings.Current.Document; + var doc = converterSettings.Current.Document; if (doc.IsFamilyDocument) { @@ -74,15 +58,15 @@ private RootObjectBuilderResult BuildSync( // 0 - Init the root Collection rootObject = - new() { name = _converterSettings.Current.Document.PathName.Split('\\').Last().Split('.').First() }; - rootObject["units"] = _converterSettings.Current.SpeckleUnits; + new() { name = converterSettings.Current.Document.PathName.Split('\\').Last().Split('.').First() }; + rootObject["units"] = converterSettings.Current.SpeckleUnits; var revitElements = new List(); // Convert ids to actual revit elements foreach (var id in objects) { - var el = _converterSettings.Current.Document.GetElement(id); + var el = converterSettings.Current.Document.GetElement(id); if (el != null) { revitElements.Add(el); @@ -97,7 +81,7 @@ private RootObjectBuilderResult BuildSync( List results = new(revitElements.Count); // Unpack groups (& other complex data structures) - var atomicObjects = _elementUnpacker.UnpackSelectionForConversion(revitElements).ToList(); + var atomicObjects = elementUnpacker.UnpackSelectionForConversion(revitElements).ToList(); var countProgress = 0; var cacheHitCount = 0; @@ -110,25 +94,25 @@ private RootObjectBuilderResult BuildSync( try { Base converted; - if (_sendConversionCache.TryGetValue(sendInfo.ProjectId, applicationId, out ObjectReference? value)) + if (sendConversionCache.TryGetValue(sendInfo.ProjectId, applicationId, out ObjectReference? value)) { converted = value; cacheHitCount++; } else { - converted = _converter.Convert(revitElement); + converted = converter.Convert(revitElement); converted.applicationId = applicationId; } - var collection = _sendCollectionManager.GetAndCreateObjectHostCollection(revitElement, rootObject); + var collection = sendCollectionManager.GetAndCreateObjectHostCollection(revitElement, rootObject); collection.elements.Add(converted); results.Add(new(Status.SUCCESS, applicationId, sourceType, converted)); } catch (Exception ex) when (!ex.IsFatal()) { - _logger.LogSendConversionError(ex, sourceType); + logger.LogSendConversionError(ex, sourceType); results.Add(new(Status.ERROR, applicationId, sourceType, null, ex)); } @@ -140,8 +124,8 @@ private RootObjectBuilderResult BuildSync( throw new SpeckleException("Failed to convert all objects."); } - var idsAndSubElementIds = _elementUnpacker.GetElementsAndSubelementIdsFromAtomicObjects(atomicObjects); - var materialProxies = _revitToSpeckleCacheSingleton.GetRenderMaterialProxyListForObjects(idsAndSubElementIds); + var idsAndSubElementIds = elementUnpacker.GetElementsAndSubelementIdsFromAtomicObjects(atomicObjects); + var materialProxies = revitToSpeckleCacheSingleton.GetRenderMaterialProxyListForObjects(idsAndSubElementIds); rootObject[ProxyKeys.RENDER_MATERIAL] = materialProxies; // NOTE: these are currently not used anywhere, we'll skip them until someone calls for it back diff --git a/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs b/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs index 1ea910abc..90d32006a 100644 --- a/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs +++ b/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using Speckle.InterfaceGenerator; using Speckle.Sdk.Common; @@ -38,13 +38,20 @@ public void RunOnMainThread(Action action) ); } - public async Task RunOnMainThreadAsync(Func action) => + public async Task RunOnMainThreadAsync(Func action) + { + if (IsMainThread) + { + await action.Invoke().ConfigureAwait(false); + return; + } await RunOnMainThreadAsync(async () => { await action.Invoke().ConfigureAwait(false); return null; }) .ConfigureAwait(false); + } public virtual Task RunContext(Func> action) => action(); From 0940fe773eef0d30e67259df493a6349a11a84f4 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 26 Nov 2024 08:31:31 +0000 Subject: [PATCH 12/65] some rearranging --- .../DependencyInjection/SharedRegistration.cs | 1 - .../HostApp/AutocadColorBaker.cs | 20 +-- .../HostApp/AutocadInstanceBaker.cs | 3 +- .../HostApp/AutocadMaterialBaker.cs | 3 +- .../Receive/AutocadHostObjectBuilder.cs | 42 +++--- .../Receive/RevitHostObjectBuilder.cs | 4 +- .../Operations/Send/RevitRootObjectBuilder.cs | 17 +-- .../HostApp/RhinoInstanceBaker.cs | 3 +- .../Receive/RhinoHostObjectBuilder.cs | 35 ++++- .../Registration/ServiceRegistration.cs | 3 - .../Bridge/BrowserBridge.cs | 31 +++-- .../Threading/MainThreadContext.cs | 126 ++++++++++++------ .../Instances/IInstanceBaker.cs | 2 +- 13 files changed, 178 insertions(+), 112 deletions(-) diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs index 6dea8e887..b677234aa 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs @@ -46,7 +46,6 @@ public static void AddAutocadBase(this IServiceCollection serviceCollection) serviceCollection.AddScoped(); serviceCollection.AddScoped(); - serviceCollection.AddScoped(); serviceCollection.AddScoped(); serviceCollection.AddScoped(); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadColorBaker.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadColorBaker.cs index 531ded14e..c02e1d839 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadColorBaker.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadColorBaker.cs @@ -1,6 +1,7 @@ using Autodesk.AutoCAD.Colors; using Microsoft.Extensions.Logging; using Speckle.Connectors.Common.Operations; +using Speckle.InterfaceGenerator; using Speckle.Sdk; using Speckle.Sdk.Models.Proxies; using AutocadColor = Autodesk.AutoCAD.Colors.Color; @@ -10,15 +11,9 @@ namespace Speckle.Connectors.Autocad.HostApp; /// /// Expects to be a scoped dependency for a given operation and helps with layer creation and cleanup. /// -public class AutocadColorBaker +[GenerateAutoInterface] +public class AutocadColorBaker(ILogger logger) : IAutocadColorBaker { - private readonly ILogger _logger; - - public AutocadColorBaker(ILogger logger) - { - _logger = logger; - } - /// /// For receive operations /// @@ -29,10 +24,7 @@ public AutocadColorBaker(ILogger logger) /// /// /// - public async Task ParseColors( - IReadOnlyCollection colorProxies, - IProgress onOperationProgressed - ) + public void ParseColors(IReadOnlyCollection colorProxies, IProgress onOperationProgressed) { var count = 0; foreach (ColorProxy colorProxy in colorProxies) @@ -62,10 +54,8 @@ IProgress onOperationProgressed } catch (Exception ex) when (!ex.IsFatal()) { - _logger.LogError(ex, "Failed parsing color proxy"); + logger.LogError(ex, "Failed parsing color proxy"); } - - await Task.Yield(); } } diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceBaker.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceBaker.cs index 35d44abe0..cf3439f7f 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceBaker.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceBaker.cs @@ -49,7 +49,7 @@ IConverterSettingsStore converterSettings } [SuppressMessage("Maintainability", "CA1506:Avoid excessive class coupling")] - public async Task BakeInstances( + public BakeResult BakeInstances( IReadOnlyCollection<(Collection[] collectionPath, IInstanceComponent obj)> instanceComponents, Dictionary> applicationIdMap, string baseLayerName, @@ -167,7 +167,6 @@ instanceOrDefinition is InstanceProxy instanceProxy } transaction.Commit(); - await Task.Yield(); return new(createdObjectIds, consumedObjectIds, conversionResults); } diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadMaterialBaker.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadMaterialBaker.cs index 4aea349fb..6afc37ebf 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadMaterialBaker.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadMaterialBaker.cs @@ -91,7 +91,7 @@ public void PurgeMaterials(string namePrefix) transaction.Commit(); } - public async Task ParseAndBakeRenderMaterials( + public void ParseAndBakeRenderMaterials( List materialProxies, string baseLayerPrefix, IProgress onOperationProgressed @@ -140,7 +140,6 @@ IProgress onOperationProgressed } transaction.Commit(); - await Task.Yield(); } private (ObjectId, ReceiveConversionResult) BakeMaterial( diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs index 39186e091..ebb6b891c 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs @@ -24,7 +24,7 @@ public class AutocadHostObjectBuilder( AutocadGroupBaker groupBaker, AutocadInstanceBaker instanceBaker, AutocadMaterialBaker materialBaker, - AutocadColorBaker colorBaker, + IAutocadColorBaker colorBaker, AutocadContext autocadContext, RootObjectUnpacker rootObjectUnpacker, IMainThreadContext mainThreadContext @@ -35,19 +35,20 @@ public async Task Build( string projectName, string modelName, IProgress onOperationProgressed, - CancellationToken _ + CancellationToken ct ) { - // NOTE: This is the only place we apply ISyncToThread across connectors. We need to sync up with main thread here - // after GetObject and Deserialization. It is anti-pattern now. Happiness level 3/10 but works. return await mainThreadContext - .RunOnMainThreadAsync( - async () => await BuildImpl(rootObject, projectName, modelName, onOperationProgressed).ConfigureAwait(false) - ) + .RunOnMainThreadAsync(async () => + { + var ret = BuildImpl(rootObject, projectName, modelName, onOperationProgressed); + await Task.Delay(100, ct).ConfigureAwait(false); + return ret; + }) .ConfigureAwait(false); } - private async Task BuildImpl( + private HostObjectBuilderResult BuildImpl( Base rootObject, string projectName, string modelName, @@ -86,14 +87,16 @@ IProgress onOperationProgressed // 3 - Bake materials and colors, as they are used later down the line by layers and objects if (unpackedRoot.RenderMaterialProxies != null) { - await materialBaker - .ParseAndBakeRenderMaterials(unpackedRoot.RenderMaterialProxies, baseLayerPrefix, onOperationProgressed) - .ConfigureAwait(true); + materialBaker.ParseAndBakeRenderMaterials( + unpackedRoot.RenderMaterialProxies, + baseLayerPrefix, + onOperationProgressed + ); } if (unpackedRoot.ColorProxies != null) { - await colorBaker.ParseColors(unpackedRoot.ColorProxies, onOperationProgressed).ConfigureAwait(true); + colorBaker.ParseColors(unpackedRoot.ColorProxies, onOperationProgressed); } // 5 - Convert atomic objects @@ -107,8 +110,7 @@ await materialBaker onOperationProgressed.Report(new("Converting objects", (double)++count / atomicObjects.Count)); try { - List convertedObjects = await ConvertObject(atomicObject, layerPath, baseLayerPrefix) - .ConfigureAwait(true); + List convertedObjects = ConvertObject(atomicObject, layerPath, baseLayerPrefix); applicationIdMap[objectId] = convertedObjects; @@ -130,9 +132,12 @@ await materialBaker } // 6 - Convert instances - var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = await instanceBaker - .BakeInstances(instanceComponentsWithPath, applicationIdMap, baseLayerPrefix, onOperationProgressed) - .ConfigureAwait(true); + var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = instanceBaker.BakeInstances( + instanceComponentsWithPath, + applicationIdMap, + baseLayerPrefix, + onOperationProgressed + ); bakedObjectIds.RemoveAll(id => consumedObjectIds.Contains(id)); bakedObjectIds.AddRange(createdInstanceIds); @@ -156,7 +161,7 @@ private void PreReceiveDeepClean(string baseLayerPrefix) materialBaker.PurgeMaterials(baseLayerPrefix); } - private async Task> ConvertObject(Base obj, Collection[] layerPath, string baseLayerNamePrefix) + private List ConvertObject(Base obj, Collection[] layerPath, string baseLayerNamePrefix) { string layerName = layerBaker.CreateLayerForReceive(layerPath, baseLayerNamePrefix); var convertedEntities = new List(); @@ -179,7 +184,6 @@ private async Task> ConvertObject(Base obj, Collection[] layerPath, } tr.Commit(); - await Task.Delay(10).ConfigureAwait(true); return convertedEntities; } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs index 8dfcbf0c1..6de705816 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs @@ -35,8 +35,8 @@ internal sealed class RevitHostObjectBuilder( ILogger logger, RevitToHostCacheSingleton revitToHostCacheSingleton, ITypedConverter<(Base atomicObject, List matrix), DirectShape> localToGlobalDirectShapeConverter, - IMainThreadContext mainThreadContext) - : IHostObjectBuilder, IDisposable + IMainThreadContext mainThreadContext +) : IHostObjectBuilder, IDisposable { public Task Build( Base rootObject, diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs index 8d9b784d6..93a44c2b2 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs @@ -25,8 +25,8 @@ public class RevitRootObjectBuilder( SendCollectionManager sendCollectionManager, ILogger logger, RevitToSpeckleCacheSingleton revitToSpeckleCacheSingleton, - IMainThreadContext mainThreadContext) - : IRootObjectBuilder + IMainThreadContext mainThreadContext +) : IRootObjectBuilder { // POC: SendSelection and RevitConversionContextStack should be interfaces, former needs interfaces @@ -35,12 +35,13 @@ public Task Build( SendInfo sendInfo, IProgress onOperationProgressed, CancellationToken ct = default - ) => mainThreadContext.RunOnMainThreadAsync(async () => - { - var ret = BuildSync(objects, sendInfo, onOperationProgressed, ct); - await Task.Delay(100, ct).ConfigureAwait(false); - return ret; - }); + ) => + mainThreadContext.RunOnMainThreadAsync(async () => + { + var ret = BuildSync(objects, sendInfo, onOperationProgressed, ct); + await Task.Delay(100, ct).ConfigureAwait(false); + return ret; + }); private RootObjectBuilderResult BuildSync( IReadOnlyList objects, diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoInstanceBaker.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoInstanceBaker.cs index 8cc716e9f..cafc8ba5c 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoInstanceBaker.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoInstanceBaker.cs @@ -42,7 +42,7 @@ ILogger logger /// Instance definitions and instances that need creating. /// A dict mapping { original application id -> [resulting application ids post conversion] } /// - public async Task BakeInstances( + public BakeResult BakeInstances( IReadOnlyCollection<(Collection[] collectionPath, IInstanceComponent obj)> instanceComponents, Dictionary> applicationIdMap, string baseLayerName, @@ -153,7 +153,6 @@ instanceOrDefinition is InstanceProxy instanceProxy } } - await Task.Yield(); return new(createdObjectIds, consumedObjectIds, conversionResults); } diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs index 939051fea..a5a18676b 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs @@ -5,6 +5,7 @@ using Speckle.Connectors.Common.Conversion; using Speckle.Connectors.Common.Operations; using Speckle.Connectors.Common.Operations.Receive; +using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.Rhino.HostApp; using Speckle.Converters.Common; using Speckle.Converters.Rhino; @@ -30,6 +31,7 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder private readonly RhinoGroupBaker _groupBaker; private readonly RootObjectUnpacker _rootObjectUnpacker; private readonly ISdkActivityFactory _activityFactory; + private readonly IMainThreadContext _mainThreadContext; public RhinoHostObjectBuilder( IRootToHostConverter converter, @@ -40,7 +42,8 @@ public RhinoHostObjectBuilder( RhinoMaterialBaker materialBaker, RhinoColorBaker colorBaker, RhinoGroupBaker groupBaker, - ISdkActivityFactory activityFactory + ISdkActivityFactory activityFactory, + IMainThreadContext mainThreadContext ) { _converter = converter; @@ -52,6 +55,7 @@ ISdkActivityFactory activityFactory _layerBaker = layerBaker; _groupBaker = groupBaker; _activityFactory = activityFactory; + _mainThreadContext = mainThreadContext; } #pragma warning disable CA1506 @@ -63,6 +67,26 @@ public async Task Build( IProgress onOperationProgressed, CancellationToken cancellationToken ) + { + return await _mainThreadContext + .RunOnThreadAsync( + async () => + { + var ret = BuildSync(rootObject, projectName, modelName, onOperationProgressed); + await Task.Delay(100, cancellationToken).ConfigureAwait(false); + return ret; + }, + false + ) + .ConfigureAwait(false); + } + + public HostObjectBuilderResult BuildSync( + Base rootObject, + string projectName, + string modelName, + IProgress onOperationProgressed + ) { using var activity = _activityFactory.Start("Build"); // POC: This is where the top level base-layer name is set. Could be abstracted or injected in the context? @@ -202,9 +226,12 @@ CancellationToken cancellationToken // 6 - Convert instances using (var _ = _activityFactory.Start("Converting instances")) { - var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = await _instanceBaker - .BakeInstances(instanceComponentsWithPath, applicationIdMap, baseLayerName, onOperationProgressed) - .ConfigureAwait(false); + var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = _instanceBaker.BakeInstances( + instanceComponentsWithPath, + applicationIdMap, + baseLayerName, + onOperationProgressed + ); bakedObjectIds.RemoveAll(id => consumedObjectIds.Contains(id)); // remove all objects that have been "consumed" bakedObjectIds.AddRange(createdInstanceIds); // add instance ids diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs index 9966a078e..a406e0f3f 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs @@ -37,9 +37,6 @@ public static void AddRhino(this IServiceCollection serviceCollection) serviceCollection.AddDUI(); serviceCollection.AddDUIView(); - // POC: Overwriting the SyncToMainThread to SyncToCurrentThread for Rhino! - // builder.AddSingletonInstance(); - // Register other connector specific types serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 5d6b0f201..00e6c79f9 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -102,22 +102,25 @@ public string[] GetBindingsMethodNames() } public void RunMethod(string methodName, string requestId, string methodArgs) => - _mainThreadContext.RunOnMainThreadAsync(async () => - { - var task = await TopLevelExceptionHandler - .CatchUnhandledAsync(async () => + _mainThreadContext.RunOnThreadAsync( + async () => + { + var task = await TopLevelExceptionHandler + .CatchUnhandledAsync(async () => + { + var result = await ExecuteMethod(methodName, methodArgs).ConfigureAwait(false); + string resultJson = _jsonSerializer.Serialize(result); + await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); + }) + .ConfigureAwait(false); + if (task.Exception is not null) { - var result = await ExecuteMethod(methodName, methodArgs).ConfigureAwait(false); - string resultJson = _jsonSerializer.Serialize(result); + string resultJson = SerializeFormattedException(task.Exception); await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); - }) - .ConfigureAwait(false); - if (task.Exception is not null) - { - string resultJson = SerializeFormattedException(task.Exception); - await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); - } - }); + } + }, + true + ); /// /// Used by the action block to invoke the actual method called by the UI. diff --git a/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs b/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs index 90d32006a..8767209be 100644 --- a/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs +++ b/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs @@ -22,64 +22,112 @@ public MainThreadContext() public virtual void RunContext(Action action) => action(); - public void RunOnMainThread(Action action) + public void RunOnThread(Action action, bool useMain) { - if (IsMainThread) + if (useMain) { - RunContext(action); - return; + if (IsMainThread) + { + RunContext(action); + } + else + { + _mainThreadContext.Post( + _ => + { + RunContext(action); + }, + null + ); + } } - _mainThreadContext.Post( - _ => + else + { + if (IsMainThread) + { + Task.Factory.StartNew(action, default, TaskCreationOptions.LongRunning, TaskScheduler.Default) + .GetAwaiter() + .GetResult(); + } + else { RunContext(action); - }, - null - ); + } + } } - public async Task RunOnMainThreadAsync(Func action) + public async Task RunOnThreadAsync(Func action, bool useMain) { - if (IsMainThread) + if (useMain) { - await action.Invoke().ConfigureAwait(false); - return; - } - await RunOnMainThreadAsync(async () => + if (IsMainThread) { await action.Invoke().ConfigureAwait(false); - return null; - }) - .ConfigureAwait(false); + } + else + { + await RunOnThreadAsync( + async () => + { + await RunContext(action.Invoke).ConfigureAwait(false); + return null; + }, + useMain + ) + .ConfigureAwait(false); + } + } + else + { + if (IsMainThread) + { + await Task + .Factory.StartNew(action, default, TaskCreationOptions.LongRunning, TaskScheduler.Default) + .ConfigureAwait(false); + } + else + { + await RunContext(action.Invoke).ConfigureAwait(false); + } + } } + public virtual Task RunContext(Func action) => action(); + public virtual Task RunContext(Func> action) => action(); [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] - public Task RunOnMainThreadAsync(Func> action) + public Task RunOnThreadAsync(Func> action, bool useMain) { - if (IsMainThread) + if (useMain) { - return RunContext(action); - } - TaskCompletionSource tcs = new(); - - _mainThreadContext.Post( - async _ => + if (IsMainThread) { - try + return RunContext(action.Invoke); + } + TaskCompletionSource tcs = new(); + _mainThreadContext.Post( + async _ => { - T result = await RunContext(action).ConfigureAwait(false); - tcs.SetResult(result); - } - catch (Exception ex) - { - tcs.SetException(ex); - } - }, - null - ); - - return tcs.Task; + try + { + T result = await RunContext(action).ConfigureAwait(false); + tcs.SetResult(result); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }, + null + ); + return tcs.Task; + } + if (IsMainThread) + { + Task> f = Task.Factory.StartNew(action, default, TaskCreationOptions.LongRunning, TaskScheduler.Default); + return f.Unwrap(); + } + return RunContext(action.Invoke); } } diff --git a/Sdk/Speckle.Connectors.Common/Instances/IInstanceBaker.cs b/Sdk/Speckle.Connectors.Common/Instances/IInstanceBaker.cs index fe6fa4af7..2ed88c836 100644 --- a/Sdk/Speckle.Connectors.Common/Instances/IInstanceBaker.cs +++ b/Sdk/Speckle.Connectors.Common/Instances/IInstanceBaker.cs @@ -14,7 +14,7 @@ public interface IInstanceBaker /// /// /// - Task BakeInstances( + BakeResult BakeInstances( IReadOnlyCollection<(Collection[] collectionPath, IInstanceComponent obj)> instanceComponents, Dictionary applicationIdMap, string baseLayerName, From 4ee6d04d27a1a9971f29016fc33d843fce324ae3 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 26 Nov 2024 11:28:56 +0000 Subject: [PATCH 13/65] renaming --- .../ArcGISConnectorModule.cs | 2 +- .../Bindings/AutocadBasicConnectorBinding.cs | 10 ++--- .../Bindings/AutocadSelectionBinding.cs | 8 ++-- .../Bindings/AutocadSendBaseBinding.cs | 10 ++--- .../Bindings/AutocadSendBinding.cs | 4 +- .../DependencyInjection/SharedRegistration.cs | 2 +- .../Receive/AutocadHostObjectBuilder.cs | 6 +-- .../Bindings/Civil3dSendBinding.cs | 4 +- .../RevitConnectorModule.cs | 2 +- .../Receive/RevitHostObjectBuilder.cs | 4 +- .../Operations/Send/RevitRootObjectBuilder.cs | 4 +- ...ThreadContext.cs => RevitThreadContext.cs} | 2 +- .../Speckle.Connectors.RevitShared.projitems | 2 +- .../Receive/RhinoHostObjectBuilder.cs | 23 +++++------- .../Registration/ServiceRegistration.cs | 2 +- .../ServiceRegistration.cs | 2 +- .../Bridge/BrowserBridge.cs | 37 +++++++++---------- .../ContainerRegistration.cs | 6 +-- ...{MainThreadContext.cs => ThreadContext.cs} | 20 +++++----- .../Threading/ThreadContextExtensions.cs | 22 +++++++++++ 20 files changed, 94 insertions(+), 78 deletions(-) rename Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/{RevitMainThreadContext.cs => RevitThreadContext.cs} (83%) rename DUI3/Speckle.Connectors.DUI/Threading/{MainThreadContext.cs => ThreadContext.cs} (90%) create mode 100644 DUI3/Speckle.Connectors.DUI/Threading/ThreadContextExtensions.cs diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs index 2f92779de..1b01489e2 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs @@ -29,7 +29,7 @@ public static class ArcGISConnectorModule public static void AddArcGIS(this IServiceCollection serviceCollection) { serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); serviceCollection.AddDUIView(); serviceCollection.AddSingleton(); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs index 5e78829d0..09d6818c1 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs @@ -20,7 +20,7 @@ public class AutocadBasicConnectorBinding : IBasicConnectorBinding private readonly DocumentModelStore _store; private readonly ISpeckleApplication _speckleApplication; - private readonly IMainThreadContext _mainThreadContext; + private readonly IThreadContext _threadContext; private readonly ILogger _logger; public BasicConnectorBindingCommands Commands { get; } @@ -31,7 +31,7 @@ public AutocadBasicConnectorBinding( IAccountManager accountManager, ISpeckleApplication speckleApplication, ILogger logger, - IMainThreadContext mainThreadContext + IThreadContext threadContext ) { _store = store; @@ -45,7 +45,7 @@ IMainThreadContext mainThreadContext await Commands.NotifyDocumentChanged().ConfigureAwait(false); }); _logger = logger; - _mainThreadContext = mainThreadContext; + _threadContext = threadContext; } public string GetConnectorVersion() => _speckleApplication.SpeckleVersion; @@ -133,8 +133,8 @@ private async Task HighlightObjectsOnView(ObjectId[] objectIds, string? modelCar { var doc = Application.DocumentManager.MdiActiveDocument; - await _mainThreadContext - .RunOnMainThreadAsync(async () => + await _threadContext + .RunOnMainAsync(async () => { try { diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs index 54ab2811e..61fb5e739 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs @@ -11,18 +11,18 @@ public class AutocadSelectionBinding : ISelectionBinding { private const string SELECTION_EVENT = "setSelection"; private readonly ITopLevelExceptionHandler _topLevelExceptionHandler; - private readonly IMainThreadContext _mainThreadContext; + private readonly IThreadContext _threadContext; private readonly HashSet _visitedDocuments = new(); public string Name => "selectionBinding"; public IBrowserBridge Parent { get; } - public AutocadSelectionBinding(IBrowserBridge parent, IMainThreadContext mainThreadContext) + public AutocadSelectionBinding(IBrowserBridge parent, IThreadContext threadContext) { _topLevelExceptionHandler = parent.TopLevelExceptionHandler; Parent = parent; - _mainThreadContext = mainThreadContext; + _threadContext = threadContext; // POC: Use here Context for doc. In converters it's OK but we are still lacking to use context into bindings. // It is with the case of if binding created with already a document @@ -45,7 +45,7 @@ private void TryRegisterDocumentForSelection(Document? document) { document.ImpliedSelectionChanged += (_, _) => _topLevelExceptionHandler.FireAndForget( - async () => await _mainThreadContext.RunOnMainThreadAsync(OnSelectionChanged).ConfigureAwait(false) + async () => await _threadContext.RunOnMainAsync(OnSelectionChanged).ConfigureAwait(false) ); _visitedDocuments.Add(document); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs index 38ce8c9aa..01f612275 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs @@ -39,7 +39,7 @@ public abstract class AutocadSendBaseBinding : ISendBinding private readonly ILogger _logger; private readonly ITopLevelExceptionHandler _topLevelExceptionHandler; private readonly ISpeckleApplication _speckleApplication; - private readonly IMainThreadContext _mainThreadContext; + private readonly IThreadContext _threadContext; /// /// Used internally to aggregate the changed objects' id. Note we're using a concurrent dictionary here as the expiry check method is not thread safe, and this was causing problems. See: @@ -60,7 +60,7 @@ protected AutocadSendBaseBinding( IOperationProgressManager operationProgressManager, ILogger logger, ISpeckleApplication speckleApplication, - IMainThreadContext mainThreadContext + IThreadContext threadContext ) { _store = store; @@ -72,7 +72,7 @@ IMainThreadContext mainThreadContext _operationProgressManager = operationProgressManager; _logger = logger; _speckleApplication = speckleApplication; - _mainThreadContext = mainThreadContext; + _threadContext = threadContext; _topLevelExceptionHandler = parent.TopLevelExceptionHandler; Parent = parent; Commands = new SendBindingUICommands(parent); @@ -148,8 +148,8 @@ private async Task RunExpirationChecks() public List GetSendSettings() => []; public async Task Send(string modelCardId) => - await _mainThreadContext - .RunOnMainThreadAsync(async () => await SendInternal(modelCardId).ConfigureAwait(false)) + await _threadContext + .RunOnWorkerAsync(async () => await SendInternal(modelCardId).ConfigureAwait(false)) .ConfigureAwait(false); protected abstract void InitializeSettings(IServiceProvider serviceProvider); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs index d1c16aa83..50b485c30 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs @@ -30,7 +30,7 @@ public AutocadSendBinding( ILogger logger, IAutocadConversionSettingsFactory autocadConversionSettingsFactory, ISpeckleApplication speckleApplication, - IMainThreadContext mainThreadContext + IThreadContext threadContext ) : base( store, @@ -43,7 +43,7 @@ IMainThreadContext mainThreadContext operationProgressManager, logger, speckleApplication, - mainThreadContext + threadContext ) { _autocadConversionSettingsFactory = autocadConversionSettingsFactory; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs index b677234aa..33d4ee099 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs @@ -26,7 +26,7 @@ public static class SharedRegistration public static void AddAutocadBase(this IServiceCollection serviceCollection) { serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); serviceCollection.AddDUIView(); // Register other connector specific types diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs index ebb6b891c..b4e2b86eb 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs @@ -27,7 +27,7 @@ public class AutocadHostObjectBuilder( IAutocadColorBaker colorBaker, AutocadContext autocadContext, RootObjectUnpacker rootObjectUnpacker, - IMainThreadContext mainThreadContext + IThreadContext threadContext ) : IHostObjectBuilder { public async Task Build( @@ -38,8 +38,8 @@ public async Task Build( CancellationToken ct ) { - return await mainThreadContext - .RunOnMainThreadAsync(async () => + return await threadContext + .RunOnWorkerAsync(async () => { var ret = BuildImpl(rootObject, projectName, modelName, onOperationProgressed); await Task.Delay(100, ct).ConfigureAwait(false); diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs index b11f54c6f..a29b42865 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs @@ -34,7 +34,7 @@ public Civil3dSendBinding( ICivil3dConversionSettingsFactory civil3dConversionSettingsFactory, IAutocadConversionSettingsFactory autocadConversionSettingsFactory, ISpeckleApplication speckleApplication, - IMainThreadContext mainThreadContext + IThreadContext threadContext ) : base( store, @@ -47,7 +47,7 @@ IMainThreadContext mainThreadContext operationProgressManager, logger, speckleApplication, - mainThreadContext + threadContext ) { _civil3dConversionSettingsFactory = civil3dConversionSettingsFactory; diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs index b0ea49153..9554daf1b 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs @@ -26,7 +26,7 @@ public static class ServiceRegistration public static void AddRevit(this IServiceCollection serviceCollection) { serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); RegisterUiDependencies(serviceCollection); // register diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs index 6de705816..536b07ee0 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs @@ -35,7 +35,7 @@ internal sealed class RevitHostObjectBuilder( ILogger logger, RevitToHostCacheSingleton revitToHostCacheSingleton, ITypedConverter<(Base atomicObject, List matrix), DirectShape> localToGlobalDirectShapeConverter, - IMainThreadContext mainThreadContext + IThreadContext threadContext ) : IHostObjectBuilder, IDisposable { public Task Build( @@ -45,7 +45,7 @@ public Task Build( IProgress onOperationProgressed, CancellationToken cancellationToken ) => - mainThreadContext.RunOnMainThreadAsync(async () => + threadContext.RunOnWorkerAsync(async () => { var ret = BuildSync(rootObject, projectName, modelName, onOperationProgressed, cancellationToken); await Task.Delay(100, cancellationToken).ConfigureAwait(false); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs index 93a44c2b2..691172ea4 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs @@ -25,7 +25,7 @@ public class RevitRootObjectBuilder( SendCollectionManager sendCollectionManager, ILogger logger, RevitToSpeckleCacheSingleton revitToSpeckleCacheSingleton, - IMainThreadContext mainThreadContext + IThreadContext threadContext ) : IRootObjectBuilder { // POC: SendSelection and RevitConversionContextStack should be interfaces, former needs interfaces @@ -36,7 +36,7 @@ public Task Build( IProgress onOperationProgressed, CancellationToken ct = default ) => - mainThreadContext.RunOnMainThreadAsync(async () => + threadContext.RunOnWorkerAsync(async () => { var ret = BuildSync(objects, sendInfo, onOperationProgressed, ct); await Task.Delay(100, ct).ConfigureAwait(false); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitMainThreadContext.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs similarity index 83% rename from Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitMainThreadContext.cs rename to Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs index 37aff2f86..28bb76264 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitMainThreadContext.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs @@ -3,7 +3,7 @@ namespace Speckle.Connectors.Revit.Plugin; -public class RevitMainThreadContext : MainThreadContext +public class RevitThreadContext : ThreadContext { public override void RunContext(Action action) => RevitTask.RunAsync(action); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Speckle.Connectors.RevitShared.projitems b/Connectors/Revit/Speckle.Connectors.RevitShared/Speckle.Connectors.RevitShared.projitems index c482085b3..0811cbe7b 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Speckle.Connectors.RevitShared.projitems +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Speckle.Connectors.RevitShared.projitems @@ -49,7 +49,7 @@ - + diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs index a5a18676b..5403e9d4f 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs @@ -31,7 +31,7 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder private readonly RhinoGroupBaker _groupBaker; private readonly RootObjectUnpacker _rootObjectUnpacker; private readonly ISdkActivityFactory _activityFactory; - private readonly IMainThreadContext _mainThreadContext; + private readonly IThreadContext _threadContext; public RhinoHostObjectBuilder( IRootToHostConverter converter, @@ -43,7 +43,7 @@ public RhinoHostObjectBuilder( RhinoColorBaker colorBaker, RhinoGroupBaker groupBaker, ISdkActivityFactory activityFactory, - IMainThreadContext mainThreadContext + IThreadContext threadContext ) { _converter = converter; @@ -55,7 +55,7 @@ IMainThreadContext mainThreadContext _layerBaker = layerBaker; _groupBaker = groupBaker; _activityFactory = activityFactory; - _mainThreadContext = mainThreadContext; + _threadContext = threadContext; } #pragma warning disable CA1506 @@ -68,16 +68,13 @@ public async Task Build( CancellationToken cancellationToken ) { - return await _mainThreadContext - .RunOnThreadAsync( - async () => - { - var ret = BuildSync(rootObject, projectName, modelName, onOperationProgressed); - await Task.Delay(100, cancellationToken).ConfigureAwait(false); - return ret; - }, - false - ) + return await _threadContext + .RunOnWorkerAsync(async () => + { + var ret = BuildSync(rootObject, projectName, modelName, onOperationProgressed); + await Task.Delay(100, cancellationToken).ConfigureAwait(false); + return ret; + }) .ConfigureAwait(false); } diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs index a406e0f3f..397c20eff 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs @@ -34,7 +34,7 @@ public static void AddRhino(this IServiceCollection serviceCollection) serviceCollection.AddSingleton(SpeckleConnectorsRhinoCommand.Instance); serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); serviceCollection.AddDUIView(); // Register other connector specific types diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs index fa3d51dbb..200b9508b 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs @@ -33,7 +33,7 @@ public static IServiceCollection AddTekla(this IServiceCollection services) services.AddSingleton(); services.AddConnectorUtils(); - services.AddDUI(); + services.AddDUI(); services.AddDUIView(); services.AddSingleton(); diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 00e6c79f9..83cabb513 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -28,7 +28,7 @@ public sealed class BrowserBridge : IBrowserBridge private readonly ConcurrentDictionary _resultsStore = new(); public ITopLevelExceptionHandler TopLevelExceptionHandler { get; } - private readonly IMainThreadContext _mainThreadContext; + private readonly IThreadContext _threadContext; private readonly IBrowserScriptExecutor _browserScriptExecutor; private readonly IJsonSerializer _jsonSerializer; @@ -56,14 +56,14 @@ private set } public BrowserBridge( - IMainThreadContext mainThreadContext, + IThreadContext threadContext, IJsonSerializer jsonSerializer, ILogger logger, ILogger topLogger, IBrowserScriptExecutor browserScriptExecutor ) { - _mainThreadContext = mainThreadContext; + _threadContext = threadContext; _jsonSerializer = jsonSerializer; _logger = logger; TopLevelExceptionHandler = new TopLevelExceptionHandler(topLogger, this); @@ -102,25 +102,22 @@ public string[] GetBindingsMethodNames() } public void RunMethod(string methodName, string requestId, string methodArgs) => - _mainThreadContext.RunOnThreadAsync( - async () => - { - var task = await TopLevelExceptionHandler - .CatchUnhandledAsync(async () => - { - var result = await ExecuteMethod(methodName, methodArgs).ConfigureAwait(false); - string resultJson = _jsonSerializer.Serialize(result); - await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); - }) - .ConfigureAwait(false); - if (task.Exception is not null) + _threadContext.RunOnMainAsync(async () => + { + var task = await TopLevelExceptionHandler + .CatchUnhandledAsync(async () => { - string resultJson = SerializeFormattedException(task.Exception); + var result = await ExecuteMethod(methodName, methodArgs).ConfigureAwait(false); + string resultJson = _jsonSerializer.Serialize(result); await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); - } - }, - true - ); + }) + .ConfigureAwait(false); + if (task.Exception is not null) + { + string resultJson = SerializeFormattedException(task.Exception); + await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); + } + }); /// /// Used by the action block to invoke the actual method called by the UI. diff --git a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs index 5d8e5bd03..0d31ee8e1 100644 --- a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs +++ b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs @@ -11,11 +11,11 @@ namespace Speckle.Connectors.DUI; public static class ContainerRegistration { - public static void AddDUI(this IServiceCollection serviceCollection) - where TMainThreadContext : IMainThreadContext, new() + public static void AddDUI(this IServiceCollection serviceCollection) + where TThreadContext : IThreadContext, new() { // send operation and dependencies - serviceCollection.AddSingleton(new TMainThreadContext()); + serviceCollection.AddSingleton(new TThreadContext()); serviceCollection.AddSingleton(); serviceCollection.AddTransient(); // POC: Each binding should have it's own bridge instance diff --git a/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs b/DUI3/Speckle.Connectors.DUI/Threading/ThreadContext.cs similarity index 90% rename from DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs rename to DUI3/Speckle.Connectors.DUI/Threading/ThreadContext.cs index 8767209be..2c9bea3ce 100644 --- a/DUI3/Speckle.Connectors.DUI/Threading/MainThreadContext.cs +++ b/DUI3/Speckle.Connectors.DUI/Threading/ThreadContext.cs @@ -5,16 +5,16 @@ namespace Speckle.Connectors.DUI.Threading; [GenerateAutoInterface] -public class MainThreadContext : IMainThreadContext +public class ThreadContext : IThreadContext { - private readonly SynchronizationContext _mainThreadContext; + private readonly SynchronizationContext _threadContext; // Do this when you start your application private static int s_mainThreadId; - public MainThreadContext() + public ThreadContext() { - _mainThreadContext = SynchronizationContext.Current.NotNull("No UI thread to capture?"); + _threadContext = SynchronizationContext.Current.NotNull("No UI thread to capture?"); s_mainThreadId = Environment.CurrentManagedThreadId; } @@ -22,6 +22,10 @@ public MainThreadContext() public virtual void RunContext(Action action) => action(); + public virtual Task RunContext(Func action) => action(); + + public virtual Task RunContext(Func> action) => action(); + public void RunOnThread(Action action, bool useMain) { if (useMain) @@ -32,7 +36,7 @@ public void RunOnThread(Action action, bool useMain) } else { - _mainThreadContext.Post( + _threadContext.Post( _ => { RunContext(action); @@ -92,10 +96,6 @@ await Task } } - public virtual Task RunContext(Func action) => action(); - - public virtual Task RunContext(Func> action) => action(); - [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] public Task RunOnThreadAsync(Func> action, bool useMain) { @@ -106,7 +106,7 @@ public Task RunOnThreadAsync(Func> action, bool useMain) return RunContext(action.Invoke); } TaskCompletionSource tcs = new(); - _mainThreadContext.Post( + _threadContext.Post( async _ => { try diff --git a/DUI3/Speckle.Connectors.DUI/Threading/ThreadContextExtensions.cs b/DUI3/Speckle.Connectors.DUI/Threading/ThreadContextExtensions.cs new file mode 100644 index 000000000..022d27f6f --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Threading/ThreadContextExtensions.cs @@ -0,0 +1,22 @@ +namespace Speckle.Connectors.DUI.Threading; + +public static class ThreadContextExtensions +{ + public static void RunOnMain(this IThreadContext threadContext, Action action) => + threadContext.RunOnThread(action, true); + + public static void RunOnWorker(this IThreadContext threadContext, Action action) => + threadContext.RunOnThread(action, false); + + public static Task RunOnMainAsync(this IThreadContext threadContext, Func action) => + threadContext.RunOnThreadAsync(action, true); + + public static Task RunOnWorkerAsync(this IThreadContext threadContext, Func action) => + threadContext.RunOnThreadAsync(action, false); + + public static Task RunOnMainAsync(this IThreadContext threadContext, Func> action) => + threadContext.RunOnThreadAsync(action, true); + + public static Task RunOnWorkerAsync(this IThreadContext threadContext, Func> action) => + threadContext.RunOnThreadAsync(action, false); +} From a7699f0bc50e8b5f91fbe3a3020597e0881895b2 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 26 Nov 2024 11:48:23 +0000 Subject: [PATCH 14/65] Revit needs new run async --- .../Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs index 28bb76264..2fde8c265 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs @@ -5,6 +5,8 @@ namespace Speckle.Connectors.Revit.Plugin; public class RevitThreadContext : ThreadContext { + public override Task RunContext(Func action) => RevitTask.RunAsync(action); + public override void RunContext(Action action) => RevitTask.RunAsync(action); public override Task RunContext(Func> action) => RevitTask.RunAsync(action); From 25cbbb42913f7ad8ea034986d0f7c67109e96435 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 26 Nov 2024 15:40:03 +0000 Subject: [PATCH 15/65] merge fixes --- .../DependencyInjection/ArcGISConnectorModule.cs | 3 +-- .../DependencyInjection/SharedRegistration.cs | 3 +-- .../Bindings/BasicConnectorBindingRevit.cs | 2 -- .../DependencyInjection/RevitConnectorModule.cs | 3 +-- .../HostApp/RevitDocumentStore.cs | 12 ------------ .../Registration/ServiceRegistration.cs | 6 +----- .../ServiceRegistration.cs | 3 +-- DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs | 12 +++++------- 8 files changed, 10 insertions(+), 34 deletions(-) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs index 0aaa95865..6bafdfc96 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs @@ -28,8 +28,7 @@ public static class ArcGISConnectorModule public static void AddArcGIS(this IServiceCollection serviceCollection) { serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); serviceCollection.AddDUIView(); // Register bindings serviceCollection.AddSingleton(); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs index 5d9d2b4ad..98a318893 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs @@ -25,8 +25,7 @@ public static class SharedRegistration public static void AddAutocadBase(this IServiceCollection serviceCollection) { serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); serviceCollection.AddDUIView(); // Register other connector specific types diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs index 51cd67cb1..14d6ee7dd 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs @@ -1,6 +1,4 @@ using Autodesk.Revit.DB; -using Microsoft.Extensions.Logging; -using Revit.Async; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs index 606056d41..600cc674e 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs @@ -25,8 +25,7 @@ public static class ServiceRegistration public static void AddRevit(this IServiceCollection serviceCollection) { serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); RegisterUiDependencies(serviceCollection); // Storage Schema diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs index 0d5fef95b..5b8629853 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs @@ -87,7 +87,6 @@ protected override void HostAppSaveState(string modelCardState) { return; } -<<<<<<< HEAD using Transaction t = new(doc, "Speckle Write State"); t.Start(); @@ -96,17 +95,6 @@ protected override void HostAppSaveState(string modelCardState) using Entity stateEntity = new(_documentModelStorageSchema.GetSchema()); string serializedModels = Serialize(); stateEntity.Set("contents", serializedModels); -======= - RevitTask.RunAsync(() => - { - var doc = (_revitContext.UIApplication?.ActiveUIDocument?.Document).NotNull(); - using Transaction t = new(doc, "Speckle Write State"); - t.Start(); - using DataStorage ds = GetSettingsDataStorage(doc) ?? DataStorage.Create(doc); - - using Entity stateEntity = new(_documentModelStorageSchema.GetSchema()); - stateEntity.Set("contents", modelCardState); ->>>>>>> dev using Entity idEntity = new(_idStorageSchema.GetSchema()); idEntity.Set("Id", s_revitDocumentStoreId); diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs index 5d0040802..9a4060dcd 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs @@ -33,11 +33,7 @@ public static void AddRhino(this IServiceCollection serviceCollection) serviceCollection.AddSingleton(SpeckleConnectorsRhinoCommand.Instance); serviceCollection.AddConnectorUtils(); -<<<<<<< HEAD - serviceCollection.AddDUI(); -======= - serviceCollection.AddDUI(); ->>>>>>> dev + serviceCollection.AddDUI(); serviceCollection.AddDUIView(); // Register other connector specific types diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs index 736432744..a4a75c081 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs @@ -32,8 +32,7 @@ public static IServiceCollection AddTekla(this IServiceCollection services) services.AddSingleton(); services.AddConnectorUtils(); - services.AddDUI(); - services.AddDUI(); + services.AddDUI(); services.AddDUIView(); services.AddSingleton(); diff --git a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs index e08668a06..28aed8ef8 100644 --- a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs +++ b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs @@ -3,8 +3,8 @@ using Speckle.Connectors.Common.Operations; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; -using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.DUI.Models; +using Speckle.Connectors.DUI.Threading; using Speckle.Sdk; using Speckle.Sdk.Transports; @@ -12,16 +12,14 @@ namespace Speckle.Connectors.DUI; public static class ContainerRegistration { - public static void AddDUI(this IServiceCollection serviceCollection) - where TThreadContext : IThreadContext, new() -{ - public static void AddDUI(this IServiceCollection serviceCollection) + public static void AddDUI(this IServiceCollection serviceCollection) where TDocumentStore : DocumentModelStore + where TThreadContext : IThreadContext, new() { - serviceCollection.AddSingleton(); - // send operation and dependencies serviceCollection.AddSingleton(new TThreadContext()); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.AddTransient(); // POC: Each binding should have it's own bridge instance From e38102f805b52d07399995ea51bb6d26e99d8269 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 26 Nov 2024 16:12:50 +0000 Subject: [PATCH 16/65] gather on worker, convert on main --- .../DependencyInjection/SharedRegistration.cs | 1 - .../HostApp/AutocadInstanceBaker.cs | 8 +- .../HostApp/AutocadLayerBaker.cs | 8 +- .../HostApp/AutocadMaterialBaker.cs | 4 +- .../Receive/AutocadHostObjectBuilder.cs | 143 ++++++++++++------ .../Plugin/RevitThreadContext.cs | 8 +- .../Threading/ThreadContext.cs | 44 +++++- .../Threading/ThreadContextExtensions.cs | 6 + 8 files changed, 161 insertions(+), 61 deletions(-) diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs index 98a318893..d84de38a3 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs @@ -46,7 +46,6 @@ public static void AddAutocadBase(this IServiceCollection serviceCollection) serviceCollection.AddScoped(); serviceCollection.AddScoped(); - serviceCollection.AddScoped(); serviceCollection.AddSingleton(); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceBaker.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceBaker.cs index cf3439f7f..739cc7612 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceBaker.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceBaker.cs @@ -25,16 +25,16 @@ namespace Speckle.Connectors.Autocad.HostApp; public class AutocadInstanceBaker : IInstanceBaker> { private readonly AutocadLayerBaker _layerBaker; - private readonly AutocadColorBaker _colorBaker; - private readonly AutocadMaterialBaker _materialBaker; + private readonly IAutocadColorBaker _colorBaker; + private readonly IAutocadMaterialBaker _materialBaker; private readonly AutocadContext _autocadContext; private readonly ILogger _logger; private readonly IConverterSettingsStore _converterSettings; public AutocadInstanceBaker( AutocadLayerBaker layerBaker, - AutocadColorBaker colorBaker, - AutocadMaterialBaker materialBaker, + IAutocadColorBaker colorBaker, + IAutocadMaterialBaker materialBaker, AutocadContext autocadContext, ILogger logger, IConverterSettingsStore converterSettings diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadLayerBaker.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadLayerBaker.cs index a7beefdb5..fb86ed438 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadLayerBaker.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadLayerBaker.cs @@ -11,15 +11,15 @@ public class AutocadLayerBaker : TraversalContextUnpacker { private readonly string _layerFilterName = "Speckle"; private readonly AutocadContext _autocadContext; - private readonly AutocadMaterialBaker _materialBaker; - private readonly AutocadColorBaker _colorBaker; + private readonly IAutocadMaterialBaker _materialBaker; + private readonly IAutocadColorBaker _colorBaker; private Document Doc => Application.DocumentManager.MdiActiveDocument; private readonly HashSet _uniqueLayerNames = new(); public AutocadLayerBaker( AutocadContext autocadContext, - AutocadMaterialBaker materialBaker, - AutocadColorBaker colorBaker + IAutocadMaterialBaker materialBaker, + IAutocadColorBaker colorBaker ) { _autocadContext = autocadContext; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadMaterialBaker.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadMaterialBaker.cs index 6afc37ebf..93a542784 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadMaterialBaker.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadMaterialBaker.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Logging; using Speckle.Connectors.Common.Conversion; using Speckle.Connectors.Common.Operations; +using Speckle.InterfaceGenerator; using Speckle.Objects.Other; using Speckle.Sdk; using Speckle.Sdk.Models; @@ -15,7 +16,8 @@ namespace Speckle.Connectors.Autocad.HostApp; /// /// Expects to be a scoped dependency for a given operation and helps with layer creation and cleanup. /// -public class AutocadMaterialBaker +[GenerateAutoInterface] +public class AutocadMaterialBaker : IAutocadMaterialBaker { private readonly ILogger _logger; private readonly AutocadContext _autocadContext; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs index b4e2b86eb..9bdc6fbaa 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs @@ -10,6 +10,7 @@ using Speckle.Sdk; using Speckle.Sdk.Models; using Speckle.Sdk.Models.Collections; +using Speckle.Sdk.Models.GraphTraversal; using Speckle.Sdk.Models.Instances; using AutocadColor = Autodesk.AutoCAD.Colors.Color; @@ -18,62 +19,97 @@ namespace Speckle.Connectors.Autocad.Operations.Receive; /// /// Expects to be a scoped dependency per receive operation. /// -public class AutocadHostObjectBuilder( - IRootToHostConverter converter, - AutocadLayerBaker layerBaker, - AutocadGroupBaker groupBaker, - AutocadInstanceBaker instanceBaker, - AutocadMaterialBaker materialBaker, - IAutocadColorBaker colorBaker, - AutocadContext autocadContext, - RootObjectUnpacker rootObjectUnpacker, - IThreadContext threadContext -) : IHostObjectBuilder +public class AutocadHostObjectBuilder : IHostObjectBuilder { + private readonly AutocadLayerBaker _layerBaker; + private readonly IRootToHostConverter _converter; + private readonly AutocadGroupBaker _groupBaker; + private readonly IAutocadMaterialBaker _materialBaker; + private readonly IAutocadColorBaker _colorBaker; + private readonly AutocadInstanceBaker _instanceBaker; + private readonly AutocadContext _autocadContext; + private readonly RootObjectUnpacker _rootObjectUnpacker; + private readonly IThreadContext _threadContext; + + public AutocadHostObjectBuilder( + IRootToHostConverter converter, + AutocadLayerBaker layerBaker, + AutocadGroupBaker groupBaker, + AutocadInstanceBaker instanceBaker, + IAutocadMaterialBaker materialBaker, + IAutocadColorBaker colorBaker, + AutocadContext autocadContext, + RootObjectUnpacker rootObjectUnpacker, + IThreadContext threadContext + ) + { + _converter = converter; + _layerBaker = layerBaker; + _groupBaker = groupBaker; + _instanceBaker = instanceBaker; + _materialBaker = materialBaker; + _colorBaker = colorBaker; + _autocadContext = autocadContext; + _rootObjectUnpacker = rootObjectUnpacker; + _threadContext = threadContext; + } + public async Task Build( Base rootObject, string projectName, string modelName, IProgress onOperationProgressed, - CancellationToken ct + CancellationToken _ ) { - return await threadContext - .RunOnWorkerAsync(async () => - { - var ret = BuildImpl(rootObject, projectName, modelName, onOperationProgressed); - await Task.Delay(100, ct).ConfigureAwait(false); - return ret; - }) + // NOTE: This is the only place we apply ISyncToThread across connectors. We need to sync up with main thread here + // after GetObject and Deserialization. It is anti-pattern now. Happiness level 3/10 but works. + var x = await _threadContext + .RunOnWorker(() => ReceiveData(rootObject, projectName, modelName, onOperationProgressed)) + .ConfigureAwait(false); + + return await _threadContext + .RunOnMainAsync( + () => + LoadData( + x.baseLayerPrefix, + x.atomicObjects, + x.atomicObjectsWithPath, + x.instanceComponentsWithPath, + x.unpackedRoot, + onOperationProgressed + ) + ) .ConfigureAwait(false); } - private HostObjectBuilderResult BuildImpl( - Base rootObject, - string projectName, - string modelName, - IProgress onOperationProgressed - ) + private ( + string baseLayerPrefix, + List atomicObjects, + List<(Collection[] path, Base current)> atomicObjectsWithPath, + List<(Collection[] path, IInstanceComponent instance)> instanceComponentsWithPath, + RootObjectUnpackerResult unpackedRoot + ) ReceiveData(Base rootObject, string projectName, string modelName, IProgress onOperationProgressed) { // Prompt the UI conversion started. Progress bar will swoosh. onOperationProgressed.Report(new("Converting", null)); // Layer filter for received commit with project and model name - layerBaker.CreateLayerFilter(projectName, modelName); + _layerBaker.CreateLayerFilter(projectName, modelName); // 0 - Clean then Rock n Roll! - string baseLayerPrefix = autocadContext.RemoveInvalidChars($"SPK-{projectName}-{modelName}-"); + string baseLayerPrefix = _autocadContext.RemoveInvalidChars($"SPK-{projectName}-{modelName}-"); PreReceiveDeepClean(baseLayerPrefix); // 1 - Unpack objects and proxies from root commit object - var unpackedRoot = rootObjectUnpacker.Unpack(rootObject); + var unpackedRoot = _rootObjectUnpacker.Unpack(rootObject); // 2 - Split atomic objects and instance components with their path - var (atomicObjects, instanceComponents) = rootObjectUnpacker.SplitAtomicObjectsAndInstances( + var (atomicObjects, instanceComponents) = _rootObjectUnpacker.SplitAtomicObjectsAndInstances( unpackedRoot.ObjectsToConvert ); - var atomicObjectsWithPath = layerBaker.GetAtomicObjectsWithPath(atomicObjects); - var instanceComponentsWithPath = layerBaker.GetInstanceComponentsWithPath(instanceComponents); + var atomicObjectsWithPath = _layerBaker.GetAtomicObjectsWithPath(atomicObjects); + var instanceComponentsWithPath = _layerBaker.GetInstanceComponentsWithPath(instanceComponents); // POC: these are not captured by traversal, so we need to re-add them here if (unpackedRoot.DefinitionProxies != null && unpackedRoot.DefinitionProxies.Count > 0) @@ -87,7 +123,7 @@ IProgress onOperationProgressed // 3 - Bake materials and colors, as they are used later down the line by layers and objects if (unpackedRoot.RenderMaterialProxies != null) { - materialBaker.ParseAndBakeRenderMaterials( + _materialBaker.ParseAndBakeRenderMaterials( unpackedRoot.RenderMaterialProxies, baseLayerPrefix, onOperationProgressed @@ -96,9 +132,21 @@ IProgress onOperationProgressed if (unpackedRoot.ColorProxies != null) { - colorBaker.ParseColors(unpackedRoot.ColorProxies, onOperationProgressed); + _colorBaker.ParseColors(unpackedRoot.ColorProxies, onOperationProgressed); } + return (baseLayerPrefix, atomicObjects, atomicObjectsWithPath, instanceComponentsWithPath, unpackedRoot); + } + + private async Task LoadData( + string baseLayerPrefix, + List atomicObjects, + List<(Collection[] path, Base current)> atomicObjectsWithPath, + List<(Collection[] path, IInstanceComponent instance)> instanceComponentsWithPath, + RootObjectUnpackerResult unpackedRoot, + IProgress onOperationProgressed + ) + { // 5 - Convert atomic objects List results = new(); List bakedObjectIds = new(); @@ -110,7 +158,8 @@ IProgress onOperationProgressed onOperationProgressed.Report(new("Converting objects", (double)++count / atomicObjects.Count)); try { - List convertedObjects = ConvertObject(atomicObject, layerPath, baseLayerPrefix); + List convertedObjects = await ConvertObject(atomicObject, layerPath, baseLayerPrefix) + .ConfigureAwait(true); applicationIdMap[objectId] = convertedObjects; @@ -132,7 +181,7 @@ IProgress onOperationProgressed } // 6 - Convert instances - var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = instanceBaker.BakeInstances( + var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = _instanceBaker.BakeInstances( instanceComponentsWithPath, applicationIdMap, baseLayerPrefix, @@ -147,7 +196,10 @@ IProgress onOperationProgressed // 7 - Create groups if (unpackedRoot.GroupProxies != null) { - List groupResults = groupBaker.CreateGroups(unpackedRoot.GroupProxies, applicationIdMap); + List groupResults = _groupBaker.CreateGroups( + unpackedRoot.GroupProxies, + applicationIdMap + ); results.AddRange(groupResults); } @@ -156,20 +208,20 @@ IProgress onOperationProgressed private void PreReceiveDeepClean(string baseLayerPrefix) { - layerBaker.DeleteAllLayersByPrefix(baseLayerPrefix); - instanceBaker.PurgeInstances(baseLayerPrefix); - materialBaker.PurgeMaterials(baseLayerPrefix); + _layerBaker.DeleteAllLayersByPrefix(baseLayerPrefix); + _instanceBaker.PurgeInstances(baseLayerPrefix); + _materialBaker.PurgeMaterials(baseLayerPrefix); } - private List ConvertObject(Base obj, Collection[] layerPath, string baseLayerNamePrefix) + private async Task> ConvertObject(Base obj, Collection[] layerPath, string baseLayerNamePrefix) { - string layerName = layerBaker.CreateLayerForReceive(layerPath, baseLayerNamePrefix); + string layerName = _layerBaker.CreateLayerForReceive(layerPath, baseLayerNamePrefix); var convertedEntities = new List(); using var tr = Application.DocumentManager.CurrentDocument.Database.TransactionManager.StartTransaction(); // 1: convert - var converted = converter.Convert(obj); + var converted = _converter.Convert(obj); // 2: handle result if (converted is Entity entity) @@ -184,18 +236,19 @@ private List ConvertObject(Base obj, Collection[] layerPath, string base } tr.Commit(); + await Task.Delay(10).ConfigureAwait(true); return convertedEntities; } private Entity BakeObject(Entity entity, Base originalObject, string layerName, Base? parentObject = null) { var objId = originalObject.applicationId ?? originalObject.id; - if (colorBaker.ObjectColorsIdMap.TryGetValue(objId, out AutocadColor? color)) + if (_colorBaker.ObjectColorsIdMap.TryGetValue(objId, out AutocadColor? color)) { entity.Color = color; } - if (materialBaker.TryGetMaterialId(originalObject, parentObject, out ObjectId matId)) + if (_materialBaker.TryGetMaterialId(originalObject, parentObject, out ObjectId matId)) { entity.MaterialId = matId; } @@ -230,7 +283,7 @@ string baseLayerName var groupDictionary = (DBDictionary) tr.GetObject(Application.DocumentManager.CurrentDocument.Database.GroupDictionaryId, OpenMode.ForWrite); - var groupName = autocadContext.RemoveInvalidChars( + var groupName = _autocadContext.RemoveInvalidChars( $@"{parentObject.speckle_type.Split('.').Last()} - {parentObject.applicationId ?? parentObject.id} ({baseLayerName})" ); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs index 2fde8c265..a42dba677 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs @@ -5,9 +5,11 @@ namespace Speckle.Connectors.Revit.Plugin; public class RevitThreadContext : ThreadContext { - public override Task RunContext(Func action) => RevitTask.RunAsync(action); + protected override Task RunContext(Func action) => RevitTask.RunAsync(action); - public override void RunContext(Action action) => RevitTask.RunAsync(action); + protected override Task RunContext(Func action) => RevitTask.RunAsync(action); - public override Task RunContext(Func> action) => RevitTask.RunAsync(action); + protected override void RunContext(Action action) => RevitTask.RunAsync(action); + + protected override Task RunContext(Func> action) => RevitTask.RunAsync(action); } diff --git a/DUI3/Speckle.Connectors.DUI/Threading/ThreadContext.cs b/DUI3/Speckle.Connectors.DUI/Threading/ThreadContext.cs index 2c9bea3ce..22fb743a0 100644 --- a/DUI3/Speckle.Connectors.DUI/Threading/ThreadContext.cs +++ b/DUI3/Speckle.Connectors.DUI/Threading/ThreadContext.cs @@ -20,11 +20,13 @@ public ThreadContext() public static bool IsMainThread => Environment.CurrentManagedThreadId == s_mainThreadId; - public virtual void RunContext(Action action) => action(); + protected virtual void RunContext(Action action) => action(); - public virtual Task RunContext(Func action) => action(); + protected virtual Task RunContext(Func action) => Task.FromResult(action()); - public virtual Task RunContext(Func> action) => action(); + protected virtual Task RunContext(Func action) => action(); + + protected virtual Task RunContext(Func> action) => action(); public void RunOnThread(Action action, bool useMain) { @@ -60,6 +62,42 @@ public void RunOnThread(Action action, bool useMain) } } + [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] + public Task RunOnThread(Func action, bool useMain) + { + if (useMain) + { + if (IsMainThread) + { + return RunContext(action.Invoke); + } + TaskCompletionSource tcs = new(); + _threadContext.Post( + async _ => + { + try + { + T result = await RunContext(action).ConfigureAwait(false); + tcs.SetResult(result); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }, + null + ); + return tcs.Task; + } + if (IsMainThread) + { + Task f = Task.Factory.StartNew(action, default, TaskCreationOptions.LongRunning, TaskScheduler.Default); + return f; + } + + return RunContext(action.Invoke); + } + public async Task RunOnThreadAsync(Func action, bool useMain) { if (useMain) diff --git a/DUI3/Speckle.Connectors.DUI/Threading/ThreadContextExtensions.cs b/DUI3/Speckle.Connectors.DUI/Threading/ThreadContextExtensions.cs index 022d27f6f..0862f732b 100644 --- a/DUI3/Speckle.Connectors.DUI/Threading/ThreadContextExtensions.cs +++ b/DUI3/Speckle.Connectors.DUI/Threading/ThreadContextExtensions.cs @@ -8,6 +8,12 @@ public static void RunOnMain(this IThreadContext threadContext, Action action) = public static void RunOnWorker(this IThreadContext threadContext, Action action) => threadContext.RunOnThread(action, false); + public static Task RunOnMain(this IThreadContext threadContext, Func action) => + threadContext.RunOnThread(action, true); + + public static Task RunOnWorker(this IThreadContext threadContext, Func action) => + threadContext.RunOnThread(action, false); + public static Task RunOnMainAsync(this IThreadContext threadContext, Func action) => threadContext.RunOnThreadAsync(action, true); From 3644054c58925fe878e7616e93dca345514af433 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 26 Nov 2024 16:45:25 +0000 Subject: [PATCH 17/65] operations know threading but not host apps --- .../ArcGISConnectorModule.cs | 2 +- .../Bindings/AutocadBasicConnectorBinding.cs | 2 +- .../Bindings/AutocadSelectionBinding.cs | 2 +- .../Bindings/AutocadSendBaseBinding.cs | 2 +- .../Bindings/AutocadSendBinding.cs | 2 +- .../DependencyInjection/SharedRegistration.cs | 2 +- .../Receive/AutocadHostObjectBuilder.cs | 140 +++++------------- .../Bindings/Civil3dSendBinding.cs | 2 +- .../Receive/RevitHostObjectBuilder.cs | 19 +-- .../Operations/Send/RevitRootObjectBuilder.cs | 19 +-- .../Plugin/RevitThreadContext.cs | 2 +- .../Receive/RhinoHostObjectBuilder.cs | 17 +-- .../Registration/ServiceRegistration.cs | 2 +- .../ServiceRegistration.cs | 2 +- .../Bridge/BrowserBridge.cs | 2 +- .../ContainerRegistration.cs | 2 +- .../Operations/ReceiveOperation.cs | 49 +++--- .../Operations/SendOperation.cs | 24 ++- .../Threading/ThreadContext.cs | 2 +- .../Threading/ThreadContextExtensions.cs | 2 +- 20 files changed, 113 insertions(+), 183 deletions(-) rename {DUI3/Speckle.Connectors.DUI => Sdk/Speckle.Connectors.Common}/Threading/ThreadContext.cs (98%) rename {DUI3/Speckle.Connectors.DUI => Sdk/Speckle.Connectors.Common}/Threading/ThreadContextExtensions.cs (95%) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs index 6bafdfc96..3dd514777 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs @@ -10,10 +10,10 @@ using Speckle.Connectors.Common.Builders; using Speckle.Connectors.Common.Caching; using Speckle.Connectors.Common.Operations; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Models.Card.SendFilter; -using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.DUI.WebView; using Speckle.Converters.Common; using Speckle.Sdk.Models.GraphTraversal; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs index 296b9bb6c..552c43aaf 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs @@ -1,11 +1,11 @@ using Autodesk.AutoCAD.DatabaseServices; using Microsoft.Extensions.Logging; using Speckle.Connectors.Autocad.HostApp.Extensions; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; -using Speckle.Connectors.DUI.Threading; using Speckle.Sdk; using Speckle.Sdk.Common; using Speckle.Sdk.Credentials; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs index 61fb5e739..0af057595 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs @@ -1,9 +1,9 @@ using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Speckle.Connectors.Autocad.HostApp.Extensions; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; -using Speckle.Connectors.DUI.Threading; namespace Speckle.Connectors.Autocad.Bindings; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs index 01f612275..cf2a9b659 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs @@ -8,6 +8,7 @@ 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.Exceptions; @@ -16,7 +17,6 @@ using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Connectors.DUI.Settings; -using Speckle.Connectors.DUI.Threading; using Speckle.Sdk; using Speckle.Sdk.Common; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs index 50b485c30..ddd5c223c 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs @@ -3,11 +3,11 @@ using Speckle.Connectors.Autocad.HostApp; using Speckle.Connectors.Common.Caching; using Speckle.Connectors.Common.Cancellation; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card.SendFilter; -using Speckle.Connectors.DUI.Threading; using Speckle.Converters.Autocad; using Speckle.Converters.Common; using Speckle.Sdk; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs index d84de38a3..9632b802b 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs @@ -10,11 +10,11 @@ using Speckle.Connectors.Common.Caching; using Speckle.Connectors.Common.Instances; using Speckle.Connectors.Common.Operations; +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.Threading; using Speckle.Connectors.DUI.WebView; using Speckle.Sdk.Models.GraphTraversal; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs index 9bdc6fbaa..7f19a85bf 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs @@ -5,12 +5,10 @@ using Speckle.Connectors.Common.Conversion; using Speckle.Connectors.Common.Operations; using Speckle.Connectors.Common.Operations.Receive; -using Speckle.Connectors.DUI.Threading; using Speckle.Converters.Common; using Speckle.Sdk; using Speckle.Sdk.Models; using Speckle.Sdk.Models.Collections; -using Speckle.Sdk.Models.GraphTraversal; using Speckle.Sdk.Models.Instances; using AutocadColor = Autodesk.AutoCAD.Colors.Color; @@ -19,97 +17,56 @@ namespace Speckle.Connectors.Autocad.Operations.Receive; /// /// Expects to be a scoped dependency per receive operation. /// -public class AutocadHostObjectBuilder : IHostObjectBuilder +public class AutocadHostObjectBuilder( + IRootToHostConverter converter, + AutocadLayerBaker layerBaker, + AutocadGroupBaker groupBaker, + AutocadInstanceBaker instanceBaker, + AutocadMaterialBaker materialBaker, + IAutocadColorBaker colorBaker, + AutocadContext autocadContext, + RootObjectUnpacker rootObjectUnpacker +) : IHostObjectBuilder { - private readonly AutocadLayerBaker _layerBaker; - private readonly IRootToHostConverter _converter; - private readonly AutocadGroupBaker _groupBaker; - private readonly IAutocadMaterialBaker _materialBaker; - private readonly IAutocadColorBaker _colorBaker; - private readonly AutocadInstanceBaker _instanceBaker; - private readonly AutocadContext _autocadContext; - private readonly RootObjectUnpacker _rootObjectUnpacker; - private readonly IThreadContext _threadContext; - - public AutocadHostObjectBuilder( - IRootToHostConverter converter, - AutocadLayerBaker layerBaker, - AutocadGroupBaker groupBaker, - AutocadInstanceBaker instanceBaker, - IAutocadMaterialBaker materialBaker, - IAutocadColorBaker colorBaker, - AutocadContext autocadContext, - RootObjectUnpacker rootObjectUnpacker, - IThreadContext threadContext - ) - { - _converter = converter; - _layerBaker = layerBaker; - _groupBaker = groupBaker; - _instanceBaker = instanceBaker; - _materialBaker = materialBaker; - _colorBaker = colorBaker; - _autocadContext = autocadContext; - _rootObjectUnpacker = rootObjectUnpacker; - _threadContext = threadContext; - } - public async Task Build( Base rootObject, string projectName, string modelName, IProgress onOperationProgressed, - CancellationToken _ + CancellationToken ct ) { - // NOTE: This is the only place we apply ISyncToThread across connectors. We need to sync up with main thread here - // after GetObject and Deserialization. It is anti-pattern now. Happiness level 3/10 but works. - var x = await _threadContext - .RunOnWorker(() => ReceiveData(rootObject, projectName, modelName, onOperationProgressed)) - .ConfigureAwait(false); - - return await _threadContext - .RunOnMainAsync( - () => - LoadData( - x.baseLayerPrefix, - x.atomicObjects, - x.atomicObjectsWithPath, - x.instanceComponentsWithPath, - x.unpackedRoot, - onOperationProgressed - ) - ) - .ConfigureAwait(false); + var ret = BuildImpl(rootObject, projectName, modelName, onOperationProgressed); + await Task.Delay(100, ct).ConfigureAwait(false); + return ret; } - private ( - string baseLayerPrefix, - List atomicObjects, - List<(Collection[] path, Base current)> atomicObjectsWithPath, - List<(Collection[] path, IInstanceComponent instance)> instanceComponentsWithPath, - RootObjectUnpackerResult unpackedRoot - ) ReceiveData(Base rootObject, string projectName, string modelName, IProgress onOperationProgressed) + private HostObjectBuilderResult BuildImpl( + Base rootObject, + string projectName, + string modelName, + IProgress onOperationProgressed + ) { // Prompt the UI conversion started. Progress bar will swoosh. onOperationProgressed.Report(new("Converting", null)); // Layer filter for received commit with project and model name - _layerBaker.CreateLayerFilter(projectName, modelName); + layerBaker.CreateLayerFilter(projectName, modelName); // 0 - Clean then Rock n Roll! - string baseLayerPrefix = _autocadContext.RemoveInvalidChars($"SPK-{projectName}-{modelName}-"); + string baseLayerPrefix = autocadContext.RemoveInvalidChars($"SPK-{projectName}-{modelName}-"); PreReceiveDeepClean(baseLayerPrefix); // 1 - Unpack objects and proxies from root commit object - var unpackedRoot = _rootObjectUnpacker.Unpack(rootObject); + var unpackedRoot = rootObjectUnpacker.Unpack(rootObject); // 2 - Split atomic objects and instance components with their path - var (atomicObjects, instanceComponents) = _rootObjectUnpacker.SplitAtomicObjectsAndInstances( + var (atomicObjects, instanceComponents) = rootObjectUnpacker.SplitAtomicObjectsAndInstances( unpackedRoot.ObjectsToConvert ); - var atomicObjectsWithPath = _layerBaker.GetAtomicObjectsWithPath(atomicObjects); - var instanceComponentsWithPath = _layerBaker.GetInstanceComponentsWithPath(instanceComponents); + var atomicObjectsWithPath = layerBaker.GetAtomicObjectsWithPath(atomicObjects); + var instanceComponentsWithPath = layerBaker.GetInstanceComponentsWithPath(instanceComponents); // POC: these are not captured by traversal, so we need to re-add them here if (unpackedRoot.DefinitionProxies != null && unpackedRoot.DefinitionProxies.Count > 0) @@ -123,7 +80,7 @@ RootObjectUnpackerResult unpackedRoot // 3 - Bake materials and colors, as they are used later down the line by layers and objects if (unpackedRoot.RenderMaterialProxies != null) { - _materialBaker.ParseAndBakeRenderMaterials( + materialBaker.ParseAndBakeRenderMaterials( unpackedRoot.RenderMaterialProxies, baseLayerPrefix, onOperationProgressed @@ -132,21 +89,9 @@ RootObjectUnpackerResult unpackedRoot if (unpackedRoot.ColorProxies != null) { - _colorBaker.ParseColors(unpackedRoot.ColorProxies, onOperationProgressed); + colorBaker.ParseColors(unpackedRoot.ColorProxies, onOperationProgressed); } - return (baseLayerPrefix, atomicObjects, atomicObjectsWithPath, instanceComponentsWithPath, unpackedRoot); - } - - private async Task LoadData( - string baseLayerPrefix, - List atomicObjects, - List<(Collection[] path, Base current)> atomicObjectsWithPath, - List<(Collection[] path, IInstanceComponent instance)> instanceComponentsWithPath, - RootObjectUnpackerResult unpackedRoot, - IProgress onOperationProgressed - ) - { // 5 - Convert atomic objects List results = new(); List bakedObjectIds = new(); @@ -158,8 +103,7 @@ IProgress onOperationProgressed onOperationProgressed.Report(new("Converting objects", (double)++count / atomicObjects.Count)); try { - List convertedObjects = await ConvertObject(atomicObject, layerPath, baseLayerPrefix) - .ConfigureAwait(true); + List convertedObjects = ConvertObject(atomicObject, layerPath, baseLayerPrefix); applicationIdMap[objectId] = convertedObjects; @@ -181,7 +125,7 @@ IProgress onOperationProgressed } // 6 - Convert instances - var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = _instanceBaker.BakeInstances( + var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = instanceBaker.BakeInstances( instanceComponentsWithPath, applicationIdMap, baseLayerPrefix, @@ -196,10 +140,7 @@ IProgress onOperationProgressed // 7 - Create groups if (unpackedRoot.GroupProxies != null) { - List groupResults = _groupBaker.CreateGroups( - unpackedRoot.GroupProxies, - applicationIdMap - ); + List groupResults = groupBaker.CreateGroups(unpackedRoot.GroupProxies, applicationIdMap); results.AddRange(groupResults); } @@ -208,20 +149,20 @@ IProgress onOperationProgressed private void PreReceiveDeepClean(string baseLayerPrefix) { - _layerBaker.DeleteAllLayersByPrefix(baseLayerPrefix); - _instanceBaker.PurgeInstances(baseLayerPrefix); - _materialBaker.PurgeMaterials(baseLayerPrefix); + layerBaker.DeleteAllLayersByPrefix(baseLayerPrefix); + instanceBaker.PurgeInstances(baseLayerPrefix); + materialBaker.PurgeMaterials(baseLayerPrefix); } - private async Task> ConvertObject(Base obj, Collection[] layerPath, string baseLayerNamePrefix) + private List ConvertObject(Base obj, Collection[] layerPath, string baseLayerNamePrefix) { - string layerName = _layerBaker.CreateLayerForReceive(layerPath, baseLayerNamePrefix); + string layerName = layerBaker.CreateLayerForReceive(layerPath, baseLayerNamePrefix); var convertedEntities = new List(); using var tr = Application.DocumentManager.CurrentDocument.Database.TransactionManager.StartTransaction(); // 1: convert - var converted = _converter.Convert(obj); + var converted = converter.Convert(obj); // 2: handle result if (converted is Entity entity) @@ -236,19 +177,18 @@ private async Task> ConvertObject(Base obj, Collection[] layerPath, } tr.Commit(); - await Task.Delay(10).ConfigureAwait(true); return convertedEntities; } private Entity BakeObject(Entity entity, Base originalObject, string layerName, Base? parentObject = null) { var objId = originalObject.applicationId ?? originalObject.id; - if (_colorBaker.ObjectColorsIdMap.TryGetValue(objId, out AutocadColor? color)) + if (colorBaker.ObjectColorsIdMap.TryGetValue(objId, out AutocadColor? color)) { entity.Color = color; } - if (_materialBaker.TryGetMaterialId(originalObject, parentObject, out ObjectId matId)) + if (materialBaker.TryGetMaterialId(originalObject, parentObject, out ObjectId matId)) { entity.MaterialId = matId; } @@ -283,7 +223,7 @@ string baseLayerName var groupDictionary = (DBDictionary) tr.GetObject(Application.DocumentManager.CurrentDocument.Database.GroupDictionaryId, OpenMode.ForWrite); - var groupName = _autocadContext.RemoveInvalidChars( + var groupName = autocadContext.RemoveInvalidChars( $@"{parentObject.speckle_type.Split('.').Last()} - {parentObject.applicationId ?? parentObject.id} ({baseLayerName})" ); diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs index a29b42865..4b26c74ef 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs @@ -4,11 +4,11 @@ using Speckle.Connectors.Autocad.HostApp; using Speckle.Connectors.Common.Caching; using Speckle.Connectors.Common.Cancellation; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card.SendFilter; -using Speckle.Connectors.DUI.Threading; using Speckle.Converters.Autocad; using Speckle.Converters.Civil3dShared; using Speckle.Converters.Common; diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs index 536b07ee0..1cbfb6796 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs @@ -5,7 +5,6 @@ using Speckle.Connectors.Common.Instances; using Speckle.Connectors.Common.Operations; using Speckle.Connectors.Common.Operations.Receive; -using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.Revit.HostApp; using Speckle.Converters.Common; using Speckle.Converters.Common.Objects; @@ -34,23 +33,21 @@ internal sealed class RevitHostObjectBuilder( RootObjectUnpacker rootObjectUnpacker, ILogger logger, RevitToHostCacheSingleton revitToHostCacheSingleton, - ITypedConverter<(Base atomicObject, List matrix), DirectShape> localToGlobalDirectShapeConverter, - IThreadContext threadContext + ITypedConverter<(Base atomicObject, List matrix), DirectShape> localToGlobalDirectShapeConverter ) : IHostObjectBuilder, IDisposable { - public Task Build( + public async Task Build( Base rootObject, string projectName, string modelName, IProgress onOperationProgressed, CancellationToken cancellationToken - ) => - threadContext.RunOnWorkerAsync(async () => - { - var ret = BuildSync(rootObject, projectName, modelName, onOperationProgressed, cancellationToken); - await Task.Delay(100, cancellationToken).ConfigureAwait(false); - return ret; - }); + ) + { + var ret = BuildSync(rootObject, projectName, modelName, onOperationProgressed, cancellationToken); + await Task.Delay(100, cancellationToken).ConfigureAwait(false); + return ret; + } private HostObjectBuilderResult BuildSync( Base rootObject, diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs index 691172ea4..923848427 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs @@ -6,7 +6,6 @@ using Speckle.Connectors.Common.Extensions; using Speckle.Connectors.Common.Operations; using Speckle.Connectors.DUI.Exceptions; -using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.Revit.HostApp; using Speckle.Converters.Common; using Speckle.Converters.RevitShared.Helpers; @@ -24,24 +23,22 @@ public class RevitRootObjectBuilder( ElementUnpacker elementUnpacker, SendCollectionManager sendCollectionManager, ILogger logger, - RevitToSpeckleCacheSingleton revitToSpeckleCacheSingleton, - IThreadContext threadContext + RevitToSpeckleCacheSingleton revitToSpeckleCacheSingleton ) : IRootObjectBuilder { // POC: SendSelection and RevitConversionContextStack should be interfaces, former needs interfaces - public Task Build( + public async Task Build( IReadOnlyList objects, SendInfo sendInfo, IProgress onOperationProgressed, CancellationToken ct = default - ) => - threadContext.RunOnWorkerAsync(async () => - { - var ret = BuildSync(objects, sendInfo, onOperationProgressed, ct); - await Task.Delay(100, ct).ConfigureAwait(false); - return ret; - }); + ) + { + var ret = BuildSync(objects, sendInfo, onOperationProgressed, ct); + await Task.Delay(100, ct).ConfigureAwait(false); + return ret; + } private RootObjectBuilderResult BuildSync( IReadOnlyList objects, diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs index a42dba677..59eb5c58d 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs @@ -1,5 +1,5 @@ using Revit.Async; -using Speckle.Connectors.DUI.Threading; +using Speckle.Connectors.Common.Threading; namespace Speckle.Connectors.Revit.Plugin; diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs index 5403e9d4f..460af0a38 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs @@ -5,7 +5,6 @@ using Speckle.Connectors.Common.Conversion; using Speckle.Connectors.Common.Operations; using Speckle.Connectors.Common.Operations.Receive; -using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.Rhino.HostApp; using Speckle.Converters.Common; using Speckle.Converters.Rhino; @@ -31,7 +30,6 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder private readonly RhinoGroupBaker _groupBaker; private readonly RootObjectUnpacker _rootObjectUnpacker; private readonly ISdkActivityFactory _activityFactory; - private readonly IThreadContext _threadContext; public RhinoHostObjectBuilder( IRootToHostConverter converter, @@ -42,8 +40,7 @@ public RhinoHostObjectBuilder( RhinoMaterialBaker materialBaker, RhinoColorBaker colorBaker, RhinoGroupBaker groupBaker, - ISdkActivityFactory activityFactory, - IThreadContext threadContext + ISdkActivityFactory activityFactory ) { _converter = converter; @@ -55,7 +52,6 @@ IThreadContext threadContext _layerBaker = layerBaker; _groupBaker = groupBaker; _activityFactory = activityFactory; - _threadContext = threadContext; } #pragma warning disable CA1506 @@ -68,14 +64,9 @@ public async Task Build( CancellationToken cancellationToken ) { - return await _threadContext - .RunOnWorkerAsync(async () => - { - var ret = BuildSync(rootObject, projectName, modelName, onOperationProgressed); - await Task.Delay(100, cancellationToken).ConfigureAwait(false); - return ret; - }) - .ConfigureAwait(false); + var ret = BuildSync(rootObject, projectName, modelName, onOperationProgressed); + await Task.Delay(100, cancellationToken).ConfigureAwait(false); + return ret; } public HostObjectBuilderResult BuildSync( diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs index 9a4060dcd..a461cf8b4 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs @@ -8,11 +8,11 @@ using Speckle.Connectors.Common.Cancellation; using Speckle.Connectors.Common.Instances; using Speckle.Connectors.Common.Operations; +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.Threading; using Speckle.Connectors.DUI.WebView; using Speckle.Connectors.Rhino.Bindings; using Speckle.Connectors.Rhino.Filters; diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs index a4a75c081..2b240179f 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs @@ -9,11 +9,11 @@ using Speckle.Connectors.Common.Caching; using Speckle.Connectors.Common.Cancellation; using Speckle.Connectors.Common.Operations; +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.Threading; using Speckle.Connectors.DUI.WebView; using Speckle.Converter.Tekla2024; using Speckle.Converters.Common; diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 83cabb513..f951a9642 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -4,8 +4,8 @@ using System.Reflection; using System.Runtime.InteropServices; using Microsoft.Extensions.Logging; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; -using Speckle.Connectors.DUI.Threading; using Speckle.Connectors.DUI.Utils; using Speckle.Newtonsoft.Json; using Speckle.Sdk.Common; diff --git a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs index 28aed8ef8..244727976 100644 --- a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs +++ b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs @@ -1,10 +1,10 @@ using System.Reflection; using Microsoft.Extensions.DependencyInjection; using Speckle.Connectors.Common.Operations; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; -using Speckle.Connectors.DUI.Threading; using Speckle.Sdk; using Speckle.Sdk.Transports; diff --git a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs index 84e6fee41..45f025963 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs @@ -1,4 +1,5 @@ using Speckle.Connectors.Common.Builders; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.Logging; using Speckle.Sdk.Api; using Speckle.Sdk.Credentials; @@ -13,29 +14,29 @@ public sealed class ReceiveOperation { private readonly IHostObjectBuilder _hostObjectBuilder; private readonly AccountService _accountService; - private readonly IServerTransportFactory _serverTransportFactory; private readonly IProgressDisplayManager _progressDisplayManager; private readonly ISdkActivityFactory _activityFactory; private readonly IOperations _operations; private readonly IClientFactory _clientFactory; + private readonly IThreadContext _threadContext; public ReceiveOperation( IHostObjectBuilder hostObjectBuilder, AccountService accountService, - IServerTransportFactory serverTransportFactory, IProgressDisplayManager progressDisplayManager, ISdkActivityFactory activityFactory, IOperations operations, - IClientFactory clientFactory + IClientFactory clientFactory, + IThreadContext threadContext ) { _hostObjectBuilder = hostObjectBuilder; _accountService = accountService; - _serverTransportFactory = serverTransportFactory; _progressDisplayManager = progressDisplayManager; _activityFactory = activityFactory; _operations = operations; _clientFactory = clientFactory; + _threadContext = threadContext; } public async Task Execute( @@ -55,8 +56,30 @@ CancellationToken cancellationToken .Version.Get(receiveInfo.SelectedVersionId, receiveInfo.ProjectId, cancellationToken) .ConfigureAwait(false); - using var transport = _serverTransportFactory.Create(account, receiveInfo.ProjectId); + var commitObject = await _threadContext + .RunOnWorkerAsync(() => ReceiveData(account, version, receiveInfo, onOperationProgressed, cancellationToken)) + .ConfigureAwait(false); + + // 4 - Convert objects + HostObjectBuilderResult res = await _threadContext + .RunOnMainAsync(() => ConvertObjects(commitObject, receiveInfo, onOperationProgressed, cancellationToken)) + .ConfigureAwait(false); + await apiClient + .Version.Received(new(version.id, receiveInfo.ProjectId, receiveInfo.SourceApplication), cancellationToken) + .ConfigureAwait(false); + + return res; + } + + private async Task ReceiveData( + Account account, + Speckle.Sdk.Api.GraphQL.Models.Version version, + ReceiveInfo receiveInfo, + IProgress onOperationProgressed, + CancellationToken cancellationToken + ) + { double? previousPercentage = null; _progressDisplayManager.Begin(); Base? commitObject = await _operations @@ -97,21 +120,7 @@ CancellationToken cancellationToken .ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); - - // 4 - Convert objects - HostObjectBuilderResult? res = await ConvertObjects( - commitObject, - receiveInfo, - onOperationProgressed, - cancellationToken - ) - .ConfigureAwait(false); - - await apiClient - .Version.Received(new(version.id, receiveInfo.ProjectId, receiveInfo.SourceApplication), cancellationToken) - .ConfigureAwait(false); - - return res; + return commitObject; } private async Task ConvertObjects( diff --git a/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs b/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs index 665e1910c..499332781 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs @@ -1,21 +1,17 @@ using Speckle.Connectors.Common.Builders; using Speckle.Connectors.Common.Conversion; +using Speckle.Connectors.Common.Threading; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; namespace Speckle.Connectors.Common.Operations; -public sealed class SendOperation +public sealed class SendOperation( + IRootObjectBuilder rootObjectBuilder, + IRootObjectSender baseObjectSender, + IThreadContext threadContext +) { - private readonly IRootObjectBuilder _rootObjectBuilder; - private readonly IRootObjectSender _baseObjectSender; - - public SendOperation(IRootObjectBuilder rootObjectBuilder, IRootObjectSender baseObjectSender) - { - _rootObjectBuilder = rootObjectBuilder; - _baseObjectSender = baseObjectSender; - } - public async Task Execute( IReadOnlyList objects, SendInfo sendInfo, @@ -23,8 +19,8 @@ public async Task Execute( CancellationToken ct = default ) { - var buildResult = await _rootObjectBuilder - .Build(objects, sendInfo, onOperationProgressed, ct) + var buildResult = await threadContext + .RunOnMainAsync(() => rootObjectBuilder.Build(objects, sendInfo, onOperationProgressed, ct)) .ConfigureAwait(false); // POC: Jonathon asks on behalf of willow twin - let's explore how this can work @@ -33,8 +29,8 @@ public async Task Execute( buildResult.RootObject["version"] = 3; // base object handler is separated, so we can do some testing on non-production databases // exact interface may want to be tweaked when we implement this - var (rootObjId, convertedReferences) = await _baseObjectSender - .Send(buildResult.RootObject, sendInfo, onOperationProgressed, ct) + var (rootObjId, convertedReferences) = await threadContext + .RunOnWorkerAsync(() => baseObjectSender.Send(buildResult.RootObject, sendInfo, onOperationProgressed, ct)) .ConfigureAwait(false); return new(rootObjId, convertedReferences, buildResult.ConversionResults); diff --git a/DUI3/Speckle.Connectors.DUI/Threading/ThreadContext.cs b/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs similarity index 98% rename from DUI3/Speckle.Connectors.DUI/Threading/ThreadContext.cs rename to Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs index 22fb743a0..441fb91df 100644 --- a/DUI3/Speckle.Connectors.DUI/Threading/ThreadContext.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs @@ -2,7 +2,7 @@ using Speckle.InterfaceGenerator; using Speckle.Sdk.Common; -namespace Speckle.Connectors.DUI.Threading; +namespace Speckle.Connectors.Common.Threading; [GenerateAutoInterface] public class ThreadContext : IThreadContext diff --git a/DUI3/Speckle.Connectors.DUI/Threading/ThreadContextExtensions.cs b/Sdk/Speckle.Connectors.Common/Threading/ThreadContextExtensions.cs similarity index 95% rename from DUI3/Speckle.Connectors.DUI/Threading/ThreadContextExtensions.cs rename to Sdk/Speckle.Connectors.Common/Threading/ThreadContextExtensions.cs index 0862f732b..ddf29854c 100644 --- a/DUI3/Speckle.Connectors.DUI/Threading/ThreadContextExtensions.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/ThreadContextExtensions.cs @@ -1,4 +1,4 @@ -namespace Speckle.Connectors.DUI.Threading; +namespace Speckle.Connectors.Common.Threading; public static class ThreadContextExtensions { From d416e7612a09cc5d9ea3f30900932e252e249fbe Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Wed, 27 Nov 2024 09:38:13 +0000 Subject: [PATCH 18/65] rhino options --- .../Operations/Send/RevitRootObjectBuilder.cs | 14 +------------- .../Operations/Receive/RhinoHostObjectBuilder.cs | 15 +-------------- .../Operations/Send/RhinoRootObjectBuilder.cs | 7 ++----- .../Builders/IHostObjectBuilder.cs | 6 ++---- .../Builders/IRootObjectBuilder.cs | 5 ++--- .../Operations/SendOperation.cs | 2 +- .../Threading/ThreadOptions.cs | 6 ++++++ 7 files changed, 15 insertions(+), 40 deletions(-) create mode 100644 Sdk/Speckle.Connectors.Common/Threading/ThreadOptions.cs diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs index 923848427..fc47ca10f 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs @@ -28,19 +28,7 @@ RevitToSpeckleCacheSingleton revitToSpeckleCacheSingleton { // POC: SendSelection and RevitConversionContextStack should be interfaces, former needs interfaces - public async Task Build( - IReadOnlyList objects, - SendInfo sendInfo, - IProgress onOperationProgressed, - CancellationToken ct = default - ) - { - var ret = BuildSync(objects, sendInfo, onOperationProgressed, ct); - await Task.Delay(100, ct).ConfigureAwait(false); - return ret; - } - - private RootObjectBuilderResult BuildSync( + public RootObjectBuilderResult Build( IReadOnlyList objects, SendInfo sendInfo, IProgress onOperationProgressed, diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs index 460af0a38..47a3d7681 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs @@ -55,21 +55,8 @@ ISdkActivityFactory activityFactory } #pragma warning disable CA1506 - public async Task Build( + public HostObjectBuilderResult Build( #pragma warning restore CA1506 - Base rootObject, - string projectName, - string modelName, - IProgress onOperationProgressed, - CancellationToken cancellationToken - ) - { - var ret = BuildSync(rootObject, projectName, modelName, onOperationProgressed); - await Task.Delay(100, cancellationToken).ConfigureAwait(false); - return ret; - } - - public HostObjectBuilderResult BuildSync( Base rootObject, string projectName, string modelName, diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Send/RhinoRootObjectBuilder.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Send/RhinoRootObjectBuilder.cs index 5f337e491..1d15c5d3b 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Send/RhinoRootObjectBuilder.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Send/RhinoRootObjectBuilder.cs @@ -60,11 +60,10 @@ ISdkActivityFactory activityFactory _activityFactory = activityFactory; } - public async Task Build( + public RootObjectBuilderResult Build( IReadOnlyList rhinoObjects, SendInfo sendInfo, - IProgress onOperationProgressed, - CancellationToken cancellationToken = default + IProgress onOperationProgressed ) { using var activity = _activityFactory.Start("Build"); @@ -96,7 +95,6 @@ public async Task Build( foreach (RhinoObject rhinoObject in atomicObjects) { using var _2 = _activityFactory.Start("Convert"); - cancellationToken.ThrowIfCancellationRequested(); // handle layer Layer layer = _converterSettings.Current.Document.Layers[rhinoObject.Attributes.LayerIndex]; @@ -130,7 +128,6 @@ public async Task Build( rootObjectCollection[ProxyKeys.COLOR] = _colorUnpacker.UnpackColors(atomicObjects, versionLayers.ToList()); } - await Task.Yield(); return new RootObjectBuilderResult(rootObjectCollection, results); } diff --git a/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs b/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs index 7d9e150dc..30ebc7eb9 100644 --- a/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs +++ b/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs @@ -14,16 +14,14 @@ public interface IHostObjectBuilder /// Project of the model. /// Name of the model. /// Action to update UI progress bar. - /// Cancellation token that passed from top -> ReceiveBinding. /// List of application ids. // POC: Where we will return these ids will matter later when we target to also cache received application ids. /// Project and model name are needed for now to construct host app objects into related layers or filters. /// POC: we might consider later to have HostObjectBuilderContext? that might hold all possible data we will need. - Task Build( + HostObjectBuilderResult Build( Base rootObject, string projectName, string modelName, - IProgress onOperationProgressed, - CancellationToken cancellationToken + IProgress onOperationProgressed ); } diff --git a/Sdk/Speckle.Connectors.Common/Builders/IRootObjectBuilder.cs b/Sdk/Speckle.Connectors.Common/Builders/IRootObjectBuilder.cs index f3584c726..c018b2b4d 100644 --- a/Sdk/Speckle.Connectors.Common/Builders/IRootObjectBuilder.cs +++ b/Sdk/Speckle.Connectors.Common/Builders/IRootObjectBuilder.cs @@ -6,11 +6,10 @@ namespace Speckle.Connectors.Common.Builders; public interface IRootObjectBuilder { - public Task Build( + public RootObjectBuilderResult Build( IReadOnlyList objects, SendInfo sendInfo, - IProgress onOperationProgressed, - CancellationToken ct = default + IProgress onOperationProgressed ); } diff --git a/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs b/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs index 499332781..327cb639c 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs @@ -20,7 +20,7 @@ public async Task Execute( ) { var buildResult = await threadContext - .RunOnMainAsync(() => rootObjectBuilder.Build(objects, sendInfo, onOperationProgressed, ct)) + .RunOnMain(() => rootObjectBuilder.Build(objects, sendInfo, onOperationProgressed)) .ConfigureAwait(false); // POC: Jonathon asks on behalf of willow twin - let's explore how this can work diff --git a/Sdk/Speckle.Connectors.Common/Threading/ThreadOptions.cs b/Sdk/Speckle.Connectors.Common/Threading/ThreadOptions.cs new file mode 100644 index 000000000..ba37a4489 --- /dev/null +++ b/Sdk/Speckle.Connectors.Common/Threading/ThreadOptions.cs @@ -0,0 +1,6 @@ +namespace Speckle.Connectors.Common.Threading; + +public class ThreadOptions +{ + +} From 9c83cee6416b2e30c65ce9eb97cfe7f50d7ca73f Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Wed, 27 Nov 2024 09:49:41 +0000 Subject: [PATCH 19/65] revit can receive --- .../Receive/RevitHostObjectBuilder.cs | 24 ++++--------------- .../Operations/Send/RevitRootObjectBuilder.cs | 4 +--- .../Operations/ReceiveOperation.cs | 17 +++++++------ .../Threading/ThreadOptions.cs | 11 ++++++--- 4 files changed, 21 insertions(+), 35 deletions(-) diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs index 1cbfb6796..07b483176 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs @@ -36,25 +36,11 @@ internal sealed class RevitHostObjectBuilder( ITypedConverter<(Base atomicObject, List matrix), DirectShape> localToGlobalDirectShapeConverter ) : IHostObjectBuilder, IDisposable { - public async Task Build( + public HostObjectBuilderResult Build( Base rootObject, string projectName, string modelName, - IProgress onOperationProgressed, - CancellationToken cancellationToken - ) - { - var ret = BuildSync(rootObject, projectName, modelName, onOperationProgressed, cancellationToken); - await Task.Delay(100, cancellationToken).ConfigureAwait(false); - return ret; - } - - private HostObjectBuilderResult BuildSync( - Base rootObject, - string projectName, - string modelName, - IProgress onOperationProgressed, - CancellationToken cancellationToken + IProgress onOperationProgressed ) { var baseGroupName = $"Project {projectName}: Model {modelName}"; // TODO: unify this across connectors! @@ -106,7 +92,7 @@ CancellationToken cancellationToken { using var _ = activityFactory.Start("Baking objects"); transactionManager.StartTransaction(true, "Baking objects"); - conversionResults = BakeObjects(localToGlobalMaps, onOperationProgressed, cancellationToken); + conversionResults = BakeObjects(localToGlobalMaps, onOperationProgressed); transactionManager.CommitTransaction(); } @@ -134,8 +120,7 @@ CancellationToken cancellationToken List<(DirectShape res, string applicationId)> postBakePaintTargets ) BakeObjects( List localToGlobalMaps, - IProgress onOperationProgressed, - CancellationToken cancellationToken + IProgress onOperationProgressed ) { using var _ = activityFactory.Start("BakeObjects"); @@ -147,7 +132,6 @@ CancellationToken cancellationToken foreach (LocalToGlobalMap localToGlobalMap in localToGlobalMaps) { - cancellationToken.ThrowIfCancellationRequested(); try { using var activity = activityFactory.Start("BakeObject"); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs index fc47ca10f..287214e2a 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs @@ -31,8 +31,7 @@ RevitToSpeckleCacheSingleton revitToSpeckleCacheSingleton public RootObjectBuilderResult Build( IReadOnlyList objects, SendInfo sendInfo, - IProgress onOperationProgressed, - CancellationToken ct = default + IProgress onOperationProgressed ) { var doc = converterSettings.Current.Document; @@ -74,7 +73,6 @@ public RootObjectBuilderResult Build( foreach (Element revitElement in atomicObjects) { - ct.ThrowIfCancellationRequested(); string applicationId = revitElement.UniqueId; string sourceType = revitElement.GetType().Name; try diff --git a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs index 45f025963..94764c28a 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs @@ -19,6 +19,7 @@ public sealed class ReceiveOperation private readonly IOperations _operations; private readonly IClientFactory _clientFactory; private readonly IThreadContext _threadContext; + private readonly IThreadOptions _threadOptions; public ReceiveOperation( IHostObjectBuilder hostObjectBuilder, @@ -27,8 +28,7 @@ public ReceiveOperation( ISdkActivityFactory activityFactory, IOperations operations, IClientFactory clientFactory, - IThreadContext threadContext - ) + IThreadContext threadContext, IThreadOptions threadOptions) { _hostObjectBuilder = hostObjectBuilder; _accountService = accountService; @@ -37,6 +37,7 @@ IThreadContext threadContext _operations = operations; _clientFactory = clientFactory; _threadContext = threadContext; + _threadOptions = threadOptions; } public async Task Execute( @@ -62,7 +63,7 @@ CancellationToken cancellationToken // 4 - Convert objects HostObjectBuilderResult res = await _threadContext - .RunOnMainAsync(() => ConvertObjects(commitObject, receiveInfo, onOperationProgressed, cancellationToken)) + .RunOnThread(() => ConvertObjects(commitObject, receiveInfo, onOperationProgressed), _threadOptions.RunReceiveBuildOnMainThread) .ConfigureAwait(false); await apiClient @@ -123,11 +124,10 @@ CancellationToken cancellationToken return commitObject; } - private async Task ConvertObjects( + private HostObjectBuilderResult ConvertObjects( Base commitObject, ReceiveInfo receiveInfo, - IProgress onOperationProgressed, - CancellationToken cancellationToken + IProgress onOperationProgressed ) { using var conversionActivity = _activityFactory.Start("ReceiveOperation.ConvertObjects"); @@ -140,9 +140,8 @@ CancellationToken cancellationToken try { - HostObjectBuilderResult res = await _hostObjectBuilder - .Build(commitObject, receiveInfo.ProjectName, receiveInfo.ModelName, onOperationProgressed, cancellationToken) - .ConfigureAwait(false); + HostObjectBuilderResult res = _hostObjectBuilder + .Build(commitObject, receiveInfo.ProjectName, receiveInfo.ModelName, onOperationProgressed); conversionActivity?.SetStatus(SdkActivityStatusCode.Ok); return res; } diff --git a/Sdk/Speckle.Connectors.Common/Threading/ThreadOptions.cs b/Sdk/Speckle.Connectors.Common/Threading/ThreadOptions.cs index ba37a4489..38ead87e7 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/ThreadOptions.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/ThreadOptions.cs @@ -1,6 +1,11 @@ -namespace Speckle.Connectors.Common.Threading; +using Speckle.InterfaceGenerator; +using Speckle.Sdk; +using Speckle.Sdk.Host; -public class ThreadOptions +namespace Speckle.Connectors.Common.Threading; + +[GenerateAutoInterface] +public class ThreadOptions(ISpeckleApplication speckleApplication) : IThreadOptions { - + public bool RunReceiveBuildOnMainThread => speckleApplication.HostApplication != HostApplications.Rhino.Name; } From 8708779a51a088fe851e9ca9fa671bda6f076172 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Wed, 27 Nov 2024 10:16:40 +0000 Subject: [PATCH 20/65] autocad in progress --- .../Receive/AutocadHostObjectBuilder.cs | 17 ++------------ .../Send/AutocadRootObjectBaseBuilder.cs | 23 ++++++------------- 2 files changed, 9 insertions(+), 31 deletions(-) diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs index 7f19a85bf..b5cf36ad9 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs @@ -22,26 +22,13 @@ public class AutocadHostObjectBuilder( AutocadLayerBaker layerBaker, AutocadGroupBaker groupBaker, AutocadInstanceBaker instanceBaker, - AutocadMaterialBaker materialBaker, + IAutocadMaterialBaker materialBaker, IAutocadColorBaker colorBaker, AutocadContext autocadContext, RootObjectUnpacker rootObjectUnpacker ) : IHostObjectBuilder { - public async Task Build( - Base rootObject, - string projectName, - string modelName, - IProgress onOperationProgressed, - CancellationToken ct - ) - { - var ret = BuildImpl(rootObject, projectName, modelName, onOperationProgressed); - await Task.Delay(100, ct).ConfigureAwait(false); - return ret; - } - - private HostObjectBuilderResult BuildImpl( + public HostObjectBuilderResult Build( Base rootObject, string projectName, string modelName, diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBaseBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBaseBuilder.cs index 9c8c77e15..6e95c9948 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBaseBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBaseBuilder.cs @@ -49,28 +49,20 @@ ISdkActivityFactory activityFactory _activityFactory = activityFactory; } - public Task Build( - IReadOnlyList objects, - SendInfo sendInfo, - IProgress onOperationProgressed, - CancellationToken ct = default - ) => Task.FromResult(BuildSync(objects, sendInfo, onOperationProgressed, ct)); - [SuppressMessage( "Maintainability", "CA1506:Avoid excessive class coupling", Justification = """ - It is already simplified but has many different references since it is a builder. Do not know can we simplify it now. - Later we might consider to refactor proxies from one proxy manager? but we do not know the shape of it all potential - proxy classes yet. So I'm supressing this one now!!! - """ + It is already simplified but has many different references since it is a builder. Do not know can we simplify it now. + Later we might consider to refactor proxies from one proxy manager? but we do not know the shape of it all potential + proxy classes yet. So I'm supressing this one now!!! + """ )] - private RootObjectBuilderResult BuildSync( + public RootObjectBuilderResult Build( IReadOnlyList objects, SendInfo sendInfo, - IProgress onOperationProgressed, - CancellationToken ct = default - ) + IProgress onOperationProgressed + ) { // 0 - Init the root Collection root = @@ -101,7 +93,6 @@ private RootObjectBuilderResult BuildSync( int count = 0; foreach (var (entity, applicationId) in atomicObjects) { - ct.ThrowIfCancellationRequested(); using (var convertActivity = _activityFactory.Start("Converting object")) { // Create and add a collection for this entity if not done so already. From ca6ce6c400a959c7843504fef032850d3dc1c9fd Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Wed, 27 Nov 2024 13:37:08 +0000 Subject: [PATCH 21/65] need to yield for UI thread async --- .../Receive/AutocadHostObjectBuilder.cs | 8 ++++-- .../Builders/IHostObjectBuilder.cs | 5 ++-- .../Operations/ReceiveOperation.cs | 11 ++++---- .../Threading/Yield.cs | 25 +++++++++++++++++++ 4 files changed, 40 insertions(+), 9 deletions(-) create mode 100644 Sdk/Speckle.Connectors.Common/Threading/Yield.cs diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs index b5cf36ad9..bcb0f36fa 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs @@ -5,6 +5,7 @@ using Speckle.Connectors.Common.Conversion; using Speckle.Connectors.Common.Operations; using Speckle.Connectors.Common.Operations.Receive; +using Speckle.Connectors.Common.Threading; using Speckle.Converters.Common; using Speckle.Sdk; using Speckle.Sdk.Models; @@ -28,15 +29,17 @@ public class AutocadHostObjectBuilder( RootObjectUnpacker rootObjectUnpacker ) : IHostObjectBuilder { - public HostObjectBuilderResult Build( + public async Task Build( Base rootObject, string projectName, string modelName, - IProgress onOperationProgressed + IProgress onOperationProgressed, + CancellationToken cancellationToken ) { // Prompt the UI conversion started. Progress bar will swoosh. onOperationProgressed.Report(new("Converting", null)); + await Yield.Force().ConfigureAwait(true); // Layer filter for received commit with project and model name layerBaker.CreateLayerFilter(projectName, modelName); @@ -88,6 +91,7 @@ IProgress onOperationProgressed { string objectId = atomicObject.applicationId ?? atomicObject.id; onOperationProgressed.Report(new("Converting objects", (double)++count / atomicObjects.Count)); + await Yield.Force().ConfigureAwait(true); try { List convertedObjects = ConvertObject(atomicObject, layerPath, baseLayerPrefix); diff --git a/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs b/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs index 30ebc7eb9..aa19cc90f 100644 --- a/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs +++ b/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs @@ -17,11 +17,12 @@ public interface IHostObjectBuilder /// List of application ids. // POC: Where we will return these ids will matter later when we target to also cache received application ids. /// Project and model name are needed for now to construct host app objects into related layers or filters. /// POC: we might consider later to have HostObjectBuilderContext? that might hold all possible data we will need. - HostObjectBuilderResult Build( + Task Build( Base rootObject, string projectName, string modelName, - IProgress onOperationProgressed + IProgress onOperationProgressed, + CancellationToken cancellationToken ); } diff --git a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs index 94764c28a..054459b8a 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs @@ -63,7 +63,7 @@ CancellationToken cancellationToken // 4 - Convert objects HostObjectBuilderResult res = await _threadContext - .RunOnThread(() => ConvertObjects(commitObject, receiveInfo, onOperationProgressed), _threadOptions.RunReceiveBuildOnMainThread) + .RunOnThreadAsync(() => ConvertObjects(commitObject, receiveInfo, onOperationProgressed, cancellationToken), _threadOptions.RunReceiveBuildOnMainThread) .ConfigureAwait(false); await apiClient @@ -124,10 +124,11 @@ CancellationToken cancellationToken return commitObject; } - private HostObjectBuilderResult ConvertObjects( + private async Task ConvertObjects( Base commitObject, ReceiveInfo receiveInfo, - IProgress onOperationProgressed + IProgress onOperationProgressed, + CancellationToken cancellationToken ) { using var conversionActivity = _activityFactory.Start("ReceiveOperation.ConvertObjects"); @@ -140,8 +141,8 @@ IProgress onOperationProgressed try { - HostObjectBuilderResult res = _hostObjectBuilder - .Build(commitObject, receiveInfo.ProjectName, receiveInfo.ModelName, onOperationProgressed); + HostObjectBuilderResult res = await _hostObjectBuilder + .Build(commitObject, receiveInfo.ProjectName, receiveInfo.ModelName, onOperationProgressed, cancellationToken).ConfigureAwait(false); conversionActivity?.SetStatus(SdkActivityStatusCode.Ok); return res; } diff --git a/Sdk/Speckle.Connectors.Common/Threading/Yield.cs b/Sdk/Speckle.Connectors.Common/Threading/Yield.cs new file mode 100644 index 000000000..70606a0bf --- /dev/null +++ b/Sdk/Speckle.Connectors.Common/Threading/Yield.cs @@ -0,0 +1,25 @@ +namespace Speckle.Connectors.Common.Threading; + +public static class Yield +{ + + private static readonly Action s_yield = () => { }; + + public static async ValueTask Force() + { + if (ThreadContext.IsMainThread) + { + await Task.Factory.StartNew( + s_yield, + CancellationToken.None, + TaskCreationOptions.PreferFairness, + SynchronizationContext.Current != null + ? TaskScheduler.FromCurrentSynchronizationContext() + : TaskScheduler.Current).ConfigureAwait(false); + } + else + { + await Task.Yield(); + } + } +} From ea45057c03db792d33acfab50a5a02210083c977 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Wed, 27 Nov 2024 13:47:59 +0000 Subject: [PATCH 22/65] revamp yield --- .../Operations/Receive/AutocadHostObjectBuilder.cs | 4 ++-- .../Operations/Receive/RevitHostObjectBuilder.cs | 6 +++--- .../Operations/Receive/RhinoHostObjectBuilder.cs | 4 ++-- .../Builders/IHostObjectBuilder.cs | 9 +++++++++ Sdk/Speckle.Connectors.Common/Threading/Yield.cs | 7 +++++++ 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs index bcb0f36fa..38c874037 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs @@ -39,7 +39,7 @@ CancellationToken cancellationToken { // Prompt the UI conversion started. Progress bar will swoosh. onOperationProgressed.Report(new("Converting", null)); - await Yield.Force().ConfigureAwait(true); + await Yield.Force().BackToThread(); // Layer filter for received commit with project and model name layerBaker.CreateLayerFilter(projectName, modelName); @@ -91,7 +91,7 @@ CancellationToken cancellationToken { string objectId = atomicObject.applicationId ?? atomicObject.id; onOperationProgressed.Report(new("Converting objects", (double)++count / atomicObjects.Count)); - await Yield.Force().ConfigureAwait(true); + await Yield.Force().BackToThread(); try { List convertedObjects = ConvertObject(atomicObject, layerPath, baseLayerPrefix); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs index 07b483176..2cc466dc0 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs @@ -22,7 +22,7 @@ namespace Speckle.Connectors.Revit.Operations.Receive; -internal sealed class RevitHostObjectBuilder( +public sealed class RevitHostObjectBuilder( IRootToHostConverter converter, IConverterSettingsStore converterSettings, ITransactionManager transactionManager, @@ -34,9 +34,9 @@ internal sealed class RevitHostObjectBuilder( ILogger logger, RevitToHostCacheSingleton revitToHostCacheSingleton, ITypedConverter<(Base atomicObject, List matrix), DirectShape> localToGlobalDirectShapeConverter -) : IHostObjectBuilder, IDisposable +) : HostObjectBuilder, IDisposable { - public HostObjectBuilderResult Build( + protected override HostObjectBuilderResult Build( Base rootObject, string projectName, string modelName, diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs index 47a3d7681..dd0787f6e 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs @@ -19,7 +19,7 @@ namespace Speckle.Connectors.Rhino.Operations.Receive; /// /// Expects to be a scoped dependency per receive operation. /// -public class RhinoHostObjectBuilder : IHostObjectBuilder +public class RhinoHostObjectBuilder : HostObjectBuilder { private readonly IRootToHostConverter _converter; private readonly IConverterSettingsStore _converterSettings; @@ -55,7 +55,7 @@ ISdkActivityFactory activityFactory } #pragma warning disable CA1506 - public HostObjectBuilderResult Build( + protected override HostObjectBuilderResult Build( #pragma warning restore CA1506 Base rootObject, string projectName, diff --git a/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs b/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs index aa19cc90f..cea3c1fe8 100644 --- a/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs +++ b/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs @@ -4,6 +4,15 @@ namespace Speckle.Connectors.Common.Builders; +public abstract class HostObjectBuilder : IHostObjectBuilder +{ + Task IHostObjectBuilder.Build(Base rootObject, string projectName, string modelName, IProgress onOperationProgressed, + CancellationToken cancellationToken) => + Task.FromResult(Build(rootObject, projectName, modelName, onOperationProgressed)); + + protected abstract HostObjectBuilderResult Build(Base rootObject, string projectName, string modelName, + IProgress onOperationProgressed); +} // POC: We might consider to put also IRootObjectBuilder interface here in same folder and create concrete classes from it in per connector. public interface IHostObjectBuilder { diff --git a/Sdk/Speckle.Connectors.Common/Threading/Yield.cs b/Sdk/Speckle.Connectors.Common/Threading/Yield.cs index 70606a0bf..23cd77d03 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/Yield.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/Yield.cs @@ -1,3 +1,5 @@ +using System.Runtime.CompilerServices; + namespace Speckle.Connectors.Common.Threading; public static class Yield @@ -22,4 +24,9 @@ await Task.Factory.StartNew( await Task.Yield(); } } + + public static ConfiguredValueTaskAwaitable BackToThread(this ValueTask valueTask) => valueTask.ConfigureAwait(true); + public static ConfiguredValueTaskAwaitable BackToAny(this ValueTask valueTask) => valueTask.ConfigureAwait(false); + public static ConfiguredTaskAwaitable BackToThread(this Task task) => task.ConfigureAwait(true); + public static ConfiguredTaskAwaitable BackToAny(this Task task) => task.ConfigureAwait(false); } From 2971a5e61d3df623e15e5984bba06ae682457f8f Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Wed, 27 Nov 2024 14:23:58 +0000 Subject: [PATCH 23/65] Found APIContext and removed it --- .../Bindings/BasicConnectorBindingRevit.cs | 11 +- .../Bindings/RevitSendBinding.cs | 15 +- .../RevitConnectorModule.cs | 3 - .../HostApp/APIContext.cs | 130 ------------------ .../Send/Filters/IRevitSendFilter.cs | 5 +- .../Send/Filters/RevitCategoriesFilter.cs | 8 +- .../Send/Filters/RevitViewsFilter.cs | 8 +- .../Send/Settings/ToSpeckleSettingsManager.cs | 3 - .../Speckle.Connectors.RevitShared.projitems | 1 - 9 files changed, 12 insertions(+), 172 deletions(-) delete mode 100644 Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/APIContext.cs diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs index 14d6ee7dd..b72c3a5d1 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs @@ -2,7 +2,6 @@ using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; -using Speckle.Connectors.Revit.HostApp; using Speckle.Connectors.RevitShared; using Speckle.Connectors.RevitShared.Operations.Send.Filters; using Speckle.Converters.RevitShared.Helpers; @@ -19,13 +18,11 @@ internal sealed class BasicConnectorBindingRevit : IBasicConnectorBinding public BasicConnectorBindingCommands Commands { get; } - private readonly APIContext _apiContext; private readonly DocumentModelStore _store; private readonly RevitContext _revitContext; private readonly ISpeckleApplication _speckleApplication; public BasicConnectorBindingRevit( - APIContext apiContext, DocumentModelStore store, IBrowserBridge parent, RevitContext revitContext, @@ -34,7 +31,6 @@ ISpeckleApplication speckleApplication { Name = "baseBinding"; Parent = parent; - _apiContext = apiContext; _store = store; _revitContext = revitContext; _speckleApplication = speckleApplication; @@ -96,21 +92,16 @@ public async Task HighlightModel(string modelCardId) { if (senderModelCard.SendFilter is IRevitSendFilter revitFilter) { - revitFilter.SetContext(_revitContext, _apiContext); + revitFilter.SetContext(_revitContext); } if (senderModelCard.SendFilter is RevitViewsFilter revitViewsFilter) { - await _apiContext - .Run(() => - { var view = revitViewsFilter.GetView(); if (view is not null) { _revitContext.UIApplication.ActiveUIDocument.ActiveView = view; } - }) - .ConfigureAwait(false); return; } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs index d0974aa38..48cd80243 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs @@ -28,7 +28,6 @@ namespace Speckle.Connectors.Revit.Bindings; internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding { private readonly IAppIdleManager _idleManager; - private readonly APIContext _apiContext; private readonly CancellationManager _cancellationManager; private readonly IServiceProvider _serviceProvider; private readonly ISendConversionCache _sendConversionCache; @@ -50,7 +49,6 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding public RevitSendBinding( IAppIdleManager idleManager, RevitContext revitContext, - APIContext apiContext, DocumentModelStore store, CancellationManager cancellationManager, IBrowserBridge bridge, @@ -66,7 +64,6 @@ ISpeckleApplication speckleApplication : base("sendBinding", store, bridge, revitContext) { _idleManager = idleManager; - _apiContext = apiContext; _cancellationManager = cancellationManager; _serviceProvider = serviceProvider; _sendConversionCache = sendConversionCache; @@ -91,8 +88,8 @@ ISpeckleApplication speckleApplication public List GetSendFilters() => [ new RevitSelectionFilter() { IsDefault = true }, - new RevitViewsFilter(RevitContext, _apiContext), - new RevitCategoriesFilter(RevitContext, _apiContext) + new RevitViewsFilter(RevitContext), + new RevitCategoriesFilter(RevitContext) ]; public List GetSendSettings() => @@ -174,12 +171,10 @@ private async Task> RefreshElementsOnSender(SenderModelCard modelC if (modelCard.SendFilter is IRevitSendFilter viewFilter) { - viewFilter.SetContext(RevitContext, _apiContext); + viewFilter.SetContext(RevitContext); } - var selectedObjects = await _apiContext - .Run(_ => modelCard.SendFilter.NotNull().RefreshObjectIds()) - .ConfigureAwait(false); + var selectedObjects = modelCard.SendFilter.NotNull().RefreshObjectIds(); List elements = selectedObjects .Select(uid => activeUIDoc.Document.GetElement(uid)) @@ -384,7 +379,7 @@ private async Task RunExpirationChecks() { if (modelCard.SendFilter is IRevitSendFilter viewFilter) { - viewFilter.SetContext(RevitContext, _apiContext); + viewFilter.SetContext(RevitContext); } var selectedObjects = modelCard.SendFilter.NotNull().IdMap.NotNull().Values; diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs index 600cc674e..b719cc2d4 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs @@ -69,9 +69,6 @@ public static void AddRevit(this IServiceCollection serviceCollection) // operation progress manager serviceCollection.AddSingleton(); - - // API context helps us to run functions on Revit UI Thread (main) - serviceCollection.AddSingleton(); } public static void RegisterUiDependencies(IServiceCollection serviceCollection) diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/APIContext.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/APIContext.cs deleted file mode 100644 index 5260d0933..000000000 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/APIContext.cs +++ /dev/null @@ -1,130 +0,0 @@ -using Autodesk.Revit.UI; - -namespace Speckle.Connectors.Revit.HostApp; - -/// -/// This class gives access to the Revit API context from anywhere in your codebase. This is essentially a -/// lite version of the Revit.Async package from Kennan Chan. Most of the functionality was taken from that code. -/// The main difference is that this class does not subscribe to the applicationIdling event from revit -/// which the docs say will impact the performance of Revit -/// -public sealed class APIContext : IDisposable -{ - private readonly SemaphoreSlim _semaphore = new(1, 1); - private readonly UIControlledApplication _uiApplication; - private readonly ExternalEventHandler _factoryExternalEventHandler; -#pragma warning disable CA2213 - private readonly ExternalEvent _factoryExternalEvent; -#pragma warning restore CA2213 - - public APIContext(UIControlledApplication application) - { - _uiApplication = application; - _factoryExternalEventHandler = new(ExternalEvent.Create); - _factoryExternalEvent = ExternalEvent.Create(_factoryExternalEventHandler); - } - - public async Task Run(Func func) - { - await _semaphore.WaitAsync().ConfigureAwait(false); - try - { - var handler = new ExternalEventHandler(func); - using var externalEvent = await Run(_factoryExternalEventHandler, handler, _factoryExternalEvent) - .ConfigureAwait(false); - - return await Run(handler, _uiApplication, externalEvent).ConfigureAwait(false); - } - finally - { - _semaphore.Release(); - } - } - - public async Task Run(Action action) => - await Run(app => - { - action(app); - return null!; - }) - .ConfigureAwait(false); - - public async Task Run(Action action) => - await Run(_ => - { - action(); - return null!; - }) - .ConfigureAwait(false); - - private async Task Run( - ExternalEventHandler handler, - TParameter parameter, - ExternalEvent externalEvent - ) - { - var task = handler.GetTask(parameter); - externalEvent.Raise(); - - return await task.ConfigureAwait(false); - } - - public void Dispose() - { - _factoryExternalEvent.Dispose(); - _semaphore.Dispose(); - } -} - -public enum HandlerStatus -{ - NotStarted, - Started, - IsCompleted, - IsFaulted, -} - -internal sealed class ExternalEventHandler : IExternalEventHandler -{ - private TaskCompletionSource Result { get; set; } - - public Task GetTask(TParameter parameter) - { - Parameter = parameter; - Result = new TaskCompletionSource(); - return Result.Task; - } - - private readonly Func _func; - - public ExternalEventHandler(Func func) - { - this._func = func; - } - - public HandlerStatus Status { get; private set; } = HandlerStatus.NotStarted; - private TParameter Parameter { get; set; } - - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Design", - "CA1031:Do not catch general exception types", - Justification = "This is a very generic utility method for running things in a Revit context. If the result of the Run method is awaited, then the exception caught here will be raised there." - )] - public void Execute(UIApplication app) - { - Status = HandlerStatus.Started; - try - { - var r = _func(Parameter); - Result.SetResult(r); - Status = HandlerStatus.IsCompleted; - } - catch (Exception ex) - { - Status = HandlerStatus.IsFaulted; - Result.SetException(ex); - } - } - - public string GetName() => "SpeckleRevitContextEventHandler"; -} diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/Filters/IRevitSendFilter.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/Filters/IRevitSendFilter.cs index 8895b357b..fe576b8b3 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/Filters/IRevitSendFilter.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/Filters/IRevitSendFilter.cs @@ -1,9 +1,8 @@ -using Speckle.Connectors.Revit.HostApp; -using Speckle.Converters.RevitShared.Helpers; +using Speckle.Converters.RevitShared.Helpers; namespace Speckle.Connectors.RevitShared.Operations.Send.Filters; public interface IRevitSendFilter { - public void SetContext(RevitContext revitContext, APIContext apiContext); + public void SetContext(RevitContext revitContext); } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/Filters/RevitCategoriesFilter.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/Filters/RevitCategoriesFilter.cs index b1cd74db7..25e3d017c 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/Filters/RevitCategoriesFilter.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/Filters/RevitCategoriesFilter.cs @@ -2,7 +2,6 @@ using Speckle.Connectors.DUI.Exceptions; using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Connectors.DUI.Utils; -using Speckle.Connectors.Revit.HostApp; using Speckle.Converters.RevitShared.Helpers; namespace Speckle.Connectors.RevitShared.Operations.Send.Filters; @@ -12,7 +11,6 @@ public record CategoryData(string Name, string Id); public class RevitCategoriesFilter : DiscriminatedObject, ISendFilter, IRevitSendFilter { private RevitContext _revitContext; - private APIContext _apiContext; private Document? _doc; public string Id { get; set; } = "revitCategories"; public string Name { get; set; } = "Categories"; @@ -25,10 +23,9 @@ public class RevitCategoriesFilter : DiscriminatedObject, ISendFilter, IRevitSen public RevitCategoriesFilter() { } - public RevitCategoriesFilter(RevitContext revitContext, APIContext apiContext) + public RevitCategoriesFilter(RevitContext revitContext) { _revitContext = revitContext; - _apiContext = apiContext; _doc = _revitContext.UIApplication?.ActiveUIDocument.Document; GetCategories(); @@ -82,10 +79,9 @@ private void GetCategories() /// NOTE: this is needed since we need doc on `GetObjectIds()` function after it deserialized. /// DI doesn't help here to pass RevitContext from constructor. /// - public void SetContext(RevitContext revitContext, APIContext apiContext) + public void SetContext(RevitContext revitContext) { _revitContext = revitContext; - _apiContext = apiContext; _doc = _revitContext.UIApplication?.ActiveUIDocument.Document; } } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/Filters/RevitViewsFilter.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/Filters/RevitViewsFilter.cs index d98f46b80..d5ae8f0e9 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/Filters/RevitViewsFilter.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/Filters/RevitViewsFilter.cs @@ -2,7 +2,6 @@ using Speckle.Connectors.DUI.Exceptions; using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Connectors.DUI.Utils; -using Speckle.Connectors.Revit.HostApp; using Speckle.Converters.RevitShared.Helpers; namespace Speckle.Connectors.RevitShared.Operations.Send.Filters; @@ -10,7 +9,6 @@ namespace Speckle.Connectors.RevitShared.Operations.Send.Filters; public class RevitViewsFilter : DiscriminatedObject, ISendFilter, IRevitSendFilter { private RevitContext _revitContext; - private APIContext _apiContext; private Document? _doc; public string Id { get; set; } = "revitViews"; public string Name { get; set; } = "Views"; @@ -23,10 +21,9 @@ public class RevitViewsFilter : DiscriminatedObject, ISendFilter, IRevitSendFilt public RevitViewsFilter() { } - public RevitViewsFilter(RevitContext revitContext, APIContext apiContext) + public RevitViewsFilter(RevitContext revitContext) { _revitContext = revitContext; - _apiContext = apiContext; _doc = _revitContext.UIApplication?.ActiveUIDocument.Document; GetViews(); @@ -100,10 +97,9 @@ private void GetViews() /// NOTE: this is needed since we need doc on `GetObjectIds()` function after it deserialized. /// DI doesn't help here to pass RevitContext from constructor. /// - public void SetContext(RevitContext revitContext, APIContext apiContext) + public void SetContext(RevitContext revitContext) { _revitContext = revitContext; - _apiContext = apiContext; _doc = _revitContext.UIApplication?.ActiveUIDocument.Document; } } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/Settings/ToSpeckleSettingsManager.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/Settings/ToSpeckleSettingsManager.cs index 96ce3fde7..f1e55df9b 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/Settings/ToSpeckleSettingsManager.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/Settings/ToSpeckleSettingsManager.cs @@ -14,7 +14,6 @@ namespace Speckle.Connectors.Revit.Operations.Send.Settings; public class ToSpeckleSettingsManager : IToSpeckleSettingsManager { private readonly RevitContext _revitContext; - private readonly APIContext _apiContext; private readonly ISendConversionCache _sendConversionCache; private readonly ElementUnpacker _elementUnpacker; @@ -25,13 +24,11 @@ public class ToSpeckleSettingsManager : IToSpeckleSettingsManager public ToSpeckleSettingsManager( RevitContext revitContext, - APIContext apiContext, ISendConversionCache sendConversionCache, ElementUnpacker elementUnpacker ) { _revitContext = revitContext; - _apiContext = apiContext; _elementUnpacker = elementUnpacker; _sendConversionCache = sendConversionCache; } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Speckle.Connectors.RevitShared.projitems b/Connectors/Revit/Speckle.Connectors.RevitShared/Speckle.Connectors.RevitShared.projitems index 0811cbe7b..cc39c34ae 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Speckle.Connectors.RevitShared.projitems +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Speckle.Connectors.RevitShared.projitems @@ -19,7 +19,6 @@ - From 05eba2502c844d2f3fc11da4496ba6ef476c8322 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Wed, 27 Nov 2024 15:39:34 +0000 Subject: [PATCH 24/65] ArcGIS runs all workers on MCT thread --- .../Bindings/ArcGISSendBinding.cs | 13 +-- .../Bindings/BasicConnectorBinding.cs | 30 +++-- .../ArcGISConnectorModule.cs | 3 +- .../Receive/ArcGISHostObjectBuilder.cs | 53 +++------ .../Send/ArcGISRootObjectBuilder.cs | 12 +- .../Utils/ArcGISThreadContext.cs | 108 ++++++++++++++++++ .../Utils/ArcGisDocumentStore.cs | 17 ++- .../ArcGISConversionSettingsFactory.cs | 7 +- .../Utils/FeatureClassUtils.cs | 6 +- .../Bridge/BrowserBridge.cs | 9 +- .../Threading/ThreadContext.cs | 8 +- .../Threading/ThreadOptions.cs | 1 + .../Threading/Yield.cs | 2 + 13 files changed, 169 insertions(+), 100 deletions(-) create mode 100644 Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs index 1b3dcb613..95404059d 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs @@ -3,7 +3,6 @@ using ArcGIS.Core.Data; using ArcGIS.Desktop.Core; using ArcGIS.Desktop.Editing.Events; -using ArcGIS.Desktop.Framework.Threading.Tasks; using ArcGIS.Desktop.Mapping; using ArcGIS.Desktop.Mapping.Events; using Microsoft.Extensions.DependencyInjection; @@ -139,8 +138,6 @@ private void SubscribeToArcGISEvents() private void SubscribeToMapMembersDataSourceChange() { - var task = QueuedTask.Run(() => - { if (MapView.Active == null) { return; @@ -159,8 +156,6 @@ private void SubscribeToMapMembersDataSourceChange() { SubscribeToTableDataSourceChange(table); } - }); - task.Wait(); } private void SubscribeToFeatureLayerDataSourceChange(FeatureLayer layer) @@ -366,9 +361,6 @@ public async Task Send(string modelCardId) CancellationToken cancellationToken = _cancellationManager.InitCancellationTokenSource(modelCardId); - var sendResult = await QueuedTask - .Run(async () => - { using var scope = _serviceProvider.CreateScope(); scope .ServiceProvider.GetRequiredService>() @@ -407,7 +399,7 @@ public async Task Send(string modelCardId) } } - var result = await scope + var sendResult = await scope .ServiceProvider.GetRequiredService>() .Execute( mapMembers, @@ -417,9 +409,6 @@ public async Task Send(string modelCardId) ) .ConfigureAwait(false); - return result; - }) - .ConfigureAwait(false); await Commands .SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs index 13e0d315c..ec71b65fd 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs @@ -1,5 +1,4 @@ using ArcGIS.Core.Data; -using ArcGIS.Desktop.Framework.Threading.Tasks; using ArcGIS.Desktop.Mapping; using Speckle.Connectors.ArcGIS.Utils; using Speckle.Connectors.DUI.Bindings; @@ -60,16 +59,19 @@ public BasicConnectorBinding(DocumentModelStore store, IBrowserBridge parent, IS public void RemoveModel(ModelCard model) => _store.RemoveModel(model); - public async Task HighlightObjects(IReadOnlyList objectIds) => - await HighlightObjectsOnView(objectIds.Select(x => new ObjectID(x)).ToList()).ConfigureAwait(false); + public Task HighlightObjects(IReadOnlyList objectIds) + { + HighlightObjectsOnView(objectIds.Select(x => new ObjectID(x)).ToList()); + return Task.CompletedTask; + } - public async Task HighlightModel(string modelCardId) + public Task HighlightModel(string modelCardId) { var model = _store.GetModelById(modelCardId); if (model is null) { - return; + return Task.CompletedTask; } var objectIds = new List(); @@ -86,26 +88,22 @@ public async Task HighlightModel(string modelCardId) if (objectIds is null) { - return; + return Task.CompletedTask; } - await HighlightObjectsOnView(objectIds).ConfigureAwait(false); + HighlightObjectsOnView(objectIds); + return Task.CompletedTask; } - private async Task HighlightObjectsOnView(IReadOnlyList objectIds) + private void HighlightObjectsOnView(IReadOnlyList objectIds) { MapView mapView = MapView.Active; - await QueuedTask - .Run(async () => - { List mapMembersFeatures = GetMapMembers(objectIds, mapView); ClearSelectionInTOC(); ClearSelection(); - await SelectMapMembersInTOC(mapMembersFeatures).ConfigureAwait(false); + SelectMapMembersInTOC(mapMembersFeatures); SelectMapMembersAndFeatures(mapMembersFeatures); mapView.ZoomToSelected(); - }) - .ConfigureAwait(false); } private List GetMapMembers(IReadOnlyList objectIds, MapView mapView) @@ -171,7 +169,7 @@ private void SelectMapMembersAndFeatures(IReadOnlyList mapMemb } } - private async Task SelectMapMembersInTOC(IReadOnlyList mapMembersFeatures) + private void SelectMapMembersInTOC(IReadOnlyList mapMembersFeatures) { List layers = new(); List tables = new(); @@ -187,7 +185,7 @@ private async Task SelectMapMembersInTOC(IReadOnlyList mapMemb } else { - await QueuedTask.Run(() => layer.SetExpanded(true)).ConfigureAwait(false); + layer.SetExpanded(true); } } else if (member is StandaloneTable table) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs index 3dd514777..1908a7372 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs @@ -10,7 +10,6 @@ using Speckle.Connectors.Common.Builders; using Speckle.Connectors.Common.Caching; using Speckle.Connectors.Common.Operations; -using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Models.Card.SendFilter; @@ -28,7 +27,7 @@ public static class ArcGISConnectorModule public static void AddArcGIS(this IServiceCollection serviceCollection) { serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); serviceCollection.AddDUIView(); // Register bindings serviceCollection.AddSingleton(); diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/ArcGISHostObjectBuilder.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/ArcGISHostObjectBuilder.cs index 2b98a8300..d0fb515cb 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/ArcGISHostObjectBuilder.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/ArcGISHostObjectBuilder.cs @@ -1,7 +1,6 @@ using System.Diagnostics.Contracts; using ArcGIS.Core.CIM; using ArcGIS.Core.Geometry; -using ArcGIS.Desktop.Framework.Threading.Tasks; using ArcGIS.Desktop.Mapping; using Speckle.Connectors.ArcGIS.HostApp; using Speckle.Connectors.ArcGIS.Utils; @@ -9,6 +8,7 @@ using Speckle.Connectors.Common.Conversion; using Speckle.Connectors.Common.Instances; using Speckle.Connectors.Common.Operations; +using Speckle.Connectors.Common.Threading; using Speckle.Converters.ArcGIS3; using Speckle.Converters.ArcGIS3.Utils; using Speckle.Converters.Common; @@ -78,14 +78,14 @@ CancellationToken cancellationToken .ToList(); if (materials != null) { - await _colorManager.ParseMaterials(materials, onOperationProgressed).ConfigureAwait(false); + await _colorManager.ParseMaterials(materials, onOperationProgressed).BackToThread(); } // get colors List? colors = (rootObject[ProxyKeys.COLOR] as List)?.Cast().ToList(); if (colors != null) { - await _colorManager.ParseColors(colors, onOperationProgressed).ConfigureAwait(false); + await _colorManager.ParseColors(colors, onOperationProgressed).BackToThread(); } int count = 0; @@ -107,7 +107,7 @@ CancellationToken cancellationToken object? conversionResult = obj is GisNonGeometricFeature ? null - : await QueuedTask.Run(() => _converter.Convert(obj)).ConfigureAwait(false); + : _converter.Convert(obj); string nestedLayerPath = $"{string.Join("\\", path)}"; if (objectToConvert.TraversalContext.Parent?.Current is not VectorLayer) @@ -130,29 +130,20 @@ obj is GisNonGeometricFeature // 2.1. Group conversionTrackers (to write into datasets) onOperationProgressed.Report(new("Grouping features into layers", null)); - Dictionary> convertedGroups = await QueuedTask - .Run(async () => - { - return await _featureClassUtils - .GroupConversionTrackers(conversionTracker, (s, progres) => onOperationProgressed.Report(new(s, progres))) - .ConfigureAwait(false); - }) - .ConfigureAwait(false); + Dictionary> convertedGroups = + _featureClassUtils + .GroupConversionTrackers(conversionTracker, (s, progres) => onOperationProgressed.Report(new(s, progres))); + // 2.2. Write groups of objects to Datasets onOperationProgressed.Report(new("Writing to Database", null)); - await QueuedTask - .Run(async () => - { - await _featureClassUtils - .CreateDatasets( - conversionTracker, - convertedGroups, - (s, progres) => onOperationProgressed.Report(new(s, progres)) - ) - .ConfigureAwait(false); - }) - .ConfigureAwait(false); + + _featureClassUtils + .CreateDatasets( + conversionTracker, + convertedGroups, + (s, progres) => onOperationProgressed.Report(new(s, progres)) + ); // 3. add layer and tables to the Map and Table Of Content @@ -204,8 +195,7 @@ await _featureClassUtils else { // no layer yet, create and add layer to Map - MapMember mapMember = await AddDatasetsToMap(trackerItem, createdLayerGroups, projectName, modelName) - .ConfigureAwait(false); + MapMember mapMember = AddDatasetsToMap(trackerItem, createdLayerGroups, projectName, modelName); // add layer and layer URI to tracker trackerItem.AddConvertedMapMember(mapMember); @@ -233,7 +223,7 @@ await _featureClassUtils if (bakedMember.Value.Item1 is FeatureLayer fLayer) { // Set the feature layer's renderer. - await QueuedTask.Run(() => fLayer.SetRenderer(bakedMember.Value.Item2)).ConfigureAwait(false); + fLayer.SetRenderer(bakedMember.Value.Item2); } } bakedObjectIds.AddRange(createdLayerGroups.Values.Select(x => x.URI)); @@ -304,16 +294,13 @@ private void AddResultsFromTracker(ObjectConversionTracker trackerItem, List AddDatasetsToMap( + private MapMember AddDatasetsToMap( ObjectConversionTracker trackerItem, Dictionary createdLayerGroups, string projectName, string modelName ) { - return await QueuedTask - .Run(() => - { // get layer details string? datasetId = trackerItem.DatasetId; // should not be null here Uri uri = new($"{_settingsStore.Current.SpeckleDatabasePath.AbsolutePath.Replace('/', '\\')}\\{datasetId}"); @@ -365,7 +352,7 @@ string modelName } } - return (MapMember)layer; + return layer; } catch (ArgumentException) { @@ -376,8 +363,6 @@ string modelName ); return table; } - }) - .ConfigureAwait(false); } private GroupLayer CreateNestedGroupLayer(string nestedLayerPath, Dictionary createdLayerGroups) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs index 08f3e2d0e..b0c3456d1 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs @@ -1,5 +1,4 @@ using System.Diagnostics; -using ArcGIS.Desktop.Framework.Threading.Tasks; using ArcGIS.Desktop.Mapping; using Microsoft.Extensions.Logging; using Speckle.Connectors.ArcGIS.HostApp; @@ -53,12 +52,11 @@ ISdkActivityFactory activityFactory } #pragma warning disable CA1506 - public async Task Build( + public RootObjectBuilderResult Build( #pragma warning restore CA1506 IReadOnlyList objects, SendInfo sendInfo, - IProgress onOperationProgressed, - CancellationToken ct = default + IProgress onOperationProgressed ) { // TODO: add a warning if Geographic CRS is set @@ -84,8 +82,6 @@ public async Task Build( { foreach ((MapMember mapMember, _) in layersWithDisplayPriority) { - ct.ThrowIfCancellationRequested(); - using (var convertingActivity = _activityFactory.Start("Converting object")) { var collectionHost = rootObjectCollection; @@ -130,9 +126,7 @@ mapMember is not ILayerContainer } else { - converted = await QueuedTask - .Run(() => (Collection)_rootToSpeckleConverter.Convert(mapMember)) - .ConfigureAwait(false); + converted = (Collection)_rootToSpeckleConverter.Convert(mapMember); // get units & Active CRS (for writing geometry coords) converted["units"] = _converterSettings.Current.SpeckleUnits; diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs new file mode 100644 index 000000000..02bccb50f --- /dev/null +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs @@ -0,0 +1,108 @@ +using ArcGIS.Desktop.Framework.Threading.Tasks; +using Speckle.Connectors.Common.Threading; + +namespace Speckle.Connectors.ArcGIS.Utils; + +public class ArcGISThreadContext : ThreadContext +{ + public override void RunOnThread(Action action, bool useMain) + { + if (useMain) + { + if (IsMainThread) + { + base.RunOnThread(action, useMain); + } + else { + QueuedTask.Run(action); + } + } + else + { + if (IsMainThread) + { + QueuedTask.Run(action); + } + else { + base.RunOnThread(action, useMain); + } + } + } + + public override async Task RunOnThread(Func action, bool useMain) + { + if (useMain) + {if (IsMainThread) + { + return await base.RunOnThread(action, useMain).BackToThread(); + } + else + { + return await QueuedTask.Run(action).BackToThread(); + } + } + else + { + if (IsMainThread) + { + return await QueuedTask.Run(action).BackToThread(); + } + else { + return await base.RunOnThread(action, useMain).BackToThread(); + } + } + } + + public override async Task RunOnThreadAsync(Func action, bool useMain) + { + if (useMain) + { + if (IsMainThread) + { + await base.RunOnThreadAsync(action, useMain).BackToThread(); + } + else + { + await QueuedTask.Run(action).BackToThread(); + } + } + else + { + if (IsMainThread) + { + await QueuedTask.Run(action).BackToThread(); + } + else + { + await base.RunOnThreadAsync(action, useMain).BackToThread(); + } + } + } + + public override async Task RunOnThreadAsync(Func> action, bool useMain) + + { + if (useMain) + { + if (IsMainThread) + { + return await base.RunOnThreadAsync(action, useMain).BackToThread(); + } + else + { + return await QueuedTask.Run(action).BackToThread(); + } + } + else + { + if (IsMainThread) + { + return await QueuedTask.Run(action).BackToThread(); + } + else + { + return await base.RunOnThreadAsync(action, useMain).BackToThread(); + } + } + } +} diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs index 78be6af1d..9638d715c 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs @@ -1,8 +1,8 @@ using System.Xml.Linq; using ArcGIS.Desktop.Core.Events; -using ArcGIS.Desktop.Framework.Threading.Tasks; using ArcGIS.Desktop.Mapping; using ArcGIS.Desktop.Mapping.Events; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Utils; @@ -11,9 +11,11 @@ namespace Speckle.Connectors.ArcGIS.Utils; public class ArcGISDocumentStore : DocumentModelStore { - public ArcGISDocumentStore(IJsonSerializer jsonSerializer, ITopLevelExceptionHandler topLevelExceptionHandler) + private readonly IThreadContext _threadContext; + public ArcGISDocumentStore(IJsonSerializer jsonSerializer, ITopLevelExceptionHandler topLevelExceptionHandler, IThreadContext threadContext) : base(jsonSerializer) { + _threadContext = threadContext; ActiveMapViewChangedEvent.Subscribe(a => topLevelExceptionHandler.CatchUnhandled(() => OnMapViewChanged(a)), true); ProjectSavingEvent.Subscribe( _ => @@ -77,8 +79,6 @@ private void OnMapViewChanged(ActiveMapViewChangedEventArgs args) protected override void HostAppSaveState(string modelCardState) { Map map = MapView.Active.Map; - QueuedTask.Run(() => - { // Read existing metadata - To prevent messing existing metadata. 🤞 Hope other add-in developers will do same :D var existingMetadata = map.GetMetadata(); @@ -101,14 +101,12 @@ protected override void HostAppSaveState(string modelCardState) } map.SetMetadata(existingXmlDocument.ToString()); - }); } - protected override void LoadState() - { - Map map = MapView.Active.Map; - QueuedTask.Run(() => + protected override void LoadState() => + _threadContext.RunOnWorker(() => { + Map map = MapView.Active.Map; var metadata = map.GetMetadata(); var root = XDocument.Parse(metadata).Root; var element = root?.Element("SpeckleModelCards"); @@ -121,5 +119,4 @@ protected override void LoadState() string modelsString = element.Value; LoadFromString(modelsString); }); - } } diff --git a/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionSettingsFactory.cs b/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionSettingsFactory.cs index 5ae9ae250..f3c0e2fc4 100644 --- a/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionSettingsFactory.cs +++ b/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionSettingsFactory.cs @@ -1,7 +1,6 @@ using ArcGIS.Core.Data; using ArcGIS.Core.Data.DDL; using ArcGIS.Desktop.Core; -using ArcGIS.Desktop.Framework.Threading.Tasks; using ArcGIS.Desktop.Mapping; using Speckle.Converters.ArcGIS3.Utils; using Speckle.Converters.Common; @@ -137,8 +136,7 @@ public Uri AddDatabaseToProject(Uri databasePath) var parentFolder = Path.GetDirectoryName(databasePath.AbsolutePath); var fGdbName = databasePath.Segments[^1]; Item folderToAdd = ItemFactory.Instance.Create(parentFolder); - // POC: QueuedTask - QueuedTask.Run(() => Project.Current.AddItem(folderToAdd as IProjectItem)); + Project.Current.AddItem(folderToAdd as IProjectItem); // Add a file geodatabase or a SQLite or enterprise database connection to a project try @@ -149,8 +147,7 @@ public Uri AddDatabaseToProject(Uri databasePath) if (gdbToAdd is not null) { - // POC: QueuedTask - var addedGeodatabase = QueuedTask.Run(() => Project.Current.AddItem(gdbToAdd as IProjectItem)); + var addedGeodatabase = Project.Current.AddItem(gdbToAdd as IProjectItem); } } catch (NullReferenceException ex) diff --git a/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/FeatureClassUtils.cs b/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/FeatureClassUtils.cs index 0cd9690f1..0795d4550 100644 --- a/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/FeatureClassUtils.cs +++ b/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/FeatureClassUtils.cs @@ -73,7 +73,7 @@ private Geodatabase GetDatabase() return geodatabase; } - public async Task>> GroupConversionTrackers( + public Dictionary> GroupConversionTrackers( Dictionary conversionTracker, Action onOperationProgressed ) @@ -132,13 +132,12 @@ private Geodatabase GetDatabase() ClearExistingDataset(uniqueKey); onOperationProgressed.Invoke("Grouping features into layers", count++ / conversionTracker.Count); - await Task.Yield(); } return geometryGroups; } - public async Task CreateDatasets( + public void CreateDatasets( Dictionary conversionTracker, Dictionary> featureClassElements, Action onOperationProgressed @@ -201,7 +200,6 @@ public async Task CreateDatasets( } onOperationProgressed.Invoke("Writing to Database", count++ / featureClassElements.Count); - await Task.Yield(); } } diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index f951a9642..195ae18c4 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -29,6 +29,7 @@ public sealed class BrowserBridge : IBrowserBridge private readonly ConcurrentDictionary _resultsStore = new(); public ITopLevelExceptionHandler TopLevelExceptionHandler { get; } private readonly IThreadContext _threadContext; + private readonly IThreadOptions _threadOptions; private readonly IBrowserScriptExecutor _browserScriptExecutor; private readonly IJsonSerializer _jsonSerializer; @@ -60,8 +61,7 @@ public BrowserBridge( IJsonSerializer jsonSerializer, ILogger logger, ILogger topLogger, - IBrowserScriptExecutor browserScriptExecutor - ) + IBrowserScriptExecutor browserScriptExecutor, IThreadOptions threadOptions) { _threadContext = threadContext; _jsonSerializer = jsonSerializer; @@ -69,6 +69,7 @@ IBrowserScriptExecutor browserScriptExecutor TopLevelExceptionHandler = new TopLevelExceptionHandler(topLogger, this); // Capture the main thread's SynchronizationContext _browserScriptExecutor = browserScriptExecutor; + _threadOptions = threadOptions; } public void AssociateWithBinding(IBinding binding) @@ -102,7 +103,7 @@ public string[] GetBindingsMethodNames() } public void RunMethod(string methodName, string requestId, string methodArgs) => - _threadContext.RunOnMainAsync(async () => + _threadContext.RunOnThreadAsync(async () => { var task = await TopLevelExceptionHandler .CatchUnhandledAsync(async () => @@ -117,7 +118,7 @@ public void RunMethod(string methodName, string requestId, string methodArgs) => string resultJson = SerializeFormattedException(task.Exception); await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); } - }); + }, _threadOptions.RunCommandsOnMainThread); /// /// Used by the action block to invoke the actual method called by the UI. diff --git a/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs b/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs index 441fb91df..51bea970a 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs @@ -28,7 +28,7 @@ public ThreadContext() protected virtual Task RunContext(Func> action) => action(); - public void RunOnThread(Action action, bool useMain) + public virtual void RunOnThread(Action action, bool useMain) { if (useMain) { @@ -63,7 +63,7 @@ public void RunOnThread(Action action, bool useMain) } [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] - public Task RunOnThread(Func action, bool useMain) + public virtual Task RunOnThread(Func action, bool useMain) { if (useMain) { @@ -98,7 +98,7 @@ public Task RunOnThread(Func action, bool useMain) return RunContext(action.Invoke); } - public async Task RunOnThreadAsync(Func action, bool useMain) + public virtual async Task RunOnThreadAsync(Func action, bool useMain) { if (useMain) { @@ -135,7 +135,7 @@ await Task } [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] - public Task RunOnThreadAsync(Func> action, bool useMain) + public virtual Task RunOnThreadAsync(Func> action, bool useMain) { if (useMain) { diff --git a/Sdk/Speckle.Connectors.Common/Threading/ThreadOptions.cs b/Sdk/Speckle.Connectors.Common/Threading/ThreadOptions.cs index 38ead87e7..3ef94b7f2 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/ThreadOptions.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/ThreadOptions.cs @@ -8,4 +8,5 @@ namespace Speckle.Connectors.Common.Threading; public class ThreadOptions(ISpeckleApplication speckleApplication) : IThreadOptions { public bool RunReceiveBuildOnMainThread => speckleApplication.HostApplication != HostApplications.Rhino.Name; + public bool RunCommandsOnMainThread => speckleApplication.HostApplication != HostApplications.ArcGIS.Name; } diff --git a/Sdk/Speckle.Connectors.Common/Threading/Yield.cs b/Sdk/Speckle.Connectors.Common/Threading/Yield.cs index 23cd77d03..bfebf3b24 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/Yield.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/Yield.cs @@ -29,4 +29,6 @@ await Task.Factory.StartNew( public static ConfiguredValueTaskAwaitable BackToAny(this ValueTask valueTask) => valueTask.ConfigureAwait(false); public static ConfiguredTaskAwaitable BackToThread(this Task task) => task.ConfigureAwait(true); public static ConfiguredTaskAwaitable BackToAny(this Task task) => task.ConfigureAwait(false); + public static ConfiguredTaskAwaitable BackToThread(this Task task) => task.ConfigureAwait(true); + public static ConfiguredTaskAwaitable BackToAny(this Task task) => task.ConfigureAwait(false); } From b59b37d8048e019b861d1be8206bdf9949c27051 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 28 Nov 2024 09:05:34 +0000 Subject: [PATCH 25/65] Refactor ThreadContext and ArcGIS saving is always on a worker --- .../Utils/ArcGISThreadContext.cs | 101 +-------------- .../Utils/ArcGisDocumentStore.cs | 9 +- .../DependencyInjection/SharedRegistration.cs | 2 +- .../Plugin/RevitThreadContext.cs | 2 +- .../Registration/ServiceRegistration.cs | 2 +- .../Threading/DefaultThreadContext.cs | 66 ++++++++++ .../Threading/ThreadContext.cs | 119 +++++++----------- 7 files changed, 121 insertions(+), 180 deletions(-) create mode 100644 Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs index 02bccb50f..7ae0eb6a8 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs @@ -5,104 +5,11 @@ namespace Speckle.Connectors.ArcGIS.Utils; public class ArcGISThreadContext : ThreadContext { - public override void RunOnThread(Action action, bool useMain) - { - if (useMain) - { - if (IsMainThread) - { - base.RunOnThread(action, useMain); - } - else { - QueuedTask.Run(action); - } - } - else - { - if (IsMainThread) - { - QueuedTask.Run(action); - } - else { - base.RunOnThread(action, useMain); - } - } - } + protected override Task MainToWorkerAsync(Func> action) => QueuedTask.Run(action); - public override async Task RunOnThread(Func action, bool useMain) - { - if (useMain) - {if (IsMainThread) - { - return await base.RunOnThread(action, useMain).BackToThread(); - } - else - { - return await QueuedTask.Run(action).BackToThread(); - } - } - else - { - if (IsMainThread) - { - return await QueuedTask.Run(action).BackToThread(); - } - else { - return await base.RunOnThread(action, useMain).BackToThread(); - } - } - } + protected override Task WorkerToMainAsync(Func> action) => QueuedTask.Run(action); - public override async Task RunOnThreadAsync(Func action, bool useMain) - { - if (useMain) - { - if (IsMainThread) - { - await base.RunOnThreadAsync(action, useMain).BackToThread(); - } - else - { - await QueuedTask.Run(action).BackToThread(); - } - } - else - { - if (IsMainThread) - { - await QueuedTask.Run(action).BackToThread(); - } - else - { - await base.RunOnThreadAsync(action, useMain).BackToThread(); - } - } - } + protected override Task MainToWorker(Func action) => QueuedTask.Run(action); - public override async Task RunOnThreadAsync(Func> action, bool useMain) - - { - if (useMain) - { - if (IsMainThread) - { - return await base.RunOnThreadAsync(action, useMain).BackToThread(); - } - else - { - return await QueuedTask.Run(action).BackToThread(); - } - } - else - { - if (IsMainThread) - { - return await QueuedTask.Run(action).BackToThread(); - } - else - { - return await base.RunOnThreadAsync(action, useMain).BackToThread(); - } - } - } + protected override Task WorkerToMain(Func action) => QueuedTask.Run(action); } diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs index 9638d715c..952b7f836 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs @@ -76,9 +76,10 @@ private void OnMapViewChanged(ActiveMapViewChangedEventArgs args) OnDocumentChanged(); } - protected override void HostAppSaveState(string modelCardState) - { - Map map = MapView.Active.Map; + protected override void HostAppSaveState(string modelCardState) => + _threadContext.RunOnWorker(() => + { + Map map = MapView.Active.Map; // Read existing metadata - To prevent messing existing metadata. 🤞 Hope other add-in developers will do same :D var existingMetadata = map.GetMetadata(); @@ -101,7 +102,7 @@ protected override void HostAppSaveState(string modelCardState) } map.SetMetadata(existingXmlDocument.ToString()); - } + }); protected override void LoadState() => _threadContext.RunOnWorker(() => diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs index 9632b802b..f264e63d2 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs @@ -25,7 +25,7 @@ public static class SharedRegistration public static void AddAutocadBase(this IServiceCollection serviceCollection) { serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); serviceCollection.AddDUIView(); // Register other connector specific types diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs index 59eb5c58d..5100ba300 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs @@ -3,7 +3,7 @@ namespace Speckle.Connectors.Revit.Plugin; -public class RevitThreadContext : ThreadContext +public class RevitThreadContext : DefaultThreadContext { protected override Task RunContext(Func action) => RevitTask.RunAsync(action); diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs index a461cf8b4..a5ad1c12d 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs @@ -33,7 +33,7 @@ public static void AddRhino(this IServiceCollection serviceCollection) serviceCollection.AddSingleton(SpeckleConnectorsRhinoCommand.Instance); serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); serviceCollection.AddDUIView(); // Register other connector specific types diff --git a/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs b/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs new file mode 100644 index 000000000..3fb0e7c3e --- /dev/null +++ b/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs @@ -0,0 +1,66 @@ +using System.Diagnostics.CodeAnalysis; +using Speckle.Sdk.Common; + +namespace Speckle.Connectors.Common.Threading; + +public class DefaultThreadContext : ThreadContext +{ + private readonly SynchronizationContext _threadContext = SynchronizationContext.Current.NotNull("No UI thread to capture?"); + + [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] + protected override Task WorkerToMainAsync(Func> action) + { + + TaskCompletionSource tcs = new(); + _threadContext.Post( + async _ => + { + try + { + T result = await RunContext(action).ConfigureAwait(false); + tcs.SetResult(result); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }, + null + ); + return tcs.Task; + } + + protected override Task MainToWorkerAsync(Func> action) + { + Task> f = Task.Factory.StartNew(action, default, TaskCreationOptions.LongRunning, TaskScheduler.Default); + return f.Unwrap(); + } + + [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] + protected override Task WorkerToMain(Func action) + { + TaskCompletionSource tcs = new(); + _threadContext.Post( + async _ => + { + try + { + T result = await RunContext(action).ConfigureAwait(false); + tcs.SetResult(result); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }, + null + ); + return tcs.Task; + } + + protected override Task MainToWorker(Func action) + { + Task f = Task.Factory.StartNew(action, default, TaskCreationOptions.LongRunning, TaskScheduler.Default); + return f; + } +} diff --git a/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs b/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs index 51bea970a..c242fd070 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs @@ -1,24 +1,13 @@ -using System.Diagnostics.CodeAnalysis; using Speckle.InterfaceGenerator; -using Speckle.Sdk.Common; namespace Speckle.Connectors.Common.Threading; [GenerateAutoInterface] -public class ThreadContext : IThreadContext +public abstract class ThreadContext : IThreadContext { - private readonly SynchronizationContext _threadContext; + private static readonly Task s_completedTask = Task.FromResult(null); - // Do this when you start your application - private static int s_mainThreadId; - - public ThreadContext() - { - _threadContext = SynchronizationContext.Current.NotNull("No UI thread to capture?"); - s_mainThreadId = Environment.CurrentManagedThreadId; - } - - public static bool IsMainThread => Environment.CurrentManagedThreadId == s_mainThreadId; + public static bool IsMainThread => Environment.CurrentManagedThreadId == 1 && !Thread.CurrentThread.IsBackground; protected virtual void RunContext(Action action) => action(); @@ -28,7 +17,7 @@ public ThreadContext() protected virtual Task RunContext(Func> action) => action(); - public virtual void RunOnThread(Action action, bool useMain) + public async Task RunOnThread(Action action, bool useMain) { if (useMain) { @@ -38,22 +27,25 @@ public virtual void RunOnThread(Action action, bool useMain) } else { - _threadContext.Post( - _ => - { - RunContext(action); - }, - null - ); + await WorkerToMainAsync( + () => + { + RunContext(action); + return s_completedTask; + } + ) + .ConfigureAwait(false); } } else { if (IsMainThread) { - Task.Factory.StartNew(action, default, TaskCreationOptions.LongRunning, TaskScheduler.Default) - .GetAwaiter() - .GetResult(); + await MainToWorkerAsync(() => + { + action(); + return s_completedTask; + }).BackToAny(); } else { @@ -62,59 +54,41 @@ public virtual void RunOnThread(Action action, bool useMain) } } - [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] public virtual Task RunOnThread(Func action, bool useMain) { if (useMain) { if (IsMainThread) { - return RunContext(action.Invoke); + return RunContext(action); } - TaskCompletionSource tcs = new(); - _threadContext.Post( - async _ => - { - try - { - T result = await RunContext(action).ConfigureAwait(false); - tcs.SetResult(result); - } - catch (Exception ex) - { - tcs.SetException(ex); - } - }, - null - ); - return tcs.Task; + + return WorkerToMain(action); } if (IsMainThread) { - Task f = Task.Factory.StartNew(action, default, TaskCreationOptions.LongRunning, TaskScheduler.Default); - return f; + return MainToWorker(action); } - return RunContext(action.Invoke); + return RunContext(action); } - public virtual async Task RunOnThreadAsync(Func action, bool useMain) + public async Task RunOnThreadAsync(Func action, bool useMain) { if (useMain) { if (IsMainThread) { - await action.Invoke().ConfigureAwait(false); + await RunContext(action).ConfigureAwait(false); } else { - await RunOnThreadAsync( + await WorkerToMainAsync( async () => { await RunContext(action.Invoke).ConfigureAwait(false); return null; - }, - useMain + } ) .ConfigureAwait(false); } @@ -123,9 +97,11 @@ public virtual async Task RunOnThreadAsync(Func action, bool useMain) { if (IsMainThread) { - await Task - .Factory.StartNew(action, default, TaskCreationOptions.LongRunning, TaskScheduler.Default) - .ConfigureAwait(false); + await MainToWorkerAsync(async () => + { + await action().BackToAny(); + return null; + }).BackToAny(); } else { @@ -134,8 +110,7 @@ await Task } } - [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] - public virtual Task RunOnThreadAsync(Func> action, bool useMain) + public Task RunOnThreadAsync(Func> action, bool useMain) { if (useMain) { @@ -143,29 +118,21 @@ public virtual Task RunOnThreadAsync(Func> action, bool useMain) { return RunContext(action.Invoke); } - TaskCompletionSource tcs = new(); - _threadContext.Post( - async _ => - { - try - { - T result = await RunContext(action).ConfigureAwait(false); - tcs.SetResult(result); - } - catch (Exception ex) - { - tcs.SetException(ex); - } - }, - null - ); - return tcs.Task; + + return WorkerToMainAsync(action); } if (IsMainThread) { - Task> f = Task.Factory.StartNew(action, default, TaskCreationOptions.LongRunning, TaskScheduler.Default); - return f.Unwrap(); + return MainToWorkerAsync(action); } return RunContext(action.Invoke); } + + protected abstract Task WorkerToMainAsync(Func> action); + + protected abstract Task MainToWorkerAsync(Func> action); + protected abstract Task WorkerToMain(Func action); + + protected abstract Task MainToWorker(Func action); } + From d826a3e9a8f62f31b2adb295aa4138e65c0d6913 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 28 Nov 2024 09:33:23 +0000 Subject: [PATCH 26/65] Revit threading is simplier? --- .../Plugin/RevitThreadContext.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs index 5100ba300..c1bada778 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs @@ -3,13 +3,13 @@ namespace Speckle.Connectors.Revit.Plugin; -public class RevitThreadContext : DefaultThreadContext +public class RevitThreadContext : ThreadContext { - protected override Task RunContext(Func action) => RevitTask.RunAsync(action); + protected override Task MainToWorkerAsync(Func> action) => action(); - protected override Task RunContext(Func action) => RevitTask.RunAsync(action); + protected override Task WorkerToMainAsync(Func> action) => RevitTask.RunAsync(action); - protected override void RunContext(Action action) => RevitTask.RunAsync(action); + protected override Task MainToWorker(Func action) => Task.FromResult(action()); - protected override Task RunContext(Func> action) => RevitTask.RunAsync(action); + protected override Task WorkerToMain(Func action) => RevitTask.RunAsync(action); } From 2e437cbc3b3df7bf8a6dba275e4e296f04a9662b Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 28 Nov 2024 09:40:27 +0000 Subject: [PATCH 27/65] ArcGIS can not always go to the queued task --- .../Utils/ArcGISThreadContext.cs | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs index 7ae0eb6a8..dcb7cb237 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs @@ -3,13 +3,34 @@ namespace Speckle.Connectors.ArcGIS.Utils; +//don't check for GUI as it's the same check we do in ThreadContext public class ArcGISThreadContext : ThreadContext { - protected override Task MainToWorkerAsync(Func> action) => QueuedTask.Run(action); + protected override Task MainToWorkerAsync(Func> action) + { + if (QueuedTask.OnWorker) + { + return action(); + } + else + { + return QueuedTask.Run(action); + } + } protected override Task WorkerToMainAsync(Func> action) => QueuedTask.Run(action); - protected override Task MainToWorker(Func action) => QueuedTask.Run(action); + protected override Task MainToWorker(Func action) + { + if (QueuedTask.OnWorker) + { + return Task.FromResult(action()); + } + else + { + return QueuedTask.Run(action); + } + } - protected override Task WorkerToMain(Func action) => QueuedTask.Run(action); + protected override Task WorkerToMain(Func action) => QueuedTask.Run(action); } From 4b245840a5bb6a7fb2431234431e008eaa4b8c37 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 28 Nov 2024 09:40:57 +0000 Subject: [PATCH 28/65] format --- .../Bindings/ArcGISSendBinding.cs | 121 ++++++++-------- .../Bindings/BasicConnectorBinding.cs | 16 +-- .../Receive/ArcGISHostObjectBuilder.cs | 132 +++++++++--------- .../Utils/ArcGISThreadContext.cs | 4 +- .../Utils/ArcGisDocumentStore.cs | 7 +- .../Send/AutocadRootObjectBaseBuilder.cs | 10 +- .../Bindings/BasicConnectorBindingRevit.cs | 10 +- .../Receive/RevitHostObjectBuilder.cs | 5 +- .../Plugin/RevitThreadContext.cs | 2 +- .../ArcGISConversionSettingsFactory.cs | 2 +- .../Bridge/BrowserBridge.cs | 35 +++-- .../Builders/IHostObjectBuilder.cs | 19 ++- .../Operations/ReceiveOperation.cs | 12 +- .../Threading/DefaultThreadContext.cs | 13 +- .../Threading/ThreadContext.cs | 43 +++--- .../Threading/Yield.cs | 23 +-- 16 files changed, 234 insertions(+), 220 deletions(-) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs index 95404059d..7082ee687 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs @@ -138,24 +138,24 @@ private void SubscribeToArcGISEvents() private void SubscribeToMapMembersDataSourceChange() { - if (MapView.Active == null) - { - return; - } + if (MapView.Active == null) + { + return; + } - // subscribe to layers - foreach (Layer layer in MapView.Active.Map.Layers) - { - if (layer is FeatureLayer featureLayer) - { - SubscribeToFeatureLayerDataSourceChange(featureLayer); - } - } - // subscribe to tables - foreach (StandaloneTable table in MapView.Active.Map.StandaloneTables) + // subscribe to layers + foreach (Layer layer in MapView.Active.Map.Layers) + { + if (layer is FeatureLayer featureLayer) { - SubscribeToTableDataSourceChange(table); + SubscribeToFeatureLayerDataSourceChange(featureLayer); } + } + // subscribe to tables + foreach (StandaloneTable table in MapView.Active.Map.StandaloneTables) + { + SubscribeToTableDataSourceChange(table); + } } private void SubscribeToFeatureLayerDataSourceChange(FeatureLayer layer) @@ -361,54 +361,51 @@ public async Task Send(string modelCardId) CancellationToken cancellationToken = _cancellationManager.InitCancellationTokenSource(modelCardId); - using var scope = _serviceProvider.CreateScope(); - scope - .ServiceProvider.GetRequiredService>() - .Initialize( - _arcGISConversionSettingsFactory.Create( - Project.Current, - MapView.Active.Map, - new CRSoffsetRotation(MapView.Active.Map) - ) - ); - List mapMembers = modelCard - .SendFilter.NotNull() - .RefreshObjectIds() - .Select(id => (MapMember)MapView.Active.Map.FindLayer(id) ?? MapView.Active.Map.FindStandaloneTable(id)) - .Where(obj => obj != null) - .ToList(); - - if (mapMembers.Count == 0) - { - // Handle as CARD ERROR in this function - throw new SpeckleSendFilterException( - "No objects were found to convert. Please update your publish filter!" - ); - } - - // subscribe to the selected layer events - foreach (MapMember mapMember in mapMembers) - { - if (mapMember is FeatureLayer featureLayer) - { - SubscribeToFeatureLayerDataSourceChange(featureLayer); - } - else if (mapMember is StandaloneTable table) - { - SubscribeToTableDataSourceChange(table); - } - } - - var sendResult = await scope - .ServiceProvider.GetRequiredService>() - .Execute( - mapMembers, - modelCard.GetSendInfo("ArcGIS"), // POC: get host app name from settings? same for GetReceiveInfo - _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationToken), - cancellationToken - ) - .ConfigureAwait(false); + using var scope = _serviceProvider.CreateScope(); + scope + .ServiceProvider.GetRequiredService>() + .Initialize( + _arcGISConversionSettingsFactory.Create( + Project.Current, + MapView.Active.Map, + new CRSoffsetRotation(MapView.Active.Map) + ) + ); + List mapMembers = modelCard + .SendFilter.NotNull() + .RefreshObjectIds() + .Select(id => (MapMember)MapView.Active.Map.FindLayer(id) ?? MapView.Active.Map.FindStandaloneTable(id)) + .Where(obj => obj != null) + .ToList(); + + if (mapMembers.Count == 0) + { + // Handle as CARD ERROR in this function + throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!"); + } + // subscribe to the selected layer events + foreach (MapMember mapMember in mapMembers) + { + if (mapMember is FeatureLayer featureLayer) + { + SubscribeToFeatureLayerDataSourceChange(featureLayer); + } + else if (mapMember is StandaloneTable table) + { + SubscribeToTableDataSourceChange(table); + } + } + + var sendResult = await scope + .ServiceProvider.GetRequiredService>() + .Execute( + mapMembers, + modelCard.GetSendInfo("ArcGIS"), // POC: get host app name from settings? same for GetReceiveInfo + _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationToken), + cancellationToken + ) + .ConfigureAwait(false); await Commands .SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs index ec71b65fd..89f04d1f6 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs @@ -90,20 +90,20 @@ public Task HighlightModel(string modelCardId) { return Task.CompletedTask; } - HighlightObjectsOnView(objectIds); - return Task.CompletedTask; + HighlightObjectsOnView(objectIds); + return Task.CompletedTask; } private void HighlightObjectsOnView(IReadOnlyList objectIds) { MapView mapView = MapView.Active; - List mapMembersFeatures = GetMapMembers(objectIds, mapView); - ClearSelectionInTOC(); - ClearSelection(); - SelectMapMembersInTOC(mapMembersFeatures); - SelectMapMembersAndFeatures(mapMembersFeatures); - mapView.ZoomToSelected(); + List mapMembersFeatures = GetMapMembers(objectIds, mapView); + ClearSelectionInTOC(); + ClearSelection(); + SelectMapMembersInTOC(mapMembersFeatures); + SelectMapMembersAndFeatures(mapMembersFeatures); + mapView.ZoomToSelected(); } private List GetMapMembers(IReadOnlyList objectIds, MapView mapView) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/ArcGISHostObjectBuilder.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/ArcGISHostObjectBuilder.cs index d0fb515cb..d5f7b3f87 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/ArcGISHostObjectBuilder.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/ArcGISHostObjectBuilder.cs @@ -104,10 +104,7 @@ CancellationToken cancellationToken try { obj = _localToGlobalConverterUtils.TransformObjects(objectToConvert.AtomicObject, objectToConvert.Matrix); - object? conversionResult = - obj is GisNonGeometricFeature - ? null - : _converter.Convert(obj); + object? conversionResult = obj is GisNonGeometricFeature ? null : _converter.Convert(obj); string nestedLayerPath = $"{string.Join("\\", path)}"; if (objectToConvert.TraversalContext.Parent?.Current is not VectorLayer) @@ -131,19 +128,19 @@ obj is GisNonGeometricFeature // 2.1. Group conversionTrackers (to write into datasets) onOperationProgressed.Report(new("Grouping features into layers", null)); Dictionary> convertedGroups = - _featureClassUtils - .GroupConversionTrackers(conversionTracker, (s, progres) => onOperationProgressed.Report(new(s, progres))); - + _featureClassUtils.GroupConversionTrackers( + conversionTracker, + (s, progres) => onOperationProgressed.Report(new(s, progres)) + ); // 2.2. Write groups of objects to Datasets onOperationProgressed.Report(new("Writing to Database", null)); - _featureClassUtils - .CreateDatasets( - conversionTracker, - convertedGroups, - (s, progres) => onOperationProgressed.Report(new(s, progres)) - ); + _featureClassUtils.CreateDatasets( + conversionTracker, + convertedGroups, + (s, progres) => onOperationProgressed.Report(new(s, progres)) + ); // 3. add layer and tables to the Map and Table Of Content @@ -301,68 +298,65 @@ private MapMember AddDatasetsToMap( string modelName ) { - // get layer details - string? datasetId = trackerItem.DatasetId; // should not be null here - Uri uri = new($"{_settingsStore.Current.SpeckleDatabasePath.AbsolutePath.Replace('/', '\\')}\\{datasetId}"); - string nestedLayerName = trackerItem.NestedLayerName; + // get layer details + string? datasetId = trackerItem.DatasetId; // should not be null here + Uri uri = new($"{_settingsStore.Current.SpeckleDatabasePath.AbsolutePath.Replace('/', '\\')}\\{datasetId}"); + string nestedLayerName = trackerItem.NestedLayerName; - // add group for the current layer - string shortName = nestedLayerName.Split("\\")[^1]; - string nestedLayerPath = string.Join("\\", nestedLayerName.Split("\\").SkipLast(1)); + // add group for the current layer + string shortName = nestedLayerName.Split("\\")[^1]; + string nestedLayerPath = string.Join("\\", nestedLayerName.Split("\\").SkipLast(1)); - // if no general group layer found - if (createdLayerGroups.Count == 0) - { - Map map = _settingsStore.Current.Map; - GroupLayer mainGroupLayer = LayerFactory.Instance.CreateGroupLayer(map, 0, $"{projectName}: {modelName}"); - mainGroupLayer.SetExpanded(true); - createdLayerGroups["Basic Speckle Group"] = mainGroupLayer; // key doesn't really matter here - } + // if no general group layer found + if (createdLayerGroups.Count == 0) + { + Map map = _settingsStore.Current.Map; + GroupLayer mainGroupLayer = LayerFactory.Instance.CreateGroupLayer(map, 0, $"{projectName}: {modelName}"); + mainGroupLayer.SetExpanded(true); + createdLayerGroups["Basic Speckle Group"] = mainGroupLayer; // key doesn't really matter here + } - var groupLayer = CreateNestedGroupLayer(nestedLayerPath, createdLayerGroups); + var groupLayer = CreateNestedGroupLayer(nestedLayerPath, createdLayerGroups); - // Most of the Speckle-written datasets will be containing geometry and added as Layers - // although, some datasets might be just tables (e.g. native GIS Tables, in the future maybe Revit schedules etc. - // We can create a connection to the dataset in advance and determine its type, but this will be more - // expensive, than assuming by default that it's a layer with geometry (which in most cases it's expected to be) - try - { - var layer = LayerFactory.Instance.CreateLayer(uri, groupLayer, layerName: shortName); - if (layer == null) - { - throw new SpeckleException($"Layer '{shortName}' was not created"); - } - layer.SetExpanded(false); - - // if Scene - // https://community.esri.com/t5/arcgis-pro-sdk-questions/sdk-equivalent-to-changing-layer-s-elevation/td-p/1346139 - if (_settingsStore.Current.Map.IsScene) - { - var groundSurfaceLayer = _settingsStore.Current.Map.GetGroundElevationSurfaceLayer(); - var layerElevationSurface = new CIMLayerElevationSurface - { - ElevationSurfaceLayerURI = groundSurfaceLayer.URI, - }; - - // for Feature Layers - if (layer.GetDefinition() is CIMFeatureLayer cimLyr) - { - cimLyr.LayerElevation = layerElevationSurface; - layer.SetDefinition(cimLyr); - } - } - - return layer; - } - catch (ArgumentException) + // Most of the Speckle-written datasets will be containing geometry and added as Layers + // although, some datasets might be just tables (e.g. native GIS Tables, in the future maybe Revit schedules etc. + // We can create a connection to the dataset in advance and determine its type, but this will be more + // expensive, than assuming by default that it's a layer with geometry (which in most cases it's expected to be) + try + { + var layer = LayerFactory.Instance.CreateLayer(uri, groupLayer, layerName: shortName); + if (layer == null) + { + throw new SpeckleException($"Layer '{shortName}' was not created"); + } + layer.SetExpanded(false); + + // if Scene + // https://community.esri.com/t5/arcgis-pro-sdk-questions/sdk-equivalent-to-changing-layer-s-elevation/td-p/1346139 + if (_settingsStore.Current.Map.IsScene) + { + var groundSurfaceLayer = _settingsStore.Current.Map.GetGroundElevationSurfaceLayer(); + var layerElevationSurface = new CIMLayerElevationSurface { ElevationSurfaceLayerURI = groundSurfaceLayer.URI, }; + + // for Feature Layers + if (layer.GetDefinition() is CIMFeatureLayer cimLyr) { - StandaloneTable table = StandaloneTableFactory.Instance.CreateStandaloneTable( - uri, - groupLayer, - tableName: shortName - ); - return table; + cimLyr.LayerElevation = layerElevationSurface; + layer.SetDefinition(cimLyr); } + } + + return layer; + } + catch (ArgumentException) + { + StandaloneTable table = StandaloneTableFactory.Instance.CreateStandaloneTable( + uri, + groupLayer, + tableName: shortName + ); + return table; + } } private GroupLayer CreateNestedGroupLayer(string nestedLayerPath, Dictionary createdLayerGroups) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs index dcb7cb237..3741d2c8d 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs @@ -20,7 +20,7 @@ protected override Task MainToWorkerAsync(Func> action) protected override Task WorkerToMainAsync(Func> action) => QueuedTask.Run(action); - protected override Task MainToWorker(Func action) + protected override Task MainToWorker(Func action) { if (QueuedTask.OnWorker) { @@ -32,5 +32,5 @@ protected override Task MainToWorker(Func action) } } - protected override Task WorkerToMain(Func action) => QueuedTask.Run(action); + protected override Task WorkerToMain(Func action) => QueuedTask.Run(action); } diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs index 952b7f836..ad44f657f 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs @@ -12,7 +12,12 @@ namespace Speckle.Connectors.ArcGIS.Utils; public class ArcGISDocumentStore : DocumentModelStore { private readonly IThreadContext _threadContext; - public ArcGISDocumentStore(IJsonSerializer jsonSerializer, ITopLevelExceptionHandler topLevelExceptionHandler, IThreadContext threadContext) + + public ArcGISDocumentStore( + IJsonSerializer jsonSerializer, + ITopLevelExceptionHandler topLevelExceptionHandler, + IThreadContext threadContext + ) : base(jsonSerializer) { _threadContext = threadContext; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBaseBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBaseBuilder.cs index 6e95c9948..62290cec2 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBaseBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBaseBuilder.cs @@ -53,16 +53,16 @@ ISdkActivityFactory activityFactory "Maintainability", "CA1506:Avoid excessive class coupling", Justification = """ - It is already simplified but has many different references since it is a builder. Do not know can we simplify it now. - Later we might consider to refactor proxies from one proxy manager? but we do not know the shape of it all potential - proxy classes yet. So I'm supressing this one now!!! - """ + It is already simplified but has many different references since it is a builder. Do not know can we simplify it now. + Later we might consider to refactor proxies from one proxy manager? but we do not know the shape of it all potential + proxy classes yet. So I'm supressing this one now!!! + """ )] public RootObjectBuilderResult Build( IReadOnlyList objects, SendInfo sendInfo, IProgress onOperationProgressed - ) + ) { // 0 - Init the root Collection root = diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs index b72c3a5d1..6691eb77b 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs @@ -97,11 +97,11 @@ public async Task HighlightModel(string modelCardId) if (senderModelCard.SendFilter is RevitViewsFilter revitViewsFilter) { - var view = revitViewsFilter.GetView(); - if (view is not null) - { - _revitContext.UIApplication.ActiveUIDocument.ActiveView = view; - } + var view = revitViewsFilter.GetView(); + if (view is not null) + { + _revitContext.UIApplication.ActiveUIDocument.ActiveView = view; + } return; } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs index 2cc466dc0..76738b4d3 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs @@ -118,10 +118,7 @@ IProgress onOperationProgressed private ( HostObjectBuilderResult builderResult, List<(DirectShape res, string applicationId)> postBakePaintTargets - ) BakeObjects( - List localToGlobalMaps, - IProgress onOperationProgressed - ) + ) BakeObjects(List localToGlobalMaps, IProgress onOperationProgressed) { using var _ = activityFactory.Start("BakeObjects"); var conversionResults = new List(); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs index c1bada778..2d53d1ada 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs @@ -9,7 +9,7 @@ public class RevitThreadContext : ThreadContext protected override Task WorkerToMainAsync(Func> action) => RevitTask.RunAsync(action); - protected override Task MainToWorker(Func action) => Task.FromResult(action()); + protected override Task MainToWorker(Func action) => Task.FromResult(action()); protected override Task WorkerToMain(Func action) => RevitTask.RunAsync(action); } diff --git a/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionSettingsFactory.cs b/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionSettingsFactory.cs index f3c0e2fc4..e0464be1b 100644 --- a/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionSettingsFactory.cs +++ b/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionSettingsFactory.cs @@ -147,7 +147,7 @@ public Uri AddDatabaseToProject(Uri databasePath) if (gdbToAdd is not null) { - var addedGeodatabase = Project.Current.AddItem(gdbToAdd as IProjectItem); + var addedGeodatabase = Project.Current.AddItem(gdbToAdd as IProjectItem); } } catch (NullReferenceException ex) diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 195ae18c4..9249aa255 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -61,7 +61,9 @@ public BrowserBridge( IJsonSerializer jsonSerializer, ILogger logger, ILogger topLogger, - IBrowserScriptExecutor browserScriptExecutor, IThreadOptions threadOptions) + IBrowserScriptExecutor browserScriptExecutor, + IThreadOptions threadOptions + ) { _threadContext = threadContext; _jsonSerializer = jsonSerializer; @@ -103,22 +105,25 @@ public string[] GetBindingsMethodNames() } public void RunMethod(string methodName, string requestId, string methodArgs) => - _threadContext.RunOnThreadAsync(async () => - { - var task = await TopLevelExceptionHandler - .CatchUnhandledAsync(async () => + _threadContext.RunOnThreadAsync( + async () => + { + var task = await TopLevelExceptionHandler + .CatchUnhandledAsync(async () => + { + var result = await ExecuteMethod(methodName, methodArgs).ConfigureAwait(false); + string resultJson = _jsonSerializer.Serialize(result); + await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); + }) + .ConfigureAwait(false); + if (task.Exception is not null) { - var result = await ExecuteMethod(methodName, methodArgs).ConfigureAwait(false); - string resultJson = _jsonSerializer.Serialize(result); + string resultJson = SerializeFormattedException(task.Exception); await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); - }) - .ConfigureAwait(false); - if (task.Exception is not null) - { - string resultJson = SerializeFormattedException(task.Exception); - await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); - } - }, _threadOptions.RunCommandsOnMainThread); + } + }, + _threadOptions.RunCommandsOnMainThread + ); /// /// Used by the action block to invoke the actual method called by the UI. diff --git a/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs b/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs index cea3c1fe8..5d68b23d1 100644 --- a/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs +++ b/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs @@ -6,13 +6,22 @@ namespace Speckle.Connectors.Common.Builders; public abstract class HostObjectBuilder : IHostObjectBuilder { - Task IHostObjectBuilder.Build(Base rootObject, string projectName, string modelName, IProgress onOperationProgressed, - CancellationToken cancellationToken) => - Task.FromResult(Build(rootObject, projectName, modelName, onOperationProgressed)); + Task IHostObjectBuilder.Build( + Base rootObject, + string projectName, + string modelName, + IProgress onOperationProgressed, + CancellationToken cancellationToken + ) => Task.FromResult(Build(rootObject, projectName, modelName, onOperationProgressed)); - protected abstract HostObjectBuilderResult Build(Base rootObject, string projectName, string modelName, - IProgress onOperationProgressed); + protected abstract HostObjectBuilderResult Build( + Base rootObject, + string projectName, + string modelName, + IProgress onOperationProgressed + ); } + // POC: We might consider to put also IRootObjectBuilder interface here in same folder and create concrete classes from it in per connector. public interface IHostObjectBuilder { diff --git a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs index 9fac3cf5c..4647e79fb 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs @@ -20,7 +20,6 @@ public sealed class ReceiveOperation( IThreadOptions threadOptions ) { - public async Task Execute( ReceiveInfo receiveInfo, IProgress onOperationProgressed, @@ -44,8 +43,10 @@ CancellationToken cancellationToken // 4 - Convert objects HostObjectBuilderResult res = await threadContext - .RunOnThreadAsync(() => ConvertObjects(commitObject, receiveInfo, onOperationProgressed, cancellationToken), - threadOptions.RunReceiveBuildOnMainThread) + .RunOnThreadAsync( + () => ConvertObjects(commitObject, receiveInfo, onOperationProgressed, cancellationToken), + threadOptions.RunReceiveBuildOnMainThread + ) .BackToAny(); await apiClient @@ -96,8 +97,9 @@ CancellationToken cancellationToken try { - HostObjectBuilderResult res = await hostObjectBuilder - .Build(commitObject, receiveInfo.ProjectName, receiveInfo.ModelName, onOperationProgressed, cancellationToken).BackToAny(); + HostObjectBuilderResult res = await hostObjectBuilder + .Build(commitObject, receiveInfo.ProjectName, receiveInfo.ModelName, onOperationProgressed, cancellationToken) + .BackToAny(); conversionActivity?.SetStatus(SdkActivityStatusCode.Ok); return res; } diff --git a/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs b/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs index 3fb0e7c3e..1a9717976 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs @@ -5,12 +5,13 @@ namespace Speckle.Connectors.Common.Threading; public class DefaultThreadContext : ThreadContext { - private readonly SynchronizationContext _threadContext = SynchronizationContext.Current.NotNull("No UI thread to capture?"); - + private readonly SynchronizationContext _threadContext = SynchronizationContext.Current.NotNull( + "No UI thread to capture?" + ); + [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] protected override Task WorkerToMainAsync(Func> action) { - TaskCompletionSource tcs = new(); _threadContext.Post( async _ => @@ -29,13 +30,13 @@ protected override Task WorkerToMainAsync(Func> action) ); return tcs.Task; } - + protected override Task MainToWorkerAsync(Func> action) { Task> f = Task.Factory.StartNew(action, default, TaskCreationOptions.LongRunning, TaskScheduler.Default); return f.Unwrap(); } - + [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] protected override Task WorkerToMain(Func action) { @@ -57,7 +58,7 @@ protected override Task WorkerToMain(Func action) ); return tcs.Task; } - + protected override Task MainToWorker(Func action) { Task f = Task.Factory.StartNew(action, default, TaskCreationOptions.LongRunning, TaskScheduler.Default); diff --git a/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs b/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs index c242fd070..ddced50e3 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs @@ -27,13 +27,11 @@ public async Task RunOnThread(Action action, bool useMain) } else { - await WorkerToMainAsync( - () => - { - RunContext(action); - return s_completedTask; - } - ) + await WorkerToMainAsync(() => + { + RunContext(action); + return s_completedTask; + }) .ConfigureAwait(false); } } @@ -42,10 +40,11 @@ await WorkerToMainAsync( if (IsMainThread) { await MainToWorkerAsync(() => - { - action(); - return s_completedTask; - }).BackToAny(); + { + action(); + return s_completedTask; + }) + .BackToAny(); } else { @@ -83,13 +82,11 @@ public async Task RunOnThreadAsync(Func action, bool useMain) } else { - await WorkerToMainAsync( - async () => - { - await RunContext(action.Invoke).ConfigureAwait(false); - return null; - } - ) + await WorkerToMainAsync(async () => + { + await RunContext(action.Invoke).ConfigureAwait(false); + return null; + }) .ConfigureAwait(false); } } @@ -98,10 +95,11 @@ public async Task RunOnThreadAsync(Func action, bool useMain) if (IsMainThread) { await MainToWorkerAsync(async () => - { - await action().BackToAny(); - return null; - }).BackToAny(); + { + await action().BackToAny(); + return null; + }) + .BackToAny(); } else { @@ -135,4 +133,3 @@ public Task RunOnThreadAsync(Func> action, bool useMain) protected abstract Task MainToWorker(Func action); } - diff --git a/Sdk/Speckle.Connectors.Common/Threading/Yield.cs b/Sdk/Speckle.Connectors.Common/Threading/Yield.cs index bfebf3b24..c1cb6e12c 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/Yield.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/Yield.cs @@ -4,20 +4,22 @@ namespace Speckle.Connectors.Common.Threading; public static class Yield { - private static readonly Action s_yield = () => { }; public static async ValueTask Force() { if (ThreadContext.IsMainThread) { - await Task.Factory.StartNew( - s_yield, - CancellationToken.None, - TaskCreationOptions.PreferFairness, - SynchronizationContext.Current != null - ? TaskScheduler.FromCurrentSynchronizationContext() - : TaskScheduler.Current).ConfigureAwait(false); + await Task + .Factory.StartNew( + s_yield, + CancellationToken.None, + TaskCreationOptions.PreferFairness, + SynchronizationContext.Current != null + ? TaskScheduler.FromCurrentSynchronizationContext() + : TaskScheduler.Current + ) + .ConfigureAwait(false); } else { @@ -26,9 +28,14 @@ await Task.Factory.StartNew( } public static ConfiguredValueTaskAwaitable BackToThread(this ValueTask valueTask) => valueTask.ConfigureAwait(true); + public static ConfiguredValueTaskAwaitable BackToAny(this ValueTask valueTask) => valueTask.ConfigureAwait(false); + public static ConfiguredTaskAwaitable BackToThread(this Task task) => task.ConfigureAwait(true); + public static ConfiguredTaskAwaitable BackToAny(this Task task) => task.ConfigureAwait(false); + public static ConfiguredTaskAwaitable BackToThread(this Task task) => task.ConfigureAwait(true); + public static ConfiguredTaskAwaitable BackToAny(this Task task) => task.ConfigureAwait(false); } From 7a71b5d96be95950b3da84aea56930a49b8c3fd7 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 28 Nov 2024 15:38:41 +0000 Subject: [PATCH 29/65] fix tekla compile errors --- .../Operations/Send/TeklaRootObjectBuilder.cs | 8 ++------ .../Speckle.Connector.TeklaShared/ServiceRegistration.cs | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Operations/Send/TeklaRootObjectBuilder.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Operations/Send/TeklaRootObjectBuilder.cs index 69da6664c..e7e4fef87 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Operations/Send/TeklaRootObjectBuilder.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Operations/Send/TeklaRootObjectBuilder.cs @@ -11,7 +11,6 @@ using Speckle.Sdk.Logging; using Speckle.Sdk.Models; using Speckle.Sdk.Models.Collections; -using Task = System.Threading.Tasks.Task; namespace Speckle.Connectors.TeklaShared.Operations.Send; @@ -44,11 +43,10 @@ TeklaMaterialUnpacker materialUnpacker _materialUnpacker = materialUnpacker; } - public async Task Build( + public RootObjectBuilderResult Build( IReadOnlyList teklaObjects, SendInfo sendInfo, - IProgress onOperationProgressed, - CancellationToken cancellationToken = default + IProgress onOperationProgressed ) { using var activity = _activityFactory.Start("Build"); @@ -67,7 +65,6 @@ public async Task Build( foreach (TSM.ModelObject teklaObject in teklaObjects) { using var _2 = _activityFactory.Start("Convert"); - cancellationToken.ThrowIfCancellationRequested(); var result = ConvertTeklaObject(teklaObject, rootObjectCollection, sendInfo.ProjectId); results.Add(result); @@ -88,7 +85,6 @@ public async Task Build( rootObjectCollection[ProxyKeys.RENDER_MATERIAL] = renderMaterialProxies; } - await Task.Yield(); return new RootObjectBuilderResult(rootObjectCollection, results); } diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs index de258945a..d9d42e0cf 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs @@ -32,7 +32,7 @@ public static IServiceCollection AddTekla(this IServiceCollection services) services.AddSingleton(); services.AddConnectorUtils(); - services.AddDUI(); + services.AddDUI(); services.AddDUIView(); services.AddSingleton(); From bb0faaa847bb27a3727b5bf035e683a2a0bb8264 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 28 Nov 2024 16:29:39 +0000 Subject: [PATCH 30/65] 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 31/65] 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 32/65] 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 33/65] 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 34/65] 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 35/65] 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 36/65] 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 3c0a84ee812f0aace1365814ad415cc9d3760944 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Fri, 29 Nov 2024 14:27:04 +0000 Subject: [PATCH 37/65] update etabs --- .../CSi/Speckle.Connectors.ETABS21/packages.lock.json | 9 +-------- .../CSi/Speckle.Connectors.ETABS22/packages.lock.json | 9 +-------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/Connectors/CSi/Speckle.Connectors.ETABS21/packages.lock.json b/Connectors/CSi/Speckle.Connectors.ETABS21/packages.lock.json index 74d5a6c3d..75dcd2fbe 100644 --- a/Connectors/CSi/Speckle.Connectors.ETABS21/packages.lock.json +++ b/Connectors/CSi/Speckle.Connectors.ETABS21/packages.lock.json @@ -275,8 +275,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" } }, "speckle.connectors.dui.webview": { @@ -353,12 +352,6 @@ "requested": "[3.1.0-dev.200, )", "resolved": "3.1.0-dev.200", "contentHash": "4ZHkKRzI6/Xa1c20NrH3+e+m5DUB+qbBSq+GJ6MShUh6SpKOC4DRdwy0qCcAWrurq7V94xU0qN+7+QzKGeWlFw==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Connectors/CSi/Speckle.Connectors.ETABS22/packages.lock.json b/Connectors/CSi/Speckle.Connectors.ETABS22/packages.lock.json index 873e54ded..c759c35e1 100644 --- a/Connectors/CSi/Speckle.Connectors.ETABS22/packages.lock.json +++ b/Connectors/CSi/Speckle.Connectors.ETABS22/packages.lock.json @@ -231,8 +231,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.200, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.200, )" } }, "speckle.connectors.dui.webview": { @@ -308,12 +307,6 @@ "requested": "[3.1.0-dev.200, )", "resolved": "3.1.0-dev.200", "contentHash": "4ZHkKRzI6/Xa1c20NrH3+e+m5DUB+qbBSq+GJ6MShUh6SpKOC4DRdwy0qCcAWrurq7V94xU0qN+7+QzKGeWlFw==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } From 20ecbada87679700b8fe3335111e6c4d9ab5da44 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Fri, 29 Nov 2024 14:54:51 +0000 Subject: [PATCH 38/65] thread context --- .../CSi/Speckle.Connectors.CSiShared/ServiceRegistration.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Connectors/CSi/Speckle.Connectors.CSiShared/ServiceRegistration.cs b/Connectors/CSi/Speckle.Connectors.CSiShared/ServiceRegistration.cs index ce63063fc..0f689e31f 100644 --- a/Connectors/CSi/Speckle.Connectors.CSiShared/ServiceRegistration.cs +++ b/Connectors/CSi/Speckle.Connectors.CSiShared/ServiceRegistration.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Speckle.Connectors.Common; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.CSiShared.Bindings; using Speckle.Connectors.CSiShared.Filters; using Speckle.Connectors.CSiShared.HostApp; @@ -20,7 +21,7 @@ public static IServiceCollection AddCSi(this IServiceCollection services) services.AddSingleton(); services.AddConnectorUtils(); - services.AddDUI(); + services.AddDUI(); services.AddDUIView(); services.AddSingleton(); From 54dfd05c8ec73b8f486692e218daee9eba0511a7 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Fri, 29 Nov 2024 14:55:01 +0000 Subject: [PATCH 39/65] autocad threading? --- .../Operations/Receive/AutocadHostObjectBuilder.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs index 38c874037..e6423e742 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs @@ -75,11 +75,13 @@ CancellationToken cancellationToken baseLayerPrefix, onOperationProgressed ); + await Yield.Force().BackToThread(); } if (unpackedRoot.ColorProxies != null) { colorBaker.ParseColors(unpackedRoot.ColorProxies, onOperationProgressed); + await Yield.Force().BackToThread(); } // 5 - Convert atomic objects @@ -91,7 +93,11 @@ CancellationToken cancellationToken { string objectId = atomicObject.applicationId ?? atomicObject.id; onOperationProgressed.Report(new("Converting objects", (double)++count / atomicObjects.Count)); - await Yield.Force().BackToThread(); + if (count % 50 == 0) + { + await Yield.Force().BackToThread(); + } + try { List convertedObjects = ConvertObject(atomicObject, layerPath, baseLayerPrefix); From 287b719455041eb6b6ae41efc9ed50a786f74a34 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 2 Dec 2024 16:39:54 +0000 Subject: [PATCH 40/65] merge fixes --- .../Receive/AutocadHostObjectBuilder.cs | 35 +++---------------- .../Receive/RhinoHostObjectBuilder.cs | 4 +-- 2 files changed, 7 insertions(+), 32 deletions(-) diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs index 59e1c0a85..543594e69 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs @@ -5,7 +5,6 @@ using Speckle.Connectors.Common.Conversion; using Speckle.Connectors.Common.Operations; using Speckle.Connectors.Common.Operations.Receive; -using Speckle.Connectors.Common.Threading; using Speckle.Converters.Common; using Speckle.Sdk; using Speckle.Sdk.Models; @@ -27,28 +26,9 @@ public class AutocadHostObjectBuilder( IAutocadColorBaker colorBaker, AutocadContext autocadContext, RootObjectUnpacker rootObjectUnpacker -) : IHostObjectBuilder +) : HostObjectBuilder { - public async Task Build( - Base rootObject, - string projectName, - string modelName, - IProgress onOperationProgressed, - CancellationToken cancellationToken - ) - { - // NOTE: This is the only place we apply ISyncToThread across connectors. We need to sync up with main thread here - // after GetObject and Deserialization. It is anti-pattern now. Happiness level 3/10 but works. - return await _syncToThread - .RunOnThread(async () => - { - await Task.CompletedTask.ConfigureAwait(true); - return BuildSync(rootObject, projectName, modelName, onOperationProgressed); - }) - .ConfigureAwait(false); - } - - private HostObjectBuilderResult BuildSync( + protected override HostObjectBuilderResult Build( Base rootObject, string projectName, string modelName, @@ -57,7 +37,6 @@ IProgress onOperationProgressed { // Prompt the UI conversion started. Progress bar will swoosh. onOperationProgressed.Report(new("Converting", null)); - await Yield.Force().BackToThread(); // Layer filter for received commit with project and model name layerBaker.CreateLayerFilter(projectName, modelName); @@ -88,7 +67,7 @@ IProgress onOperationProgressed // 3 - Bake materials and colors, as they are used later down the line by layers and objects if (unpackedRoot.RenderMaterialProxies != null) { - _materialBaker.ParseAndBakeRenderMaterials( + materialBaker.ParseAndBakeRenderMaterials( unpackedRoot.RenderMaterialProxies, baseLayerPrefix, onOperationProgressed @@ -97,7 +76,7 @@ IProgress onOperationProgressed if (unpackedRoot.ColorProxies != null) { - _colorBaker.ParseColors(unpackedRoot.ColorProxies, onOperationProgressed); + colorBaker.ParseColors(unpackedRoot.ColorProxies, onOperationProgressed); } // 5 - Convert atomic objects @@ -109,10 +88,6 @@ IProgress onOperationProgressed { string objectId = atomicObject.applicationId ?? atomicObject.id; onOperationProgressed.Report(new("Converting objects", (double)++count / atomicObjects.Count)); - if (count % 50 == 0) - { - await Yield.Force().BackToThread(); - } try { @@ -138,7 +113,7 @@ IProgress onOperationProgressed } // 6 - Convert instances - var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = _instanceBaker.BakeInstances( + var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = instanceBaker.BakeInstances( instanceComponentsWithPath, applicationIdMap, baseLayerPrefix, diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs index 9c3152e49..c7ba7d71e 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs @@ -55,7 +55,7 @@ ISdkActivityFactory activityFactory } #pragma warning disable CA1506 - public Task Build( + protected override HostObjectBuilderResult Build( #pragma warning restore CA1506 Base rootObject, string projectName, @@ -226,7 +226,7 @@ IProgress onOperationProgressed } _converterSettings.Current.Document.Views.Redraw(); - return Task.FromResult(new HostObjectBuilderResult(bakedObjectIds, conversionResults)); + return new HostObjectBuilderResult(bakedObjectIds, conversionResults); } private void PreReceiveDeepClean(string baseLayerName) From 8b3fb9859a22cd3930209ae8f5ad72b341d3c9c6 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 2 Dec 2024 16:58:00 +0000 Subject: [PATCH 41/65] remove more async --- .../HostApp/ArcGISColorManager.cs | 9 ++------- .../Receive/ArcGISHostObjectBuilder.cs | 7 +++---- .../Receive/AutocadHostObjectBuilder.cs | 9 +++++---- .../Receive/RevitHostObjectBuilder.cs | 16 ++++++++++----- .../Receive/RhinoHostObjectBuilder.cs | 9 ++++++--- .../Builders/IHostObjectBuilder.cs | 20 +------------------ .../Operations/ReceiveOperation.cs | 14 ++++++++----- 7 files changed, 37 insertions(+), 47 deletions(-) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/HostApp/ArcGISColorManager.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/HostApp/ArcGISColorManager.cs index 970feb224..f036bd092 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/HostApp/ArcGISColorManager.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/HostApp/ArcGISColorManager.cs @@ -56,7 +56,7 @@ public List UnpackColors(List<(MapMember, int)> mapMembersWithDispla /// /// /// - public async Task ParseColors(List colorProxies, IProgress onOperationProgressed) + public void ParseColors(List colorProxies, IProgress onOperationProgressed) { // injected as Singleton, so we need to clean existing proxies first ObjectColorsIdMap = new(); @@ -64,7 +64,6 @@ public async Task ParseColors(List colorProxies, IProgress colorProxies, IProgress /// /// - public async Task ParseMaterials( - List materialProxies, - IProgress onOperationProgressed - ) + public void ParseMaterials(List materialProxies, IProgress onOperationProgressed) { // injected as Singleton, so we need to clean existing proxies first ObjectMaterialsIdMap = new(); @@ -89,7 +85,6 @@ IProgress onOperationProgressed foreach (RenderMaterialProxy colorProxy in materialProxies) { onOperationProgressed.Report(new("Converting materials", (double)++count / materialProxies.Count)); - await Task.Yield(); foreach (string objectId in colorProxy.objects) { Color convertedColor = Color.FromArgb(colorProxy.value.diffuse); diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/ArcGISHostObjectBuilder.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/ArcGISHostObjectBuilder.cs index d5f7b3f87..980c9642f 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/ArcGISHostObjectBuilder.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/ArcGISHostObjectBuilder.cs @@ -8,7 +8,6 @@ using Speckle.Connectors.Common.Conversion; using Speckle.Connectors.Common.Instances; using Speckle.Connectors.Common.Operations; -using Speckle.Connectors.Common.Threading; using Speckle.Converters.ArcGIS3; using Speckle.Converters.ArcGIS3.Utils; using Speckle.Converters.Common; @@ -58,7 +57,7 @@ ArcGISColorManager colorManager _crsUtils = crsUtils; } - public async Task Build( + public HostObjectBuilderResult Build( Base rootObject, string projectName, string modelName, @@ -78,14 +77,14 @@ CancellationToken cancellationToken .ToList(); if (materials != null) { - await _colorManager.ParseMaterials(materials, onOperationProgressed).BackToThread(); + _colorManager.ParseMaterials(materials, onOperationProgressed); } // get colors List? colors = (rootObject[ProxyKeys.COLOR] as List)?.Cast().ToList(); if (colors != null) { - await _colorManager.ParseColors(colors, onOperationProgressed).BackToThread(); + _colorManager.ParseColors(colors, onOperationProgressed); } int count = 0; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs index 543594e69..5dc9fd739 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs @@ -26,13 +26,14 @@ public class AutocadHostObjectBuilder( IAutocadColorBaker colorBaker, AutocadContext autocadContext, RootObjectUnpacker rootObjectUnpacker -) : HostObjectBuilder +) : IHostObjectBuilder { - protected override HostObjectBuilderResult Build( + public HostObjectBuilderResult Build( Base rootObject, string projectName, string modelName, - IProgress onOperationProgressed + IProgress onOperationProgressed, + CancellationToken cancellationToken ) { // Prompt the UI conversion started. Progress bar will swoosh. @@ -88,7 +89,7 @@ IProgress onOperationProgressed { string objectId = atomicObject.applicationId ?? atomicObject.id; onOperationProgressed.Report(new("Converting objects", (double)++count / atomicObjects.Count)); - + cancellationToken.ThrowIfCancellationRequested(); try { List convertedObjects = ConvertObject(atomicObject, layerPath, baseLayerPrefix); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs index 76738b4d3..0a23ff6c0 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs @@ -34,13 +34,14 @@ public sealed class RevitHostObjectBuilder( ILogger logger, RevitToHostCacheSingleton revitToHostCacheSingleton, ITypedConverter<(Base atomicObject, List matrix), DirectShape> localToGlobalDirectShapeConverter -) : HostObjectBuilder, IDisposable +) : IHostObjectBuilder, IDisposable { - protected override HostObjectBuilderResult Build( + public HostObjectBuilderResult Build( Base rootObject, string projectName, string modelName, - IProgress onOperationProgressed + IProgress onOperationProgressed, + CancellationToken cancellationToken ) { var baseGroupName = $"Project {projectName}: Model {modelName}"; // TODO: unify this across connectors! @@ -92,7 +93,7 @@ IProgress onOperationProgressed { using var _ = activityFactory.Start("Baking objects"); transactionManager.StartTransaction(true, "Baking objects"); - conversionResults = BakeObjects(localToGlobalMaps, onOperationProgressed); + conversionResults = BakeObjects(localToGlobalMaps, onOperationProgressed, cancellationToken); transactionManager.CommitTransaction(); } @@ -118,7 +119,11 @@ IProgress onOperationProgressed private ( HostObjectBuilderResult builderResult, List<(DirectShape res, string applicationId)> postBakePaintTargets - ) BakeObjects(List localToGlobalMaps, IProgress onOperationProgressed) + ) BakeObjects( + List localToGlobalMaps, + IProgress onOperationProgressed, + CancellationToken cancellationToken + ) { using var _ = activityFactory.Start("BakeObjects"); var conversionResults = new List(); @@ -129,6 +134,7 @@ IProgress onOperationProgressed foreach (LocalToGlobalMap localToGlobalMap in localToGlobalMaps) { + cancellationToken.ThrowIfCancellationRequested(); try { using var activity = activityFactory.Start("BakeObject"); diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs index c7ba7d71e..83b5c9400 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs @@ -19,7 +19,7 @@ namespace Speckle.Connectors.Rhino.Operations.Receive; /// /// Expects to be a scoped dependency per receive operation. /// -public class RhinoHostObjectBuilder : HostObjectBuilder +public class RhinoHostObjectBuilder : IHostObjectBuilder { private readonly IRootToHostConverter _converter; private readonly IConverterSettingsStore _converterSettings; @@ -55,12 +55,13 @@ ISdkActivityFactory activityFactory } #pragma warning disable CA1506 - protected override HostObjectBuilderResult Build( + public HostObjectBuilderResult Build( #pragma warning restore CA1506 Base rootObject, string projectName, string modelName, - IProgress onOperationProgressed + IProgress onOperationProgressed, + CancellationToken cancellationToken ) { using var activity = _activityFactory.Start("Build"); @@ -109,6 +110,7 @@ IProgress onOperationProgressed onOperationProgressed.Report(new("Baking layers (redraw disabled)", null)); using (var _ = _activityFactory.Start("Pre baking layers")) { + //TODO what is this? This is going to the UI thread RhinoApp.InvokeAndWait(() => { using var layerNoDraw = new DisableRedrawScope(_converterSettings.Current.Document.Views); @@ -133,6 +135,7 @@ IProgress onOperationProgressed onOperationProgressed.Report( new("Converting objects", (double)++count / atomicObjectsWithoutInstanceComponentsForConverter.Count) ); + cancellationToken.ThrowIfCancellationRequested(); try { // 0: get pre-created layer from cache in layer baker diff --git a/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs b/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs index 5d68b23d1..112af1952 100644 --- a/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs +++ b/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs @@ -4,24 +4,6 @@ namespace Speckle.Connectors.Common.Builders; -public abstract class HostObjectBuilder : IHostObjectBuilder -{ - Task IHostObjectBuilder.Build( - Base rootObject, - string projectName, - string modelName, - IProgress onOperationProgressed, - CancellationToken cancellationToken - ) => Task.FromResult(Build(rootObject, projectName, modelName, onOperationProgressed)); - - protected abstract HostObjectBuilderResult Build( - Base rootObject, - string projectName, - string modelName, - IProgress onOperationProgressed - ); -} - // POC: We might consider to put also IRootObjectBuilder interface here in same folder and create concrete classes from it in per connector. public interface IHostObjectBuilder { @@ -35,7 +17,7 @@ public interface IHostObjectBuilder /// List of application ids. // POC: Where we will return these ids will matter later when we target to also cache received application ids. /// Project and model name are needed for now to construct host app objects into related layers or filters. /// POC: we might consider later to have HostObjectBuilderContext? that might hold all possible data we will need. - Task Build( + HostObjectBuilderResult Build( Base rootObject, string projectName, string modelName, diff --git a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs index 4647e79fb..c33cd74af 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs @@ -43,7 +43,7 @@ CancellationToken cancellationToken // 4 - Convert objects HostObjectBuilderResult res = await threadContext - .RunOnThreadAsync( + .RunOnThread( () => ConvertObjects(commitObject, receiveInfo, onOperationProgressed, cancellationToken), threadOptions.RunReceiveBuildOnMainThread ) @@ -80,7 +80,7 @@ CancellationToken cancellationToken return commitObject; } - private async Task ConvertObjects( + private HostObjectBuilderResult ConvertObjects( Base commitObject, ReceiveInfo receiveInfo, IProgress onOperationProgressed, @@ -97,9 +97,13 @@ CancellationToken cancellationToken try { - HostObjectBuilderResult res = await hostObjectBuilder - .Build(commitObject, receiveInfo.ProjectName, receiveInfo.ModelName, onOperationProgressed, cancellationToken) - .BackToAny(); + HostObjectBuilderResult res = hostObjectBuilder.Build( + commitObject, + receiveInfo.ProjectName, + receiveInfo.ModelName, + onOperationProgressed, + cancellationToken + ); conversionActivity?.SetStatus(SdkActivityStatusCode.Ok); return res; } From 0ae267690011ffd2160384f57161f549d1f47441 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 2 Dec 2024 17:03:56 +0000 Subject: [PATCH 42/65] clean up --- .../Threading/DefaultThreadContext.cs | 6 ++-- .../Threading/ThreadContext.cs | 34 +++++++------------ .../Threading/Yield.cs | 29 ++-------------- 3 files changed, 19 insertions(+), 50 deletions(-) diff --git a/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs b/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs index 1a9717976..9b4f89ab5 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs @@ -18,7 +18,7 @@ protected override Task WorkerToMainAsync(Func> action) { try { - T result = await RunContext(action).ConfigureAwait(false); + T result = await action().BackToCurrent(); tcs.SetResult(result); } catch (Exception ex) @@ -42,11 +42,11 @@ protected override Task WorkerToMain(Func action) { TaskCompletionSource tcs = new(); _threadContext.Post( - async _ => + _ => { try { - T result = await RunContext(action).ConfigureAwait(false); + T result = action(); tcs.SetResult(result); } catch (Exception ex) diff --git a/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs b/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs index ddced50e3..612c02324 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs @@ -9,27 +9,19 @@ public abstract class ThreadContext : IThreadContext public static bool IsMainThread => Environment.CurrentManagedThreadId == 1 && !Thread.CurrentThread.IsBackground; - protected virtual void RunContext(Action action) => action(); - - protected virtual Task RunContext(Func action) => Task.FromResult(action()); - - protected virtual Task RunContext(Func action) => action(); - - protected virtual Task RunContext(Func> action) => action(); - public async Task RunOnThread(Action action, bool useMain) { if (useMain) { if (IsMainThread) { - RunContext(action); + action(); } else { await WorkerToMainAsync(() => { - RunContext(action); + action(); return s_completedTask; }) .ConfigureAwait(false); @@ -48,7 +40,7 @@ await MainToWorkerAsync(() => } else { - RunContext(action); + action(); } } } @@ -59,7 +51,7 @@ public virtual Task RunOnThread(Func action, bool useMain) { if (IsMainThread) { - return RunContext(action); + return Task.FromResult(action()); } return WorkerToMain(action); @@ -69,7 +61,7 @@ public virtual Task RunOnThread(Func action, bool useMain) return MainToWorker(action); } - return RunContext(action); + return Task.FromResult(action()); } public async Task RunOnThreadAsync(Func action, bool useMain) @@ -78,16 +70,16 @@ public async Task RunOnThreadAsync(Func action, bool useMain) { if (IsMainThread) { - await RunContext(action).ConfigureAwait(false); + await action().BackToCurrent(); } else { await WorkerToMainAsync(async () => { - await RunContext(action.Invoke).ConfigureAwait(false); + await action().BackToCurrent(); return null; }) - .ConfigureAwait(false); + .BackToCurrent(); } } else @@ -96,14 +88,14 @@ public async Task RunOnThreadAsync(Func action, bool useMain) { await MainToWorkerAsync(async () => { - await action().BackToAny(); + await action().BackToCurrent(); return null; }) - .BackToAny(); + .BackToCurrent(); } else { - await RunContext(action.Invoke).ConfigureAwait(false); + await action().BackToCurrent(); } } } @@ -114,7 +106,7 @@ public Task RunOnThreadAsync(Func> action, bool useMain) { if (IsMainThread) { - return RunContext(action.Invoke); + return action(); } return WorkerToMainAsync(action); @@ -123,7 +115,7 @@ public Task RunOnThreadAsync(Func> action, bool useMain) { return MainToWorkerAsync(action); } - return RunContext(action.Invoke); + return action(); } protected abstract Task WorkerToMainAsync(Func> action); diff --git a/Sdk/Speckle.Connectors.Common/Threading/Yield.cs b/Sdk/Speckle.Connectors.Common/Threading/Yield.cs index c1cb6e12c..6477a7b01 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/Yield.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/Yield.cs @@ -4,38 +4,15 @@ namespace Speckle.Connectors.Common.Threading; public static class Yield { - private static readonly Action s_yield = () => { }; - - public static async ValueTask Force() - { - if (ThreadContext.IsMainThread) - { - await Task - .Factory.StartNew( - s_yield, - CancellationToken.None, - TaskCreationOptions.PreferFairness, - SynchronizationContext.Current != null - ? TaskScheduler.FromCurrentSynchronizationContext() - : TaskScheduler.Current - ) - .ConfigureAwait(false); - } - else - { - await Task.Yield(); - } - } - - public static ConfiguredValueTaskAwaitable BackToThread(this ValueTask valueTask) => valueTask.ConfigureAwait(true); + public static ConfiguredValueTaskAwaitable BackToCurrent(this ValueTask valueTask) => valueTask.ConfigureAwait(true); public static ConfiguredValueTaskAwaitable BackToAny(this ValueTask valueTask) => valueTask.ConfigureAwait(false); - public static ConfiguredTaskAwaitable BackToThread(this Task task) => task.ConfigureAwait(true); + public static ConfiguredTaskAwaitable BackToCurrent(this Task task) => task.ConfigureAwait(true); public static ConfiguredTaskAwaitable BackToAny(this Task task) => task.ConfigureAwait(false); - public static ConfiguredTaskAwaitable BackToThread(this Task task) => task.ConfigureAwait(true); + public static ConfiguredTaskAwaitable BackToCurrent(this Task task) => task.ConfigureAwait(true); public static ConfiguredTaskAwaitable BackToAny(this Task task) => task.ConfigureAwait(false); } From b1f41c68157daf725587f6e3fd3377e909bd074f Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 3 Dec 2024 09:24:21 +0000 Subject: [PATCH 43/65] 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 44/65] 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 45/65] 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 46/65] 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 47/65] 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 48/65] 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 d5f63237bebfeac23873eac6db3d4f6a8590bed8 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 3 Dec 2024 15:18:20 +0000 Subject: [PATCH 49/65] can build agian --- .../Receive/AutocadHostObjectBuilder.cs | 19 +----- .../Operations/Send/CSiRootObjectBuilder.cs | 7 +- .../ServiceRegistration.cs | 14 +--- .../Receive/RevitHostObjectBuilder.cs | 64 ++----------------- 4 files changed, 10 insertions(+), 94 deletions(-) diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs index 4427ee544..94e0d2a80 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs @@ -132,16 +132,11 @@ CancellationToken cancellationToken // 7 - Create groups if (unpackedRoot.GroupProxies != null) { -<<<<<<< HEAD - List groupResults = groupBaker.CreateGroups(unpackedRoot.GroupProxies, applicationIdMap); - results.AddRange(groupResults); -======= - IReadOnlyCollection groupResults = _groupBaker.CreateGroups( + IReadOnlyCollection groupResults = groupBaker.CreateGroups( unpackedRoot.GroupProxies, applicationIdMap ); results.UnionWith(groupResults); ->>>>>>> dev } return new HostObjectBuilderResult(bakedObjectIds, results); @@ -156,13 +151,8 @@ private void PreReceiveDeepClean(string baseLayerPrefix) private IReadOnlyCollection ConvertObject(Base obj, Collection[] layerPath, string baseLayerNamePrefix) { -<<<<<<< HEAD string layerName = layerBaker.CreateLayerForReceive(layerPath, baseLayerNamePrefix); - var convertedEntities = new List(); -======= - string layerName = _layerBaker.CreateLayerForReceive(layerPath, baseLayerNamePrefix); var convertedEntities = new HashSet(); ->>>>>>> dev using var tr = Application.DocumentManager.CurrentDocument.Database.TransactionManager.StartTransaction(); @@ -187,13 +177,8 @@ private IReadOnlyCollection ConvertObject(Base obj, Collection[] layerPa private Entity BakeObject(Entity entity, Base originalObject, string layerName, Base? parentObject = null) { -<<<<<<< HEAD - var objId = originalObject.applicationId ?? originalObject.id; - if (colorBaker.ObjectColorsIdMap.TryGetValue(objId, out AutocadColor? color)) -======= var objId = originalObject.applicationId ?? originalObject.id.NotNull(); - if (_colorBaker.ObjectColorsIdMap.TryGetValue(objId, out AutocadColor? color)) ->>>>>>> dev + if (colorBaker.ObjectColorsIdMap.TryGetValue(objId, out AutocadColor? color)) { entity.Color = color; } diff --git a/Connectors/CSi/Speckle.Connectors.CSiShared/Operations/Send/CSiRootObjectBuilder.cs b/Connectors/CSi/Speckle.Connectors.CSiShared/Operations/Send/CSiRootObjectBuilder.cs index a5cb5c58c..88c64afd2 100644 --- a/Connectors/CSi/Speckle.Connectors.CSiShared/Operations/Send/CSiRootObjectBuilder.cs +++ b/Connectors/CSi/Speckle.Connectors.CSiShared/Operations/Send/CSiRootObjectBuilder.cs @@ -42,11 +42,10 @@ ICSiApplicationService csiApplicationService _csiApplicationService = csiApplicationService; } - public async Task Build( + public RootObjectBuilderResult Build( IReadOnlyList csiObjects, SendInfo sendInfo, - IProgress onOperationProgressed, - CancellationToken cancellationToken = default + IProgress onOperationProgressed ) { using var activity = _activityFactory.Start("Build"); @@ -63,7 +62,6 @@ public async Task Build( foreach (ICSiWrapper csiObject in csiObjects) { using var _2 = _activityFactory.Start("Convert"); - cancellationToken.ThrowIfCancellationRequested(); var result = ConvertCSiObject(csiObject, rootObjectCollection, sendInfo.ProjectId); results.Add(result); @@ -78,7 +76,6 @@ public async Task Build( throw new SpeckleException("Failed to convert all objects."); } - await Task.Yield(); return new RootObjectBuilderResult(rootObjectCollection, results); } diff --git a/Connectors/CSi/Speckle.Connectors.CSiShared/ServiceRegistration.cs b/Connectors/CSi/Speckle.Connectors.CSiShared/ServiceRegistration.cs index 810371abc..ea906c9e9 100644 --- a/Connectors/CSi/Speckle.Connectors.CSiShared/ServiceRegistration.cs +++ b/Connectors/CSi/Speckle.Connectors.CSiShared/ServiceRegistration.cs @@ -1,11 +1,8 @@ using Microsoft.Extensions.DependencyInjection; using Speckle.Connectors.Common; -<<<<<<< HEAD -using Speckle.Connectors.Common.Threading; -======= using Speckle.Connectors.Common.Builders; using Speckle.Connectors.Common.Operations; ->>>>>>> dev +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.CSiShared.Bindings; using Speckle.Connectors.CSiShared.Builders; using Speckle.Connectors.CSiShared.Filters; @@ -13,7 +10,6 @@ using Speckle.Connectors.DUI; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; -using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Connectors.DUI.WebView; using Speckle.Converters.CSiShared; @@ -28,15 +24,9 @@ public static IServiceCollection AddCSi(this IServiceCollection services) services.AddSingleton(); services.AddConnectorUtils(); -<<<<<<< HEAD - services.AddDUI(); -======= - services.AddDUI(); ->>>>>>> dev + services.AddDUI(); services.AddDUIView(); - services.AddSingleton(); - services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs index ac1ead967..f44c230d0 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs @@ -34,69 +34,13 @@ public sealed class RevitHostObjectBuilder( RootObjectUnpacker rootObjectUnpacker, ILogger logger, RevitToHostCacheSingleton revitToHostCacheSingleton, - ITypedConverter<(Base atomicObject, List matrix), DirectShape> localToGlobalDirectShapeConverter + ITypedConverter< + (Base atomicObject, IReadOnlyCollection matrix), + DirectShape + > localToGlobalDirectShapeConverter ) : IHostObjectBuilder, IDisposable { -<<<<<<< HEAD public HostObjectBuilderResult Build( -======= - private readonly IRootToHostConverter _converter; - private readonly IConverterSettingsStore _converterSettings; - private readonly RevitToHostCacheSingleton _revitToHostCacheSingleton; - private readonly ITransactionManager _transactionManager; - private readonly ILocalToGlobalUnpacker _localToGlobalUnpacker; - private readonly RevitGroupBaker _groupBaker; - private readonly RevitMaterialBaker _materialBaker; - private readonly ILogger _logger; - private readonly ITypedConverter< - (Base atomicObject, IReadOnlyCollection matrix), - DirectShape - > _localToGlobalDirectShapeConverter; - - private readonly RootObjectUnpacker _rootObjectUnpacker; - private readonly ISdkActivityFactory _activityFactory; - - public RevitHostObjectBuilder( - IRootToHostConverter converter, - IConverterSettingsStore converterSettings, - ITransactionManager transactionManager, - ISdkActivityFactory activityFactory, - ILocalToGlobalUnpacker localToGlobalUnpacker, - RevitGroupBaker groupManager, - RevitMaterialBaker materialBaker, - RootObjectUnpacker rootObjectUnpacker, - ILogger logger, - RevitToHostCacheSingleton revitToHostCacheSingleton, - ITypedConverter< - (Base atomicObject, IReadOnlyCollection matrix), - DirectShape - > localToGlobalDirectShapeConverter - ) - { - _converter = converter; - _converterSettings = converterSettings; - _transactionManager = transactionManager; - _localToGlobalUnpacker = localToGlobalUnpacker; - _groupBaker = groupManager; - _materialBaker = materialBaker; - _rootObjectUnpacker = rootObjectUnpacker; - _logger = logger; - _revitToHostCacheSingleton = revitToHostCacheSingleton; - _localToGlobalDirectShapeConverter = localToGlobalDirectShapeConverter; - _activityFactory = activityFactory; - } - - public Task Build( - Base rootObject, - string projectName, - string modelName, - IProgress onOperationProgressed, - CancellationToken cancellationToken - ) => - RevitTask.RunAsync(() => BuildSync(rootObject, projectName, modelName, onOperationProgressed, cancellationToken)); - - private HostObjectBuilderResult BuildSync( ->>>>>>> dev Base rootObject, string projectName, string modelName, From caac2a78e6cbc844db56e21eb4fa2da90d69aa2b Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 3 Dec 2024 17:07:04 +0000 Subject: [PATCH 50/65] Use valuetask --- .../Utils/ArcGISThreadContext.cs | 14 ++++---- .../Utils/ArcGisDocumentStore.cs | 4 +-- .../Bindings/AutocadSelectionBinding.cs | 2 +- .../Plugin/RevitThreadContext.cs | 8 ++--- .../Receive/RhinoHostObjectBuilder.cs | 14 ++++---- .../Bridge/BrowserBridge.cs | 2 +- .../Operations/ReceiveOperation.cs | 2 +- .../Operations/SendOperation.cs | 2 +- .../Threading/DefaultThreadContext.cs | 18 +++++----- .../Threading/ThreadContext.cs | 33 +++++++++---------- .../Threading/ThreadContextExtensions.cs | 16 ++++----- .../Threading/Yield.cs | 12 ++++++- 12 files changed, 69 insertions(+), 58 deletions(-) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs index 3741d2c8d..dee64e930 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs @@ -6,7 +6,7 @@ namespace Speckle.Connectors.ArcGIS.Utils; //don't check for GUI as it's the same check we do in ThreadContext public class ArcGISThreadContext : ThreadContext { - protected override Task MainToWorkerAsync(Func> action) + protected override ValueTask MainToWorkerAsync(Func> action) { if (QueuedTask.OnWorker) { @@ -14,23 +14,23 @@ protected override Task MainToWorkerAsync(Func> action) } else { - return QueuedTask.Run(action); + return QueuedTask.Run(async() => await action().BackToCurrent()).AsValueTask(); } } - protected override Task WorkerToMainAsync(Func> action) => QueuedTask.Run(action); + protected override ValueTask WorkerToMainAsync(Func> action) => QueuedTask.Run(async() => await action().BackToCurrent()).AsValueTask(); - protected override Task MainToWorker(Func action) + protected override ValueTask MainToWorker(Func action) { if (QueuedTask.OnWorker) { - return Task.FromResult(action()); + return new(action()); } else { - return QueuedTask.Run(action); + return QueuedTask.Run(action).AsValueTask(); } } - protected override Task WorkerToMain(Func action) => QueuedTask.Run(action); + protected override ValueTask WorkerToMain(Func action) => QueuedTask.Run(action).AsValueTask(); } diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs index ad44f657f..5a39736f2 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs @@ -107,7 +107,7 @@ protected override void HostAppSaveState(string modelCardState) => } map.SetMetadata(existingXmlDocument.ToString()); - }); + }).Wait(); protected override void LoadState() => _threadContext.RunOnWorker(() => @@ -124,5 +124,5 @@ protected override void LoadState() => string modelsString = element.Value; LoadFromString(modelsString); - }); + }).Wait(); } diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs index 0af057595..6ccf1cfc3 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs @@ -57,7 +57,7 @@ private void TryRegisterDocumentForSelection(Document? document) // Ui requests to GetSelection() should just return this local copy that is kept up to date by the event handler. private SelectionInfo _selectionInfo; - private async Task OnSelectionChanged() + private async ValueTask OnSelectionChanged() { _selectionInfo = GetSelectionInternal(); await Parent.Send(SELECTION_EVENT, _selectionInfo).ConfigureAwait(false); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs index 2d53d1ada..b4cc76319 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs @@ -5,11 +5,11 @@ namespace Speckle.Connectors.Revit.Plugin; public class RevitThreadContext : ThreadContext { - protected override Task MainToWorkerAsync(Func> action) => action(); + protected override ValueTask MainToWorkerAsync(Func> action) => action(); - protected override Task WorkerToMainAsync(Func> action) => RevitTask.RunAsync(action); + protected override ValueTask WorkerToMainAsync(Func> action) => RevitTask.RunAsync(async () => await action().BackToCurrent()).AsValueTask(); - protected override Task MainToWorker(Func action) => Task.FromResult(action()); + protected override ValueTask MainToWorker(Func action) => new(action()); - protected override Task WorkerToMain(Func action) => RevitTask.RunAsync(action); + protected override ValueTask WorkerToMain(Func action) => new(RevitTask.RunAsync(action)); } diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs index 3fa233bd5..b2de7b1d7 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs @@ -6,6 +6,7 @@ using Speckle.Connectors.Common.Extensions; using Speckle.Connectors.Common.Operations; using Speckle.Connectors.Common.Operations.Receive; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.Rhino.HostApp; using Speckle.Converters.Common; using Speckle.Converters.Rhino; @@ -32,6 +33,7 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder private readonly RhinoGroupBaker _groupBaker; private readonly RootObjectUnpacker _rootObjectUnpacker; private readonly ISdkActivityFactory _activityFactory; + private readonly IThreadContext _threadContext; public RhinoHostObjectBuilder( IRootToHostConverter converter, @@ -42,8 +44,7 @@ public RhinoHostObjectBuilder( RhinoMaterialBaker materialBaker, RhinoColorBaker colorBaker, RhinoGroupBaker groupBaker, - ISdkActivityFactory activityFactory - ) + ISdkActivityFactory activityFactory, IThreadContext threadContext) { _converter = converter; _converterSettings = converterSettings; @@ -54,6 +55,7 @@ ISdkActivityFactory activityFactory _layerBaker = layerBaker; _groupBaker = groupBaker; _activityFactory = activityFactory; + _threadContext = threadContext; } #pragma warning disable CA1506 @@ -113,13 +115,13 @@ CancellationToken cancellationToken using (var _ = _activityFactory.Start("Pre baking layers")) { //TODO what is this? This is going to the UI thread - RhinoApp.InvokeAndWait(() => + _threadContext.RunOnMain(() => { using var layerNoDraw = new DisableRedrawScope(_converterSettings.Current.Document.Views); var paths = atomicObjectsWithoutInstanceComponentsWithPath.Select(t => t.path).ToList(); paths.AddRange(instanceComponentsWithPath.Select(t => t.path)); _layerBaker.CreateAllLayersForReceive(paths, baseLayerName); - }); + }).Wait(); } // 5 - Convert atomic objects @@ -243,7 +245,7 @@ private void PreReceiveDeepClean(string baseLayerName) RhinoMath.UnsetIntIndex ); - RhinoApp.InvokeAndWait(() => + _threadContext.RunOnMain(() => { _instanceBaker.PurgeInstances(baseLayerName); _materialBaker.PurgeMaterials(baseLayerName); @@ -271,7 +273,7 @@ private void PreReceiveDeepClean(string baseLayerName) // Cleans up any previously received group _groupBaker.PurgeGroups(baseLayerName); - }); + }).Wait(); } /// diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 9249aa255..e46774eec 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -123,7 +123,7 @@ public void RunMethod(string methodName, string requestId, string methodArgs) => } }, _threadOptions.RunCommandsOnMainThread - ); + ).Wait(); /// /// Used by the action block to invoke the actual method called by the UI. diff --git a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs index c33cd74af..4ba8d2708 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs @@ -56,7 +56,7 @@ await apiClient return res; } - private async Task ReceiveData( + private async ValueTask ReceiveData( Account account, Speckle.Sdk.Api.GraphQL.Models.Version version, ReceiveInfo receiveInfo, diff --git a/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs b/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs index 414a75168..60e9bda7b 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs @@ -48,7 +48,7 @@ public async Task Execute( return new(rootObjId, convertedReferences, buildResult.ConversionResults); } - public async Task Send( + public async ValueTask Send( Base commitObject, SendInfo sendInfo, IProgress onOperationProgressed, diff --git a/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs b/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs index 9b4f89ab5..6509eb3c7 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs @@ -10,7 +10,7 @@ public class DefaultThreadContext : ThreadContext ); [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] - protected override Task WorkerToMainAsync(Func> action) + protected override ValueTask WorkerToMainAsync(Func> action) { TaskCompletionSource tcs = new(); _threadContext.Post( @@ -28,17 +28,17 @@ protected override Task WorkerToMainAsync(Func> action) }, null ); - return tcs.Task; + return new ValueTask(tcs.Task); } - protected override Task MainToWorkerAsync(Func> action) + protected override ValueTask MainToWorkerAsync(Func> action) { - Task> f = Task.Factory.StartNew(action, default, TaskCreationOptions.LongRunning, TaskScheduler.Default); - return f.Unwrap(); + Task> f = Task.Factory.StartNew(async () => await action().BackToCurrent(), default, TaskCreationOptions.LongRunning, TaskScheduler.Default); + return new ValueTask(f.Unwrap()); } [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "TaskCompletionSource")] - protected override Task WorkerToMain(Func action) + protected override ValueTask WorkerToMain(Func action) { TaskCompletionSource tcs = new(); _threadContext.Post( @@ -56,12 +56,12 @@ protected override Task WorkerToMain(Func action) }, null ); - return tcs.Task; + return new ValueTask(tcs.Task); } - protected override Task MainToWorker(Func action) + protected override ValueTask MainToWorker(Func action) { Task f = Task.Factory.StartNew(action, default, TaskCreationOptions.LongRunning, TaskScheduler.Default); - return f; + return new ValueTask(f); } } diff --git a/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs b/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs index 612c02324..42c44d01c 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs @@ -5,11 +5,11 @@ namespace Speckle.Connectors.Common.Threading; [GenerateAutoInterface] public abstract class ThreadContext : IThreadContext { - private static readonly Task s_completedTask = Task.FromResult(null); + public static bool IsMainThread => Environment.CurrentManagedThreadId == 1 && !Thread.CurrentThread.IsBackground; - public async Task RunOnThread(Action action, bool useMain) + public async ValueTask RunOnThread(Action action, bool useMain) { if (useMain) { @@ -22,7 +22,7 @@ public async Task RunOnThread(Action action, bool useMain) await WorkerToMainAsync(() => { action(); - return s_completedTask; + return new ValueTask(); }) .ConfigureAwait(false); } @@ -34,7 +34,7 @@ await WorkerToMainAsync(() => await MainToWorkerAsync(() => { action(); - return s_completedTask; + return new ValueTask(); }) .BackToAny(); } @@ -45,13 +45,13 @@ await MainToWorkerAsync(() => } } - public virtual Task RunOnThread(Func action, bool useMain) + public virtual ValueTask RunOnThread(Func action, bool useMain) { if (useMain) { if (IsMainThread) { - return Task.FromResult(action()); + return new ValueTask(action()); } return WorkerToMain(action); @@ -61,10 +61,10 @@ public virtual Task RunOnThread(Func action, bool useMain) return MainToWorker(action); } - return Task.FromResult(action()); + return new ValueTask(action()); } - public async Task RunOnThreadAsync(Func action, bool useMain) + public async ValueTask RunOnThreadAsync(Func action, bool useMain) { if (useMain) { @@ -77,7 +77,7 @@ public async Task RunOnThreadAsync(Func action, bool useMain) await WorkerToMainAsync(async () => { await action().BackToCurrent(); - return null; + return new ValueTask(null); }) .BackToCurrent(); } @@ -88,8 +88,8 @@ public async Task RunOnThreadAsync(Func action, bool useMain) { await MainToWorkerAsync(async () => { - await action().BackToCurrent(); - return null; + await action().BackToCurrent(); + return new ValueTask(null); }) .BackToCurrent(); } @@ -100,7 +100,7 @@ public async Task RunOnThreadAsync(Func action, bool useMain) } } - public Task RunOnThreadAsync(Func> action, bool useMain) + public ValueTask RunOnThreadAsync(Func> action, bool useMain) { if (useMain) { @@ -117,11 +117,10 @@ public Task RunOnThreadAsync(Func> action, bool useMain) } return action(); } + protected abstract ValueTask WorkerToMainAsync(Func> action); - protected abstract Task WorkerToMainAsync(Func> action); - - protected abstract Task MainToWorkerAsync(Func> action); - protected abstract Task WorkerToMain(Func action); + protected abstract ValueTask MainToWorkerAsync(Func> action); + protected abstract ValueTask WorkerToMain(Func action); - protected abstract Task MainToWorker(Func action); + protected abstract ValueTask MainToWorker(Func action); } diff --git a/Sdk/Speckle.Connectors.Common/Threading/ThreadContextExtensions.cs b/Sdk/Speckle.Connectors.Common/Threading/ThreadContextExtensions.cs index ddf29854c..f2c915d47 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/ThreadContextExtensions.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/ThreadContextExtensions.cs @@ -2,27 +2,27 @@ public static class ThreadContextExtensions { - public static void RunOnMain(this IThreadContext threadContext, Action action) => + public static ValueTask RunOnMain(this IThreadContext threadContext, Action action) => threadContext.RunOnThread(action, true); - public static void RunOnWorker(this IThreadContext threadContext, Action action) => + public static ValueTask RunOnWorker(this IThreadContext threadContext, Action action) => threadContext.RunOnThread(action, false); - public static Task RunOnMain(this IThreadContext threadContext, Func action) => + public static ValueTask RunOnMain(this IThreadContext threadContext, Func action) => threadContext.RunOnThread(action, true); - public static Task RunOnWorker(this IThreadContext threadContext, Func action) => + public static ValueTask RunOnWorker(this IThreadContext threadContext, Func action) => threadContext.RunOnThread(action, false); - public static Task RunOnMainAsync(this IThreadContext threadContext, Func action) => + public static ValueTask RunOnMainAsync(this IThreadContext threadContext, Func action) => threadContext.RunOnThreadAsync(action, true); - public static Task RunOnWorkerAsync(this IThreadContext threadContext, Func action) => + public static ValueTask RunOnWorkerAsync(this IThreadContext threadContext, Func action) => threadContext.RunOnThreadAsync(action, false); - public static Task RunOnMainAsync(this IThreadContext threadContext, Func> action) => + public static ValueTask RunOnMainAsync(this IThreadContext threadContext, Func> action) => threadContext.RunOnThreadAsync(action, true); - public static Task RunOnWorkerAsync(this IThreadContext threadContext, Func> action) => + public static ValueTask RunOnWorkerAsync(this IThreadContext threadContext, Func> action) => threadContext.RunOnThreadAsync(action, false); } diff --git a/Sdk/Speckle.Connectors.Common/Threading/Yield.cs b/Sdk/Speckle.Connectors.Common/Threading/Yield.cs index 6477a7b01..d1437dc94 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/Yield.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/Yield.cs @@ -2,8 +2,11 @@ namespace Speckle.Connectors.Common.Threading; -public static class Yield +public static class TaskExtensions { + public static ConfiguredValueTaskAwaitable BackToCurrent (this ValueTask valueTask) => valueTask.ConfigureAwait(true); + + public static ConfiguredValueTaskAwaitable BackToAny(this ValueTask valueTask) => valueTask.ConfigureAwait(false); public static ConfiguredValueTaskAwaitable BackToCurrent(this ValueTask valueTask) => valueTask.ConfigureAwait(true); public static ConfiguredValueTaskAwaitable BackToAny(this ValueTask valueTask) => valueTask.ConfigureAwait(false); @@ -15,4 +18,11 @@ public static class Yield public static ConfiguredTaskAwaitable BackToCurrent(this Task task) => task.ConfigureAwait(true); public static ConfiguredTaskAwaitable BackToAny(this Task task) => task.ConfigureAwait(false); + + public static ValueTask AsValueTask(this Task task) => new(task); + public static ValueTask AsValueTask(this Task task) => new(task); + public static void Wait(this Task task) => task.GetAwaiter().GetResult(); + public static T Wait(this Task task) => task.GetAwaiter().GetResult(); + public static void Wait(this ValueTask task) => task.GetAwaiter().GetResult(); + public static T Wait(this ValueTask task) => task.GetAwaiter().GetResult(); } From 1ea4acbb0d16acfef919c5c16ac4fb49a63162fa Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 3 Dec 2024 17:07:25 +0000 Subject: [PATCH 51/65] fmt --- .../Utils/ArcGISThreadContext.cs | 5 +- .../Utils/ArcGisDocumentStore.cs | 82 ++++++++++--------- .../Plugin/RevitThreadContext.cs | 3 +- .../Receive/RhinoHostObjectBuilder.cs | 64 ++++++++------- .../Bridge/BrowserBridge.cs | 36 ++++---- .../Threading/DefaultThreadContext.cs | 7 +- .../Threading/ThreadContext.cs | 5 +- .../Threading/Yield.cs | 14 +++- 8 files changed, 121 insertions(+), 95 deletions(-) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs index dee64e930..112ef1448 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs @@ -14,11 +14,12 @@ protected override ValueTask MainToWorkerAsync(Func> action) } else { - return QueuedTask.Run(async() => await action().BackToCurrent()).AsValueTask(); + return QueuedTask.Run(async () => await action().BackToCurrent()).AsValueTask(); } } - protected override ValueTask WorkerToMainAsync(Func> action) => QueuedTask.Run(async() => await action().BackToCurrent()).AsValueTask(); + protected override ValueTask WorkerToMainAsync(Func> action) => + QueuedTask.Run(async () => await action().BackToCurrent()).AsValueTask(); protected override ValueTask MainToWorker(Func action) { diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs index 5a39736f2..0dd2e7abe 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs @@ -82,47 +82,51 @@ private void OnMapViewChanged(ActiveMapViewChangedEventArgs args) } protected override void HostAppSaveState(string modelCardState) => - _threadContext.RunOnWorker(() => - { - Map map = MapView.Active.Map; - // Read existing metadata - To prevent messing existing metadata. 🤞 Hope other add-in developers will do same :D - var existingMetadata = map.GetMetadata(); - - // Parse existing metadata - XDocument existingXmlDocument = !string.IsNullOrEmpty(existingMetadata) - ? XDocument.Parse(existingMetadata) - : new XDocument(new XElement("metadata")); - - XElement xmlModelCards = new("SpeckleModelCards", modelCardState); - - // Check if SpeckleModelCards element already exists at root and update it - var speckleModelCardsElement = existingXmlDocument.Root?.Element("SpeckleModelCards"); - if (speckleModelCardsElement != null) + _threadContext + .RunOnWorker(() => { - speckleModelCardsElement.ReplaceWith(xmlModelCards); - } - else - { - existingXmlDocument.Root?.Add(xmlModelCards); - } - - map.SetMetadata(existingXmlDocument.ToString()); - }).Wait(); + Map map = MapView.Active.Map; + // Read existing metadata - To prevent messing existing metadata. 🤞 Hope other add-in developers will do same :D + var existingMetadata = map.GetMetadata(); + + // Parse existing metadata + XDocument existingXmlDocument = !string.IsNullOrEmpty(existingMetadata) + ? XDocument.Parse(existingMetadata) + : new XDocument(new XElement("metadata")); + + XElement xmlModelCards = new("SpeckleModelCards", modelCardState); + + // Check if SpeckleModelCards element already exists at root and update it + var speckleModelCardsElement = existingXmlDocument.Root?.Element("SpeckleModelCards"); + if (speckleModelCardsElement != null) + { + speckleModelCardsElement.ReplaceWith(xmlModelCards); + } + else + { + existingXmlDocument.Root?.Add(xmlModelCards); + } + + map.SetMetadata(existingXmlDocument.ToString()); + }) + .Wait(); protected override void LoadState() => - _threadContext.RunOnWorker(() => - { - Map map = MapView.Active.Map; - var metadata = map.GetMetadata(); - var root = XDocument.Parse(metadata).Root; - var element = root?.Element("SpeckleModelCards"); - if (element is null) + _threadContext + .RunOnWorker(() => { - ClearAndSave(); - return; - } - - string modelsString = element.Value; - LoadFromString(modelsString); - }).Wait(); + Map map = MapView.Active.Map; + var metadata = map.GetMetadata(); + var root = XDocument.Parse(metadata).Root; + var element = root?.Element("SpeckleModelCards"); + if (element is null) + { + ClearAndSave(); + return; + } + + string modelsString = element.Value; + LoadFromString(modelsString); + }) + .Wait(); } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs index b4cc76319..92dd7d521 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs @@ -7,7 +7,8 @@ public class RevitThreadContext : ThreadContext { protected override ValueTask MainToWorkerAsync(Func> action) => action(); - protected override ValueTask WorkerToMainAsync(Func> action) => RevitTask.RunAsync(async () => await action().BackToCurrent()).AsValueTask(); + protected override ValueTask WorkerToMainAsync(Func> action) => + RevitTask.RunAsync(async () => await action().BackToCurrent()).AsValueTask(); protected override ValueTask MainToWorker(Func action) => new(action()); diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs index b2de7b1d7..1a42a4dfb 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs @@ -44,7 +44,9 @@ public RhinoHostObjectBuilder( RhinoMaterialBaker materialBaker, RhinoColorBaker colorBaker, RhinoGroupBaker groupBaker, - ISdkActivityFactory activityFactory, IThreadContext threadContext) + ISdkActivityFactory activityFactory, + IThreadContext threadContext + ) { _converter = converter; _converterSettings = converterSettings; @@ -115,13 +117,15 @@ CancellationToken cancellationToken using (var _ = _activityFactory.Start("Pre baking layers")) { //TODO what is this? This is going to the UI thread - _threadContext.RunOnMain(() => - { - using var layerNoDraw = new DisableRedrawScope(_converterSettings.Current.Document.Views); - var paths = atomicObjectsWithoutInstanceComponentsWithPath.Select(t => t.path).ToList(); - paths.AddRange(instanceComponentsWithPath.Select(t => t.path)); - _layerBaker.CreateAllLayersForReceive(paths, baseLayerName); - }).Wait(); + _threadContext + .RunOnMain(() => + { + using var layerNoDraw = new DisableRedrawScope(_converterSettings.Current.Document.Views); + var paths = atomicObjectsWithoutInstanceComponentsWithPath.Select(t => t.path).ToList(); + paths.AddRange(instanceComponentsWithPath.Select(t => t.path)); + _layerBaker.CreateAllLayersForReceive(paths, baseLayerName); + }) + .Wait(); } // 5 - Convert atomic objects @@ -245,35 +249,37 @@ private void PreReceiveDeepClean(string baseLayerName) RhinoMath.UnsetIntIndex ); - _threadContext.RunOnMain(() => - { - _instanceBaker.PurgeInstances(baseLayerName); - _materialBaker.PurgeMaterials(baseLayerName); - - var doc = _converterSettings.Current.Document; - // Cleans up any previously received objects - if (rootLayerIndex != RhinoMath.UnsetIntIndex) + _threadContext + .RunOnMain(() => { - var documentLayer = doc.Layers[rootLayerIndex]; - var childLayers = documentLayer.GetChildren(); - if (childLayers != null) + _instanceBaker.PurgeInstances(baseLayerName); + _materialBaker.PurgeMaterials(baseLayerName); + + var doc = _converterSettings.Current.Document; + // Cleans up any previously received objects + if (rootLayerIndex != RhinoMath.UnsetIntIndex) { - using var layerNoDraw = new DisableRedrawScope(doc.Views); - foreach (var layer in childLayers) + var documentLayer = doc.Layers[rootLayerIndex]; + var childLayers = documentLayer.GetChildren(); + if (childLayers != null) { - var purgeSuccess = doc.Layers.Purge(layer.Index, true); - if (!purgeSuccess) + using var layerNoDraw = new DisableRedrawScope(doc.Views); + foreach (var layer in childLayers) { - Console.WriteLine($"Failed to purge layer: {layer}"); + var purgeSuccess = doc.Layers.Purge(layer.Index, true); + if (!purgeSuccess) + { + Console.WriteLine($"Failed to purge layer: {layer}"); + } } } + doc.Layers.Purge(documentLayer.Index, true); } - doc.Layers.Purge(documentLayer.Index, true); - } - // Cleans up any previously received group - _groupBaker.PurgeGroups(baseLayerName); - }).Wait(); + // Cleans up any previously received group + _groupBaker.PurgeGroups(baseLayerName); + }) + .Wait(); } /// diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index e46774eec..69562d9af 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -105,25 +105,27 @@ public string[] GetBindingsMethodNames() } public void RunMethod(string methodName, string requestId, string methodArgs) => - _threadContext.RunOnThreadAsync( - async () => - { - var task = await TopLevelExceptionHandler - .CatchUnhandledAsync(async () => + _threadContext + .RunOnThreadAsync( + async () => + { + var task = await TopLevelExceptionHandler + .CatchUnhandledAsync(async () => + { + var result = await ExecuteMethod(methodName, methodArgs).ConfigureAwait(false); + string resultJson = _jsonSerializer.Serialize(result); + await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); + }) + .ConfigureAwait(false); + if (task.Exception is not null) { - var result = await ExecuteMethod(methodName, methodArgs).ConfigureAwait(false); - string resultJson = _jsonSerializer.Serialize(result); + string resultJson = SerializeFormattedException(task.Exception); await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); - }) - .ConfigureAwait(false); - if (task.Exception is not null) - { - string resultJson = SerializeFormattedException(task.Exception); - await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); - } - }, - _threadOptions.RunCommandsOnMainThread - ).Wait(); + } + }, + _threadOptions.RunCommandsOnMainThread + ) + .Wait(); /// /// Used by the action block to invoke the actual method called by the UI. diff --git a/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs b/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs index 6509eb3c7..29057f544 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs @@ -33,7 +33,12 @@ protected override ValueTask WorkerToMainAsync(Func> action) protected override ValueTask MainToWorkerAsync(Func> action) { - Task> f = Task.Factory.StartNew(async () => await action().BackToCurrent(), default, TaskCreationOptions.LongRunning, TaskScheduler.Default); + Task> f = Task.Factory.StartNew( + async () => await action().BackToCurrent(), + default, + TaskCreationOptions.LongRunning, + TaskScheduler.Default + ); return new ValueTask(f.Unwrap()); } diff --git a/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs b/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs index 42c44d01c..459f0285d 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs @@ -5,8 +5,6 @@ namespace Speckle.Connectors.Common.Threading; [GenerateAutoInterface] public abstract class ThreadContext : IThreadContext { - - public static bool IsMainThread => Environment.CurrentManagedThreadId == 1 && !Thread.CurrentThread.IsBackground; public async ValueTask RunOnThread(Action action, bool useMain) @@ -88,7 +86,7 @@ public async ValueTask RunOnThreadAsync(Func action, bool useMain) { await MainToWorkerAsync(async () => { - await action().BackToCurrent(); + await action().BackToCurrent(); return new ValueTask(null); }) .BackToCurrent(); @@ -117,6 +115,7 @@ public ValueTask RunOnThreadAsync(Func> action, bool useMain) } return action(); } + protected abstract ValueTask WorkerToMainAsync(Func> action); protected abstract ValueTask MainToWorkerAsync(Func> action); diff --git a/Sdk/Speckle.Connectors.Common/Threading/Yield.cs b/Sdk/Speckle.Connectors.Common/Threading/Yield.cs index d1437dc94..e2215ad7b 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/Yield.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/Yield.cs @@ -4,9 +4,12 @@ namespace Speckle.Connectors.Common.Threading; public static class TaskExtensions { - public static ConfiguredValueTaskAwaitable BackToCurrent (this ValueTask valueTask) => valueTask.ConfigureAwait(true); + public static ConfiguredValueTaskAwaitable BackToCurrent(this ValueTask valueTask) => + valueTask.ConfigureAwait(true); + + public static ConfiguredValueTaskAwaitable BackToAny(this ValueTask valueTask) => + valueTask.ConfigureAwait(false); - public static ConfiguredValueTaskAwaitable BackToAny(this ValueTask valueTask) => valueTask.ConfigureAwait(false); public static ConfiguredValueTaskAwaitable BackToCurrent(this ValueTask valueTask) => valueTask.ConfigureAwait(true); public static ConfiguredValueTaskAwaitable BackToAny(this ValueTask valueTask) => valueTask.ConfigureAwait(false); @@ -18,11 +21,16 @@ public static class TaskExtensions public static ConfiguredTaskAwaitable BackToCurrent(this Task task) => task.ConfigureAwait(true); public static ConfiguredTaskAwaitable BackToAny(this Task task) => task.ConfigureAwait(false); - + public static ValueTask AsValueTask(this Task task) => new(task); + public static ValueTask AsValueTask(this Task task) => new(task); + public static void Wait(this Task task) => task.GetAwaiter().GetResult(); + public static T Wait(this Task task) => task.GetAwaiter().GetResult(); + public static void Wait(this ValueTask task) => task.GetAwaiter().GetResult(); + public static T Wait(this ValueTask task) => task.GetAwaiter().GetResult(); } From 027b0cc34373aa52595647affdfa02cc81275a57 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 3 Dec 2024 17:24:28 +0000 Subject: [PATCH 52/65] fix up some bridge execution to be sync --- .../CefSharpPanel.xaml.cs | 10 ++----- .../DUI3ControlWebView.xaml.cs | 3 +-- .../Bridge/BrowserBridge.cs | 27 +++++++++---------- .../Bridge/IBrowserScriptExecutor.cs | 2 +- 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared.Cef/CefSharpPanel.xaml.cs b/Connectors/Revit/Speckle.Connectors.RevitShared.Cef/CefSharpPanel.xaml.cs index ae78681ed..0f2c587b2 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared.Cef/CefSharpPanel.xaml.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared.Cef/CefSharpPanel.xaml.cs @@ -13,15 +13,9 @@ public CefSharpPanel() InitializeComponent(); } - public Task ExecuteScriptAsyncMethod(string script, CancellationToken cancellationToken) + public void ExecuteScriptAsync(string script) { - Browser.Dispatcher.Invoke( - () => Browser.ExecuteScriptAsync(script), - DispatcherPriority.Background, - cancellationToken - ); - - return Task.CompletedTask; + Browser.Dispatcher.Invoke(() => Browser.ExecuteScriptAsync(script), DispatcherPriority.Background); } public bool IsBrowserInitialized => Browser.IsBrowserInitialized; diff --git a/DUI3/Speckle.Connectors.DUI.WebView/DUI3ControlWebView.xaml.cs b/DUI3/Speckle.Connectors.DUI.WebView/DUI3ControlWebView.xaml.cs index c401a3289..5bd6d83b6 100644 --- a/DUI3/Speckle.Connectors.DUI.WebView/DUI3ControlWebView.xaml.cs +++ b/DUI3/Speckle.Connectors.DUI.WebView/DUI3ControlWebView.xaml.cs @@ -26,7 +26,7 @@ public DUI3ControlWebView(IServiceProvider serviceProvider) public object BrowserElement => Browser; - public Task ExecuteScriptAsyncMethod(string script, CancellationToken cancellationToken) + public void ExecuteScriptAsync(string script) { if (!Browser.IsInitialized) { @@ -39,7 +39,6 @@ public Task ExecuteScriptAsyncMethod(string script, CancellationToken cancellati () => Browser.ExecuteScriptAsync(script), DispatcherPriority.Background ); - return Task.CompletedTask; } private void OnInitialized(object? sender, CoreWebView2InitializationCompletedEventArgs e) diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 69562d9af..ca8734e22 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -104,6 +104,7 @@ public string[] GetBindingsMethodNames() return bindingNames; } + //don't wait for browser runs on purpose public void RunMethod(string methodName, string requestId, string methodArgs) => _threadContext .RunOnThreadAsync( @@ -114,18 +115,18 @@ public void RunMethod(string methodName, string requestId, string methodArgs) => { var result = await ExecuteMethod(methodName, methodArgs).ConfigureAwait(false); string resultJson = _jsonSerializer.Serialize(result); - await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); + NotifyUIMethodCallResultReady(requestId, resultJson); }) .ConfigureAwait(false); if (task.Exception is not null) { string resultJson = SerializeFormattedException(task.Exception); - await NotifyUIMethodCallResultReady(requestId, resultJson).ConfigureAwait(false); + NotifyUIMethodCallResultReady(requestId, resultJson); } }, _threadOptions.RunCommandsOnMainThread ) - .Wait(); + .BackToAny(); /// /// Used by the action block to invoke the actual method called by the UI. @@ -217,16 +218,12 @@ private string SerializeFormattedException(Exception e) /// /// /// - /// - private async Task NotifyUIMethodCallResultReady( - string requestId, - string? serializedData = null, - CancellationToken cancellationToken = default - ) + /// + private void NotifyUIMethodCallResultReady(string requestId, string? serializedData = null) { _resultsStore[requestId] = serializedData; string script = $"{FrontendBoundName}.responseReady('{requestId}')"; - await _browserScriptExecutor.ExecuteScriptAsyncMethod(script, cancellationToken).ConfigureAwait(false); + _browserScriptExecutor.ExecuteScriptAsync(script); } /// @@ -260,7 +257,7 @@ public void OpenUrl(string url) Process.Start(new ProcessStartInfo { FileName = url, UseShellExecute = true }); } - public async Task Send(string eventName, CancellationToken cancellationToken = default) + public Task Send(string eventName, CancellationToken cancellationToken = default) { if (_binding is null) { @@ -269,10 +266,11 @@ public async Task Send(string eventName, CancellationToken cancellationToken = d var script = $"{FrontendBoundName}.emit('{eventName}')"; - await _browserScriptExecutor.ExecuteScriptAsyncMethod(script, cancellationToken).ConfigureAwait(false); + _browserScriptExecutor.ExecuteScriptAsync(script); + return Task.CompletedTask; } - public async Task Send(string eventName, T data, CancellationToken cancellationToken = default) + public Task Send(string eventName, T data, CancellationToken cancellationToken = default) where T : class { if (_binding is null) @@ -284,6 +282,7 @@ public async Task Send(string eventName, T data, CancellationToken cancellati string requestId = $"{Guid.NewGuid()}_{eventName}"; _resultsStore[requestId] = payload; var script = $"{FrontendBoundName}.emitResponseReady('{eventName}', '{requestId}')"; - await _browserScriptExecutor.ExecuteScriptAsyncMethod(script, cancellationToken).ConfigureAwait(false); + _browserScriptExecutor.ExecuteScriptAsync(script); + return Task.CompletedTask; } } diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserScriptExecutor.cs b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserScriptExecutor.cs index 6c3fb69f9..f84658df2 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserScriptExecutor.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserScriptExecutor.cs @@ -4,7 +4,7 @@ public interface IBrowserScriptExecutor { /// thrown when is /// The (constant string) script to execute on the browser - public Task ExecuteScriptAsyncMethod(string script, CancellationToken cancellationToken); + public void ExecuteScriptAsync(string script); public bool IsBrowserInitialized { get; } From 7f61d95419cefe0a985a08656d2b54dcd1870440 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Wed, 4 Dec 2024 08:33:31 +0000 Subject: [PATCH 53/65] cleanup --- .../CefSharpPanel.xaml.cs | 2 +- .../DUI3ControlWebView.xaml.cs | 2 +- DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs | 10 +++++----- .../Bridge/IBrowserScriptExecutor.cs | 2 +- .../Threading/{Yield.cs => TaskExtensions.cs} | 3 +++ 5 files changed, 11 insertions(+), 8 deletions(-) rename Sdk/Speckle.Connectors.Common/Threading/{Yield.cs => TaskExtensions.cs} (91%) diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared.Cef/CefSharpPanel.xaml.cs b/Connectors/Revit/Speckle.Connectors.RevitShared.Cef/CefSharpPanel.xaml.cs index 0f2c587b2..98e98c88f 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared.Cef/CefSharpPanel.xaml.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared.Cef/CefSharpPanel.xaml.cs @@ -13,7 +13,7 @@ public CefSharpPanel() InitializeComponent(); } - public void ExecuteScriptAsync(string script) + public void ExecuteScript(string script) { Browser.Dispatcher.Invoke(() => Browser.ExecuteScriptAsync(script), DispatcherPriority.Background); } diff --git a/DUI3/Speckle.Connectors.DUI.WebView/DUI3ControlWebView.xaml.cs b/DUI3/Speckle.Connectors.DUI.WebView/DUI3ControlWebView.xaml.cs index 5bd6d83b6..59307e4bb 100644 --- a/DUI3/Speckle.Connectors.DUI.WebView/DUI3ControlWebView.xaml.cs +++ b/DUI3/Speckle.Connectors.DUI.WebView/DUI3ControlWebView.xaml.cs @@ -26,7 +26,7 @@ public DUI3ControlWebView(IServiceProvider serviceProvider) public object BrowserElement => Browser; - public void ExecuteScriptAsync(string script) + public void ExecuteScript(string script) { if (!Browser.IsInitialized) { diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index ca8734e22..1b2fab072 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -126,7 +126,7 @@ public void RunMethod(string methodName, string requestId, string methodArgs) => }, _threadOptions.RunCommandsOnMainThread ) - .BackToAny(); + .FireAndForget(); /// /// Used by the action block to invoke the actual method called by the UI. @@ -218,12 +218,12 @@ private string SerializeFormattedException(Exception e) /// /// /// - /// + /// private void NotifyUIMethodCallResultReady(string requestId, string? serializedData = null) { _resultsStore[requestId] = serializedData; string script = $"{FrontendBoundName}.responseReady('{requestId}')"; - _browserScriptExecutor.ExecuteScriptAsync(script); + _browserScriptExecutor.ExecuteScript(script); } /// @@ -266,7 +266,7 @@ public Task Send(string eventName, CancellationToken cancellationToken = default var script = $"{FrontendBoundName}.emit('{eventName}')"; - _browserScriptExecutor.ExecuteScriptAsync(script); + _browserScriptExecutor.ExecuteScript(script); return Task.CompletedTask; } @@ -282,7 +282,7 @@ public Task Send(string eventName, T data, CancellationToken cancellationToke string requestId = $"{Guid.NewGuid()}_{eventName}"; _resultsStore[requestId] = payload; var script = $"{FrontendBoundName}.emitResponseReady('{eventName}', '{requestId}')"; - _browserScriptExecutor.ExecuteScriptAsync(script); + _browserScriptExecutor.ExecuteScript(script); return Task.CompletedTask; } } diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserScriptExecutor.cs b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserScriptExecutor.cs index f84658df2..c0979f36c 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserScriptExecutor.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserScriptExecutor.cs @@ -4,7 +4,7 @@ public interface IBrowserScriptExecutor { /// thrown when is /// The (constant string) script to execute on the browser - public void ExecuteScriptAsync(string script); + public void ExecuteScript(string script); public bool IsBrowserInitialized { get; } diff --git a/Sdk/Speckle.Connectors.Common/Threading/Yield.cs b/Sdk/Speckle.Connectors.Common/Threading/TaskExtensions.cs similarity index 91% rename from Sdk/Speckle.Connectors.Common/Threading/Yield.cs rename to Sdk/Speckle.Connectors.Common/Threading/TaskExtensions.cs index e2215ad7b..157ec40ff 100644 --- a/Sdk/Speckle.Connectors.Common/Threading/Yield.cs +++ b/Sdk/Speckle.Connectors.Common/Threading/TaskExtensions.cs @@ -33,4 +33,7 @@ public static ConfiguredValueTaskAwaitable BackToAny(this ValueTask val public static void Wait(this ValueTask task) => task.GetAwaiter().GetResult(); public static T Wait(this ValueTask task) => task.GetAwaiter().GetResult(); +#pragma warning disable CA1030 + public static void FireAndForget(this ValueTask valueTask) => valueTask.BackToAny(); +#pragma warning restore CA1030 } From 7927d5a017d1059db5bc755e4cdeda1b26f6ebfb Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 5 Dec 2024 10:53:00 +0000 Subject: [PATCH 54/65] add some non async paths for progress --- .../Bindings/OperationProgressManager.cs | 27 +++++++++---------- .../Bridge/BrowserBridge.cs | 15 +++++++++++ .../Bridge/IBrowserBridge.cs | 2 ++ .../Bridge/TopLevelExceptionHandler.cs | 15 ++++++----- 4 files changed, 38 insertions(+), 21 deletions(-) diff --git a/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs b/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs index 992aaf669..f53c9d005 100644 --- a/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs +++ b/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs @@ -30,20 +30,19 @@ CancellationToken cancellationToken ) { var progress = new NonUIThreadProgress(args => - bridge.TopLevelExceptionHandler.FireAndForget( - () => - SetModelProgress( - bridge, - modelCardId, - new ModelCardProgress(modelCardId, args.Status, args.Progress), - cancellationToken - ) - ) + { + SetModelProgress( + bridge, + modelCardId, + new ModelCardProgress(modelCardId, args.Status, args.Progress), + cancellationToken + ); + } ); return progress; } - public async Task SetModelProgress( + public void SetModelProgress( IBrowserBridge bridge, string modelCardId, ModelCardProgress progress, @@ -60,7 +59,7 @@ CancellationToken cancellationToken t.Item1 = DateTime.Now; s_lastProgressValues[modelCardId] = (t.Item1, progress.Status); // Since it's the first time we get a call for this model card, we should send it out - await SendProgress(bridge, modelCardId, progress).ConfigureAwait(false); + SendProgress(bridge, modelCardId, progress); return; } @@ -72,9 +71,9 @@ CancellationToken cancellationToken return; } s_lastProgressValues[modelCardId] = (currentTime, progress.Status); - await SendProgress(bridge, modelCardId, progress).ConfigureAwait(false); + SendProgress(bridge, modelCardId, progress); } - private static async Task SendProgress(IBrowserBridge bridge, string modelCardId, ModelCardProgress progress) => - await bridge.Send(SET_MODEL_PROGRESS_UI_COMMAND_NAME, new { modelCardId, progress }).ConfigureAwait(false); + private static void SendProgress(IBrowserBridge bridge, string modelCardId, ModelCardProgress progress) => + bridge.Send2(SET_MODEL_PROGRESS_UI_COMMAND_NAME, new { modelCardId, progress }); } diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 1b2fab072..b99809480 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -285,4 +285,19 @@ public Task Send(string eventName, T data, CancellationToken cancellationToke _browserScriptExecutor.ExecuteScript(script); return Task.CompletedTask; } + + public void Send2(string eventName, T data) + where T : class + { + if (_binding is null) + { + throw new InvalidOperationException("Bridge was not initialized with a binding"); + } + + string payload = _jsonSerializer.Serialize(data); + string requestId = $"{Guid.NewGuid()}_{eventName}"; + _resultsStore[requestId] = payload; + var script = $"{FrontendBoundName}.emitResponseReady('{eventName}', '{requestId}')"; + _browserScriptExecutor.ExecuteScript(script); + } } diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs index f968bf3ef..65ec766df 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs @@ -40,5 +40,7 @@ public interface IBrowserBridge public Task Send(string eventName, T data, CancellationToken cancellationToken = default) where T : class; + 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 6420c4e8a..7c33fd5bd 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.Bindings; using Speckle.InterfaceGenerator; using Speckle.Sdk; @@ -64,7 +65,7 @@ public async Task CatchUnhandledAsync(Func function) { try { - await function().ConfigureAwait(false); + await function().BackToCurrent(); return new Result(); } catch (Exception ex) when (!ex.IsFatal()) @@ -76,7 +77,7 @@ await SetGlobalNotification( ex.ToFormattedString(), false ) - .ConfigureAwait(false); + .BackToCurrent(); return new(ex); } } @@ -94,11 +95,11 @@ public async Task> CatchUnhandledAsync(Func> function) { try { - return new(await function.Invoke().ConfigureAwait(false)); + return new(await function.Invoke().BackToCurrent()); } catch (Exception ex) when (!ex.IsFatal()) { - await HandleException(ex).ConfigureAwait(false); + await HandleException(ex).BackToCurrent(); return new(ex); } } @@ -121,7 +122,7 @@ await SetGlobalNotification( ex.ToFormattedString(), false ) - .ConfigureAwait(false); + .BackToCurrent(); } catch (Exception toastEx) { @@ -145,7 +146,7 @@ await SetGlobalNotification( /// In cases where you can use keyword, you should prefer using /// /// - public async void FireAndForget(Func function) => await CatchUnhandledAsync(function).ConfigureAwait(false); + public async void FireAndForget(Func function) => await CatchUnhandledAsync(function).BackToCurrent(); private async Task SetGlobalNotification(ToastNotificationType type, string title, string message, bool autoClose) => await Parent @@ -159,5 +160,5 @@ await Parent autoClose } ) - .ConfigureAwait(false); + .BackToCurrent(); } From 5548ac86770c496fc1f33070c81ac55b139c5f30 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 5 Dec 2024 11:02:29 +0000 Subject: [PATCH 55/65] format --- .../Bindings/OperationProgressManager.cs | 21 +++++++++---------- .../Bridge/BrowserBridge.cs | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs b/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs index f53c9d005..3724eed44 100644 --- a/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs +++ b/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs @@ -30,15 +30,14 @@ CancellationToken cancellationToken ) { var progress = new NonUIThreadProgress(args => - { - SetModelProgress( - bridge, - modelCardId, - new ModelCardProgress(modelCardId, args.Status, args.Progress), - cancellationToken - ); - } - ); + { + SetModelProgress( + bridge, + modelCardId, + new ModelCardProgress(modelCardId, args.Status, args.Progress), + cancellationToken + ); + }); return progress; } @@ -59,7 +58,7 @@ CancellationToken cancellationToken t.Item1 = DateTime.Now; s_lastProgressValues[modelCardId] = (t.Item1, progress.Status); // Since it's the first time we get a call for this model card, we should send it out - SendProgress(bridge, modelCardId, progress); + SendProgress(bridge, modelCardId, progress); return; } @@ -71,7 +70,7 @@ CancellationToken cancellationToken return; } s_lastProgressValues[modelCardId] = (currentTime, progress.Status); - SendProgress(bridge, modelCardId, progress); + SendProgress(bridge, modelCardId, progress); } private static void SendProgress(IBrowserBridge bridge, string modelCardId, ModelCardProgress progress) => diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index b99809480..527dc04a9 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -285,7 +285,7 @@ public Task Send(string eventName, T data, CancellationToken cancellationToke _browserScriptExecutor.ExecuteScript(script); return Task.CompletedTask; } - + public void Send2(string eventName, T data) where T : class { From 10d9f3b03313d22f8e1dc646ae4ce0b3fc987a0e Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 5 Dec 2024 12:16:49 +0000 Subject: [PATCH 56/65] remove needless selection --- .../Bindings/TeklaSelectionBinding.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs index 4c26ab1d1..5a416e14d 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs @@ -29,8 +29,6 @@ Tekla.Structures.Model.UI.ModelObjectSelector selector _events.SelectionChange += Events_SelectionChangeEvent; _events.Register(); - - UpdateSelection(); } private void Events_SelectionChangeEvent() @@ -38,7 +36,6 @@ private void Events_SelectionChangeEvent() lock (_selectionEventHandlerLock) { _idleManager.SubscribeToIdle(nameof(TeklaSelectionBinding), UpdateSelection); - UpdateSelection(); } } From 75d8c9ab0f7413c3b6a4a3544a7aea8fd934916a Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 5 Dec 2024 13:13:42 +0000 Subject: [PATCH 57/65] 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 58/65] 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 59/65] 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()); From 9541ba76ae221b4b46e3864ff1698588b8d18fb5 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 2 Jan 2025 14:11:42 +0000 Subject: [PATCH 60/65] Build fixes from merge --- .../Bindings/ArcGISSendBinding.cs | 4 ++- .../ArcGISConnectorModule.cs | 1 - .../Bindings/AutocadSelectionBinding.cs | 8 +++-- .../NavisworksConnectorServiceRegistration.cs | 1 - .../Bindings/SelectionBinding.cs | 1 + .../Bindings/RhinoSendBinding.cs | 6 ++-- .../Plugin/Speckle.Connectors.RhinoPlugin.cs | 1 + .../Bridge/BrowserBridge.cs | 29 +++++++++++---- .../Bridge/TopLevelExceptionHandler.cs | 36 +++---------------- .../ContainerRegistration.cs | 1 + .../Eventing/MainThreadEventSubscription.cs | 2 +- .../Eventing/WorkerEventSubscription.cs | 2 +- .../Operations/SendOperation.cs | 2 +- 13 files changed, 45 insertions(+), 49 deletions(-) diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs index e823b57c7..ea887b66f 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs @@ -70,7 +70,9 @@ public ArcGISSendBinding( ILogger logger, IArcGISConversionSettingsFactory arcGisConversionSettingsFactory, MapMembersUtils mapMemberUtils, - IThreadContext threadContext + IThreadContext threadContext, + IEventAggregator eventAggregator, + ITopLevelExceptionHandler topLevelExceptionHandler ) { _store = store; diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs index 301c13272..08ea8dbd9 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs @@ -37,7 +37,6 @@ public static void AddArcGIS(this IServiceCollection serviceCollection) serviceCollection.AddSingleton(sp => sp.GetRequiredService()); serviceCollection.AddSingleton(); - serviceCollection.RegisterTopLevelExceptionHandler(); serviceCollection.AddSingleton(DefaultTraversal.CreateTraversalFunc()); // register send operation and dependencies diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs index 4afe09989..6d3d5e7d7 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) + public AutocadSelectionBinding( + IBrowserBridge parent, + IThreadContext threadContext, + ITopLevelExceptionHandler topLevelExceptionHandler + ) { _topLevelExceptionHandler = topLevelExceptionHandler; Parent = parent; @@ -55,7 +59,7 @@ private void TryRegisterDocumentForSelection(Document? document) // Ui requests to GetSelection() should just return this local copy that is kept up to date by the event handler. private SelectionInfo _selectionInfo; - private async ValueTask OnSelectionChanged() + private async Task OnSelectionChanged() { _selectionInfo = GetSelectionInternal(); await Parent.Send(SELECTION_EVENT, _selectionInfo); diff --git a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/DependencyInjection/NavisworksConnectorServiceRegistration.cs b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/DependencyInjection/NavisworksConnectorServiceRegistration.cs index b906ddce4..7d633dcae 100644 --- a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/DependencyInjection/NavisworksConnectorServiceRegistration.cs +++ b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/DependencyInjection/NavisworksConnectorServiceRegistration.cs @@ -59,7 +59,6 @@ public static void AddNavisworks(this IServiceCollection serviceCollection) serviceCollection.AddSingleton(); // Register Intercom/interop - serviceCollection.RegisterTopLevelExceptionHandler(); serviceCollection.AddTransient(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SelectionBinding.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SelectionBinding.cs index fcf7a3902..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) diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs index 925236d71..2cbfbbbc2 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs @@ -112,9 +112,9 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) { PreviousUnitSystem = newUnit; - await InvalidateAllSender(); - } - }; + await InvalidateAllSender(); + } + }); eventAggregator .GetEvent() 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 1828b7479..61052675c 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Plugin/Speckle.Connectors.RhinoPlugin.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Plugin/Speckle.Connectors.RhinoPlugin.cs @@ -1,6 +1,7 @@ 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; diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index dc0d95340..600fae3cf 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -28,12 +28,8 @@ public sealed class BrowserBridge : IBrowserBridge /// private readonly ConcurrentDictionary _resultsStore = new(); - public ITopLevelExceptionHandler TopLevelExceptionHandler { get; } - private readonly IThreadContext _threadContext; - private readonly IThreadOptions _threadOptions; private readonly ITopLevelExceptionHandler _topLevelExceptionHandler; - private readonly IEventAggregator _eventAggregator; private readonly IThreadContext _threadContext; private readonly IThreadOptions _threadOptions; @@ -66,9 +62,10 @@ public BrowserBridge( IThreadContext threadContext, IJsonSerializer jsonSerializer, ILogger logger, - ILogger topLogger, IBrowserScriptExecutor browserScriptExecutor, - IThreadOptions threadOptions + IThreadOptions threadOptions, + IEventAggregator eventAggregator, + ITopLevelExceptionHandler topLevelExceptionHandler ) { _threadContext = threadContext; @@ -77,6 +74,26 @@ IThreadOptions threadOptions // Capture the main thread's SynchronizationContext _browserScriptExecutor = browserScriptExecutor; _threadOptions = threadOptions; + _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.MainThread + ); } public void AssociateWithBinding(IBinding binding) diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs index 7fa131940..e8ca9e522 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.Connectors.DUI.Eventing; using Speckle.InterfaceGenerator; using Speckle.Sdk; @@ -85,11 +84,10 @@ public Result CatchUnhandled(Func function) public async Task CatchUnhandledAsync(Func function) { var r = await CatchUnhandledAsync(async () => - { - await function().BackToCurrent(); - return true; - }) - .BackToCurrent(); + { + await function(); + return true; + }); if (r.IsSuccess) { return new Result(); @@ -120,32 +118,6 @@ public async Task> CatchUnhandledAsync(Func> function) } } - private async Task HandleException(Exception ex) - { - _logger.LogError(ex, UNHANDLED_LOGGER_TEMPLATE); - - try - { - await SetGlobalNotification( - ToastNotificationType.DANGER, - "Unhandled Exception Occured", - ex.ToFormattedString(), - 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/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs index b1481b608..517b0720d 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; diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs index 1b9519e49..c524f027f 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)).BackToCurrent(); + threadContext.RunOnMain(() => action.Invoke(payload)); } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs index 82d9c74ea..1083987be 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)).BackToCurrent(); + threadContext.RunOnWorker(() => action(argument)); } diff --git a/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs b/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs index 9faaa5166..357e82566 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs @@ -48,7 +48,7 @@ public async Task Execute( return new(rootObjId, convertedReferences, buildResult.ConversionResults); } - public async ValueTask Send( + private async Task Send( Base commitObject, SendInfo sendInfo, IProgress onOperationProgressed, From 47ca94280bce4e03b1752b7f746771de8ddd688b Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 2 Jan 2025 14:34:15 +0000 Subject: [PATCH 61/65] Fix tests and clean up --- .../HostApp/AutocadDocumentModelStore.cs | 1 - .../Bridge/IdleCallManagerTests.cs | 2 +- .../Bridge/TopLevelExceptionHandlerTests.cs | 3 +-- .../Bridge/TopLevelExceptionHandler.cs | 17 +++++++---------- Speckle.Connectors.sln | 9 ++++----- 5 files changed, 13 insertions(+), 19 deletions(-) diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadDocumentModelStore.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadDocumentModelStore.cs index 04c68ab29..eb8796cb1 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadDocumentModelStore.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadDocumentModelStore.cs @@ -52,7 +52,6 @@ private void OnDocChangeInternal(Document? doc) _previousDocName = currentDocName; LoadState(); - LoadState(); _eventAggregator.GetEvent().Publish(new object()); } diff --git a/DUI3/Speckle.Connectors.DUI.Tests/Bridge/IdleCallManagerTests.cs b/DUI3/Speckle.Connectors.DUI.Tests/Bridge/IdleCallManagerTests.cs index 9c8397023..611f6af7f 100644 --- a/DUI3/Speckle.Connectors.DUI.Tests/Bridge/IdleCallManagerTests.cs +++ b/DUI3/Speckle.Connectors.DUI.Tests/Bridge/IdleCallManagerTests.cs @@ -15,7 +15,7 @@ public void SubscribeToIdleTest() var sut = new IdleCallManager(handler.Object); var action = Create(); var addEvent = Create(); - handler.Setup(x => x.CatchUnhandled(It.IsAny())); + handler.Setup(x => x.CatchUnhandled(It.IsAny())).Returns(new Result()); sut.SubscribeToIdle("id", action.Object, addEvent.Object); } diff --git a/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs b/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs index 2a4957745..cfa7deebb 100644 --- a/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs +++ b/DUI3/Speckle.Connectors.DUI.Tests/Bridge/TopLevelExceptionHandlerTests.cs @@ -75,10 +75,9 @@ public void CatchUnhandledFunc_Exception_Fatal() var eventAggregator = Create(); var sut = new TopLevelExceptionHandler(logger.Object, eventAggregator.Object); - var exception = Assert.Throws( + Assert.Throws( () => sut.CatchUnhandled(new Func(() => throw new AppDomainUnloadedException())) ); - exception.InnerExceptions.Single().Should().BeOfType(); } [Test] diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs index e8ca9e522..2e98ce072 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs @@ -61,16 +61,13 @@ public Result CatchUnhandled(Func function) { try { - try - { - return new Result(function()); - } - catch (Exception ex) when (!ex.IsFatal()) - { - _logger.LogError(ex, UNHANDLED_LOGGER_TEMPLATE); - _eventAggregator.GetEvent().Publish(ex); - return new(ex); - } + return new Result(function()); + } + catch (Exception ex) when (!ex.IsFatal()) + { + _logger.LogError(ex, UNHANDLED_LOGGER_TEMPLATE); + _eventAggregator.GetEvent().Publish(ex); + return new(ex); } catch (Exception ex) { diff --git a/Speckle.Connectors.sln b/Speckle.Connectors.sln index a28a14618..2e78ba884 100644 --- a/Speckle.Connectors.sln +++ b/Speckle.Connectors.sln @@ -15,8 +15,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Config", "Config", "{85A13E README.md = README.md EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DUI", "DUI", "{FD4D6594-D81E-456F-8F2E-35B09E04A755}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Revit", "Revit", "{D92751C8-1039-4005-90B2-913E55E0B8BD}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sdk", "Sdk", "{2E00592E-558D-492D-88F9-3ECEE4C0C7DA}" @@ -658,7 +656,7 @@ Global {DC570FFF-6FE5-47BD-8BC1-B471A6067786} = {FC224610-32D3-454E-9BC1-1219FE8ACD5F} {E1C43415-3200-45F4-8BF9-A4DD7D7F2ED6} = {FC224610-32D3-454E-9BC1-1219FE8ACD5F} {26391930-F86F-47E0-A5F6-B89919E38CE1} = {E9DEBA00-50A4-485D-BA65-D8AB3E3467AB} - {D81C0B87-F0C1-4297-A147-02F001FB7E1E} = {FD4D6594-D81E-456F-8F2E-35B09E04A755} + {D81C0B87-F0C1-4297-A147-02F001FB7E1E} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA} {7291B93C-615D-42DE-B8C1-3F9DF643E0FC} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA} {8AEF06C0-CA5C-4460-BC2D-ADE5F35D0434} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA} {9584AEE5-CD59-46E6-93E6-2DC2B5285B75} = {42826721-9A18-4762-8BA9-F1429DD5C5B1} @@ -672,7 +670,7 @@ Global {804E065F-914C-414A-AF84-009312C3CFF6} = {42826721-9A18-4762-8BA9-F1429DD5C5B1} {9ADD1B7A-6401-4202-8613-F668E2FBC0A4} = {4721AA15-AF6E-4A62-A2C3-65564DC563E6} {631C295A-7CCF-4B42-8686-7034E31469E7} = {2D5AE63D-85C0-43D1-84BF-04418ED93F63} - {7420652C-3046-4F38-BE64-9B9E69D76FA2} = {FD4D6594-D81E-456F-8F2E-35B09E04A755} + {7420652C-3046-4F38-BE64-9B9E69D76FA2} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA} {C50AA3E3-8C31-4131-9DEC-1D8B377D5A89} = {59E8E8F3-4E42-4E92-83B3-B1C2AB901D18} {CA8EAE01-AB9F-4EC1-B6F3-73721487E9E1} = {2F45036E-D817-41E9-B82F-DBE013EC95D0} {35175682-DA83-4C0A-A49D-B191F5885D8E} = {4721AA15-AF6E-4A62-A2C3-65564DC563E6} @@ -699,7 +697,7 @@ Global {7F1FDCF2-0CE8-4119-B3C1-F2CC6D7E1C36} = {0AF38BA3-65A0-481B-8CBB-B82E406E1575} {19424B55-058C-4E9C-B86F-700AEF9EAEC3} = {0AF38BA3-65A0-481B-8CBB-B82E406E1575} {0AF38BA3-65A0-481B-8CBB-B82E406E1575} = {D92751C8-1039-4005-90B2-913E55E0B8BD} - {EB83A3A3-F9B6-4281-8EBF-F7289FB5D885} = {FD4D6594-D81E-456F-8F2E-35B09E04A755} + {EB83A3A3-F9B6-4281-8EBF-F7289FB5D885} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA} {D8069A23-AD2E-4C9E-8574-7E8C45296A46} = {0AF38BA3-65A0-481B-8CBB-B82E406E1575} {2D5AE63D-85C0-43D1-84BF-04418ED93F63} = {804E065F-914C-414A-AF84-009312C3CFF6} {2F45036E-D817-41E9-B82F-DBE013EC95D0} = {804E065F-914C-414A-AF84-009312C3CFF6} @@ -789,6 +787,7 @@ Global Converters\Civil3d\Speckle.Converters.Civil3dShared\Speckle.Converters.Civil3dShared.projitems*{25172c49-7aa4-4739-bb07-69785094c379}*SharedItemsImports = 5 Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{26391930-f86f-47e0-a5f6-b89919e38ce1}*SharedItemsImports = 5 Converters\Civil3d\Speckle.Converters.Civil3dShared\Speckle.Converters.Civil3dShared.projitems*{35175682-da83-4c0a-a49d-b191f5885d8e}*SharedItemsImports = 13 + Converters\CSi\Speckle.Converters.ETABSShared\Speckle.Converters.ETABSShared.projitems*{36377858-d696-4567-ab05-637f4ec841f5}*SharedItemsImports = 13 Connectors\Tekla\Speckle.Connector.TeklaShared\Speckle.Connectors.TeklaShared.projitems*{3ab9028b-b2d2-464b-9ba3-39c192441e50}*SharedItemsImports = 13 Connectors\Autocad\Speckle.Connectors.AutocadShared\Speckle.Connectors.AutocadShared.projitems*{41bc679f-887f-44cf-971d-a5502ee87db0}*SharedItemsImports = 13 Connectors\Autocad\Speckle.Connectors.AutocadShared\Speckle.Connectors.AutocadShared.projitems*{4459f2b1-a340-488e-a856-eb2ae9c72ad4}*SharedItemsImports = 5 From 35db076d5d1947d3eb40b7335da9facba22ca338 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Wed, 8 Jan 2025 16:44:14 +0000 Subject: [PATCH 62/65] Add new events --- .../Bindings/RhinoSendBinding.cs | 16 +++++++++------- .../Speckle.Connectors.RhinoShared/Events.cs | 8 ++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs index 89bf6d772..0e768db80 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs @@ -108,7 +108,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) { ChangedObjectIdsInGroupsOrLayers[selectedObject.Id.ToString()] = 1; } - _idleManager.SubscribeToIdle(nameof(RhinoSendBinding), RunExpirationChecks); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); } }; eventAggregator @@ -175,8 +175,9 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) } }); - RhinoDoc.GroupTableEvent += (_, args) => - _topLevelExceptionHandler.CatchUnhandled(() => + eventAggregator + .GetEvent() + .Subscribe(args => { if (!_store.IsDocumentInit) { @@ -187,11 +188,12 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) { ChangedObjectIdsInGroupsOrLayers[obj.Id.ToString()] = 1; } - _idleManager.SubscribeToIdle(nameof(RhinoSendBinding), RunExpirationChecks); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); }); - RhinoDoc.LayerTableEvent += (_, args) => - _topLevelExceptionHandler.CatchUnhandled(() => + eventAggregator + .GetEvent() + .Subscribe(args => { if (!_store.IsDocumentInit) { @@ -219,7 +221,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) ChangedObjectIdsInGroupsOrLayers[obj.Id.ToString()] = 1; } } - _idleManager.SubscribeToIdle(nameof(RhinoSendBinding), RunExpirationChecks); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); }); // 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. diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs index d5639ed3f..af3910f47 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs @@ -46,6 +46,12 @@ public class ModifyObjectAttributes(IThreadContext threadContext, ITopLevelExcep public class ReplaceRhinoObject(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); +public class GroupTableEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); + +public class LayerTableEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); + public static class RhinoEvents { public static void Register(IEventAggregator eventAggregator) @@ -65,5 +71,7 @@ public static void Register(IEventAggregator eventAggregator) RhinoDoc.MaterialTableEvent += (_, e) => eventAggregator.GetEvent().Publish(e); RhinoDoc.ModifyObjectAttributes += (_, e) => eventAggregator.GetEvent().Publish(e); RhinoDoc.ReplaceRhinoObject += (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.GroupTableEvent += (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoDoc.LayerTableEvent += (_, e) => eventAggregator.GetEvent().Publish(e); } } From ad4d8617a787fd208906bc1928bd386a0d8eb95f Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Fri, 17 Jan 2025 12:57:49 +0000 Subject: [PATCH 63/65] Properly dispose one time events --- .../Eventing/OneTimeThreadedEvent.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs index db3270e79..2fadb2966 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs @@ -76,4 +76,17 @@ private SubscriptionToken OneTimeInternal( return token; } } + + public override void Publish(T payload) + { + lock (_activeTokens) + { + base.Publish(payload); + foreach (var token in _activeTokens.Values) + { + token.Dispose(); + } + _activeTokens.Clear(); + } + } } From e19cbc49b2ec6277b57d854da0e38ca1838ab76b Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 20 Jan 2025 13:25:43 +0000 Subject: [PATCH 64/65] Minor tekla updates --- .../Bindings/TeklaSelectionBinding.cs | 2 +- .../Bindings/TeklaSendBinding.cs | 2 +- .../Tekla/Speckle.Connector.TeklaShared/Events.cs | 12 ++++++------ .../HostApp/TeklaDocumentModelStore.cs | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs index 2fbcca3e0..81b32be60 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs @@ -26,7 +26,7 @@ IEventAggregator eventAggregator _selector = selector; _eventAggregator = eventAggregator; - eventAggregator.GetEvent().Subscribe(_ => Events_SelectionChangeEvent()); + eventAggregator.GetEvent().Subscribe(_ => Events_SelectionChangeEvent()); } private void Events_SelectionChangeEvent() diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs index b02514ae9..d49dd0ba5 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs @@ -78,7 +78,7 @@ IEventAggregator eventAggregator _toSpeckleSettingsManager = toSpeckleSettingsManager; _model = new Model(); - eventAggregator.GetEvent().Subscribe(ModelHandler_OnChange); + eventAggregator.GetEvent().Subscribe(ModelHandler_OnChange); } // subscribes the all changes in a modelobject diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs index 24b749eef..83d0e7c10 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs @@ -4,13 +4,13 @@ namespace Speckle.Connectors.RhinoShared; -public class SelectionChange(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) +public class SelectionChangeEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); -public class ModelObjectChanged(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) +public class ModelObjectChangedEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent>(threadContext, exceptionHandler); -public class ModelLoad(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) +public class ModelLoadEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); public static class TeklaEvents @@ -18,9 +18,9 @@ public static class TeklaEvents public static void Register(Tekla.Structures.Model.Events events, IEventAggregator eventAggregator) { events.UnRegister(); - events.SelectionChange += () => eventAggregator.GetEvent().Publish(new object()); - events.ModelObjectChanged += x => eventAggregator.GetEvent().Publish(x); - events.ModelLoad += () => 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 f9e7f1945..a8207ffb1 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/HostApp/TeklaDocumentModelStore.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/HostApp/TeklaDocumentModelStore.cs @@ -29,8 +29,8 @@ IEventAggregator eventAggregator _model = new TSM.Model(); GenerateKey(); eventAggregator - .GetEvent() - .Publish(() => + .GetEvent() + .Subscribe(_ => { GenerateKey(); LoadState(); From dfd080383e43a6bb09f7e0cd656495ba095b2874 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 21 Jan 2025 14:12:39 +0000 Subject: [PATCH 65/65] Introduce Async publish and Async/Sync subscription (#505) * Support async publish but async or sync subscribe * Publish with tests * more sub overloads * added onetime tests that fail * Reorganized events to have async and sync * adjust subscriptions * Rhino fixes * use async eventing everywhere and add docstore init method * clean up * add handlers for unobserved task exceptions * fix usage of exception handler to include one time users * fix(civil3d): handles property exceptions for corridor elements (#508) * Update GeneralPropertiesExtractor.cs * Update GeneralPropertiesExtractor.cs * Update CorridorDisplayValueExtractor.cs * Fix weak references * Fix TeklaEvents namespace * Anonymous methods are always created as strong references * refactor to have features --------- Co-authored-by: Claire Kuang --- .../SpeckleModule.cs | 2 + .../Utils/ArcGisDocumentStore.cs | 9 +- .../HostApp/AutocadDocumentModelStore.cs | 4 +- .../Plugin/AutocadCommand.cs | 2 + .../Plugin/SpeckleFormBase.cs | 2 + .../Plugin/DockableConnectorPane.cs | 2 + .../HostApp/RevitDocumentStore.cs | 9 +- .../Plugin/RevitExternalApplication.cs | 2 + .../Bindings/RhinoSelectionBinding.cs | 2 +- .../Bindings/RhinoSendBinding.cs | 18 +- .../Speckle.Connectors.RhinoShared/Events.cs | 38 +-- .../HostApp/RhinoDocumentStore.cs | 4 +- .../Plugin/Speckle.Connectors.RhinoPlugin.cs | 3 +- .../Bindings/TeklaSelectionBinding.cs | 10 +- .../Bindings/TeklaSendBinding.cs | 1 - .../Speckle.Connector.TeklaShared/Events.cs | 11 +- .../HostApp/TeklaDocumentModelStore.cs | 13 +- .../SpeckleTeklaPanelHost.cs | 3 +- .../Helpers/CorridorDisplayValueExtractor.cs | 5 + .../Properties/GeneralPropertiesExtractor.cs | 36 ++- .../Eventing/EventAggregatorTests.cs | 283 ++++++++++++++++++ .../Bridge/BrowserBridge.cs | 4 +- .../Bridge/TopLevelExceptionHandler.cs | 4 +- .../ContainerRegistration.cs | 18 ++ .../Eventing/DelegateReference.cs | 114 +++---- .../Eventing/EventBase.cs | 106 +++---- .../Eventing/EventFeatures.cs | 11 + .../Eventing/EventSubscription.cs | 153 +++------- .../Eventing/IEventSubscription.cs | 8 + .../Eventing/MainThreadEventSubscription.cs | 16 - .../Eventing/OneTimeEventSubscription.cs | 20 -- .../Eventing/OneTimeThreadedEvent.cs | 92 +++--- .../Eventing/PubSubEvent.cs | 138 --------- .../Eventing/SpeckleEvent.cs | 40 +++ .../Eventing/SubscriptionToken.cs | 14 +- .../Eventing/ThreadedEvent.cs | 82 +---- .../Eventing/WeakOrStrongReference.cs | 24 ++ .../Eventing/WorkerEventSubscription.cs | 16 - .../Models/DocumentModelStore.cs | 2 + 39 files changed, 677 insertions(+), 644 deletions(-) create mode 100644 DUI3/Speckle.Connectors.DUI.Tests/Eventing/EventAggregatorTests.cs create mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/EventFeatures.cs create mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/IEventSubscription.cs delete mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs delete mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/OneTimeEventSubscription.cs delete mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs create mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs create mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/WeakOrStrongReference.cs delete mode 100644 DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/SpeckleModule.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/SpeckleModule.cs index 1d5eee795..64370fdf2 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/SpeckleModule.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/SpeckleModule.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Speckle.Connectors.ArcGIS.DependencyInjection; using Speckle.Connectors.Common; +using Speckle.Connectors.DUI; using Speckle.Converters.ArcGIS3; using Speckle.Sdk.Host; using Module = ArcGIS.Desktop.Framework.Contracts.Module; @@ -34,6 +35,7 @@ public SpeckleModule() services.AddArcGIS(); services.AddArcGISConverters(); Container = services.BuildServiceProvider(); + Container.UseDUI(); } private HostAppVersion GetVersion() diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs index dbec9d03b..e64953be5 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs @@ -42,13 +42,16 @@ IEventAggregator eventAggregator }, true ); + } + public override async Task OnDocumentStoreInitialized() + { // in case plugin was loaded into already opened Map, read metadata from the current Map if (!IsDocumentInit && MapView.Active != null) { IsDocumentInit = true; LoadState(); - eventAggregator.GetEvent().Publish(new object()); + await _eventAggregator.GetEvent().PublishAsync(new object()); } } @@ -73,7 +76,7 @@ private void OnProjectSaving() /// /// On map view switch, this event trigger twice, first for outgoing view, second for incoming view. /// - private void OnMapViewChanged(ActiveMapViewChangedEventArgs args) + private async void OnMapViewChanged(ActiveMapViewChangedEventArgs args) { if (args.IncomingView is null) { @@ -82,7 +85,7 @@ private void OnMapViewChanged(ActiveMapViewChangedEventArgs args) IsDocumentInit = true; LoadState(); - _eventAggregator.GetEvent().Publish(new object()); + await _eventAggregator.GetEvent().PublishAsync(new object()); } protected override void HostAppSaveState(string modelCardState) => diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadDocumentModelStore.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadDocumentModelStore.cs index eb8796cb1..899954633 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadDocumentModelStore.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadDocumentModelStore.cs @@ -42,7 +42,7 @@ IEventAggregator eventAggregator // OnDocChangeInternal((Document)args.DocumentWindow.Document); } - private void OnDocChangeInternal(Document? doc) + private async void OnDocChangeInternal(Document? doc) { var currentDocName = doc != null ? doc.Name : _nullDocumentName; if (_previousDocName == currentDocName) @@ -52,7 +52,7 @@ private void OnDocChangeInternal(Document? doc) _previousDocName = currentDocName; LoadState(); - _eventAggregator.GetEvent().Publish(new object()); + await _eventAggregator.GetEvent().PublishAsync(new object()); } protected override void LoadState() diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Plugin/AutocadCommand.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Plugin/AutocadCommand.cs index cbc69d098..f3c177540 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Plugin/AutocadCommand.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Plugin/AutocadCommand.cs @@ -3,6 +3,7 @@ using Autodesk.AutoCAD.Windows; using Microsoft.Extensions.DependencyInjection; using Speckle.Connectors.Common; +using Speckle.Connectors.DUI; using Speckle.Connectors.DUI.WebView; #if AUTOCAD using Speckle.Connectors.Autocad.DependencyInjection; @@ -47,6 +48,7 @@ public void Command() services.AddCivil3dConverters(); #endif Container = services.BuildServiceProvider(); + Container.UseDUI(); var panelWebView = Container.GetRequiredService(); diff --git a/Connectors/CSi/Speckle.Connectors.CSiShared/Plugin/SpeckleFormBase.cs b/Connectors/CSi/Speckle.Connectors.CSiShared/Plugin/SpeckleFormBase.cs index a3a81cad1..2cf925a82 100644 --- a/Connectors/CSi/Speckle.Connectors.CSiShared/Plugin/SpeckleFormBase.cs +++ b/Connectors/CSi/Speckle.Connectors.CSiShared/Plugin/SpeckleFormBase.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Speckle.Connectors.Common; using Speckle.Connectors.CSiShared.HostApp; +using Speckle.Connectors.DUI; using Speckle.Connectors.DUI.WebView; using Speckle.Converters.CSiShared; using Speckle.Sdk.Host; @@ -25,6 +26,7 @@ protected SpeckleFormBase() ConfigureServices(services); Container = services.BuildServiceProvider(); + Container.UseDUI(); var webview = Container.GetRequiredService(); Host = new() { Child = webview, Dock = DockStyle.Fill }; diff --git a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Plugin/DockableConnectorPane.cs b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Plugin/DockableConnectorPane.cs index a06842db6..9c4240c81 100644 --- a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Plugin/DockableConnectorPane.cs +++ b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Plugin/DockableConnectorPane.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using Speckle.Connector.Navisworks.DependencyInjection; using Speckle.Connectors.Common; +using Speckle.Connectors.DUI; using Speckle.Connectors.DUI.WebView; using Speckle.Converter.Navisworks.DependencyInjection; using Speckle.Sdk.Host; @@ -42,6 +43,7 @@ public override Control CreateControlPane() services.AddNavisworksConverter(); Container = services.BuildServiceProvider(); + Container.UseDUI(); var u = Container.GetRequiredService(); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs index 8ddf7aa58..f1b8d5e89 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs @@ -53,10 +53,11 @@ 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()); } + public override Task OnDocumentStoreInitialized() => + _eventAggregator.GetEvent().PublishAsync(new object()); + /// /// This is the place where we track document switch for new document -> Responsible to Read from new doc /// @@ -76,10 +77,10 @@ private void OnViewActivated(object? _, ViewActivatedEventArgs e) IsDocumentInit = true; _idleManager.SubscribeToIdle( nameof(RevitDocumentStore), - () => + async () => { LoadState(); - _eventAggregator.GetEvent().Publish(new object()); + await _eventAggregator.GetEvent().PublishAsync(new object()); } ); } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitExternalApplication.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitExternalApplication.cs index 3eb15365b..0cd5c1b60 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitExternalApplication.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitExternalApplication.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Speckle.Connectors.Common; +using Speckle.Connectors.DUI; using Speckle.Connectors.Revit.DependencyInjection; using Speckle.Converters.RevitShared; using Speckle.Sdk; @@ -47,6 +48,7 @@ public Result OnStartup(UIControlledApplication application) services.AddRevitConverters(); services.AddSingleton(application); _container = services.BuildServiceProvider(); + _container.UseDUI(); // resolve root object _revitPlugin = _container.GetRequiredService(); diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSelectionBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSelectionBinding.cs index 98b1c9480..f91a37ba3 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 0e768db80..9e9a27fa2 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs @@ -108,7 +108,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) { ChangedObjectIdsInGroupsOrLayers[selectedObject.Id.ToString()] = 1; } - eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), _ => RunExpirationChecks()); } }; eventAggregator @@ -142,7 +142,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) } ChangedObjectIds[e.ObjectId.ToString()] = 1; - eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), _ => RunExpirationChecks()); }); eventAggregator @@ -155,7 +155,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) } ChangedObjectIds[e.ObjectId.ToString()] = 1; - eventAggregator.GetEvent().OneTimeSubscribe(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)! @@ -171,7 +171,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) if (args is RhinoDoc.RenderMaterialAssignmentChangedEventArgs changedEventArgs) { ChangedObjectIds[changedEventArgs.ObjectId.ToString()] = 1; - eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), _ => RunExpirationChecks()); } }); @@ -188,7 +188,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) { ChangedObjectIdsInGroupsOrLayers[obj.Id.ToString()] = 1; } - eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), _ => RunExpirationChecks()); }); eventAggregator @@ -221,7 +221,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) ChangedObjectIdsInGroupsOrLayers[obj.Id.ToString()] = 1; } } - eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), _ => RunExpirationChecks()); }); // 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. @@ -237,7 +237,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) if (args.EventType == MaterialTableEventType.Modified) { ChangedMaterialIndexes[args.Index] = 1; - eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), _ => RunExpirationChecks()); } }); @@ -259,7 +259,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) ) { ChangedObjectIds[e.RhinoObject.Id.ToString()] = 1; - eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), _ => RunExpirationChecks()); } }); @@ -274,7 +274,7 @@ private void SubscribeToRhinoEvents(IEventAggregator eventAggregator) ChangedObjectIds[e.NewRhinoObject.Id.ToString()] = 1; ChangedObjectIds[e.OldRhinoObject.Id.ToString()] = 1; - eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), RunExpirationChecks); + eventAggregator.GetEvent().OneTimeSubscribe(nameof(RhinoSendBinding), _ => RunExpirationChecks()); }); } diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs index af3910f47..0e7a68021 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Events.cs @@ -56,22 +56,26 @@ 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); - RhinoDoc.GroupTableEvent += (_, e) => eventAggregator.GetEvent().Publish(e); - RhinoDoc.LayerTableEvent += (_, e) => eventAggregator.GetEvent().Publish(e); + RhinoApp.Idle += async (_, e) => await eventAggregator.GetEvent().PublishAsync(e); + + RhinoDoc.BeginOpenDocument += async (_, e) => await eventAggregator.GetEvent().PublishAsync(e); + RhinoDoc.EndOpenDocument += async (_, e) => await eventAggregator.GetEvent().PublishAsync(e); + RhinoDoc.SelectObjects += async (_, e) => await eventAggregator.GetEvent().PublishAsync(e); + RhinoDoc.DeselectObjects += async (_, e) => await eventAggregator.GetEvent().PublishAsync(e); + RhinoDoc.DeselectAllObjects += async (_, e) => await eventAggregator.GetEvent().PublishAsync(e); + RhinoDoc.ActiveDocumentChanged += async (_, e) => + await eventAggregator.GetEvent().PublishAsync(e); + RhinoDoc.DocumentPropertiesChanged += async (_, e) => + await eventAggregator.GetEvent().PublishAsync(e); + RhinoDoc.AddRhinoObject += async (_, e) => await eventAggregator.GetEvent().PublishAsync(e); + RhinoDoc.DeleteRhinoObject += async (_, e) => await eventAggregator.GetEvent().PublishAsync(e); + RhinoDoc.RenderMaterialsTableEvent += async (_, e) => + await eventAggregator.GetEvent().PublishAsync(e); + RhinoDoc.MaterialTableEvent += async (_, e) => await eventAggregator.GetEvent().PublishAsync(e); + RhinoDoc.ModifyObjectAttributes += async (_, e) => + await eventAggregator.GetEvent().PublishAsync(e); + RhinoDoc.ReplaceRhinoObject += async (_, e) => await eventAggregator.GetEvent().PublishAsync(e); + RhinoDoc.GroupTableEvent += async (_, e) => await eventAggregator.GetEvent().PublishAsync(e); + RhinoDoc.LayerTableEvent += async (_, e) => await eventAggregator.GetEvent().PublishAsync(e); } } diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoDocumentStore.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoDocumentStore.cs index 2af952d34..00bd73746 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoDocumentStore.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoDocumentStore.cs @@ -17,7 +17,7 @@ public RhinoDocumentStore(IJsonSerializer jsonSerializer, IEventAggregator event eventAggregator.GetEvent().Subscribe(_ => IsDocumentInit = false); eventAggregator .GetEvent() - .Subscribe(e => + .Subscribe(async e => { if (e.Merge) { @@ -31,7 +31,7 @@ public RhinoDocumentStore(IJsonSerializer jsonSerializer, IEventAggregator event IsDocumentInit = true; LoadState(); - eventAggregator.GetEvent().Publish(new object()); + await eventAggregator.GetEvent().PublishAsync(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 61052675c..105b74ce9 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Plugin/Speckle.Connectors.RhinoPlugin.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Plugin/Speckle.Connectors.RhinoPlugin.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Rhino.PlugIns; using Speckle.Connectors.Common; +using Speckle.Connectors.DUI; using Speckle.Connectors.DUI.Eventing; using Speckle.Connectors.Rhino.DependencyInjection; using Speckle.Connectors.RhinoShared; @@ -52,8 +53,8 @@ protected override LoadReturnCode OnLoad(ref string errorMessage) // but the Rhino connector has `.rhp` as it is extension. Container = services.BuildServiceProvider(); - RhinoEvents.Register(Container.GetRequiredService()); + Container.UseDUI(); return LoadReturnCode.Success; } diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs index 81b32be60..5439a2edb 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSelectionBinding.cs @@ -1,7 +1,6 @@ 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; @@ -9,9 +8,8 @@ namespace Speckle.Connectors.TeklaShared.Bindings; public class TeklaSelectionBinding : ISelectionBinding { private const string SELECTION_EVENT = "setSelection"; - private readonly object _selectionEventHandlerLock = new object(); + private readonly object _selectionEventHandlerLock = new(); private readonly Tekla.Structures.Model.UI.ModelObjectSelector _selector; - private readonly IEventAggregator _eventAggregator; public string Name => "selectionBinding"; public IBrowserBridge Parent { get; } @@ -24,7 +22,6 @@ IEventAggregator eventAggregator { Parent = parent; _selector = selector; - _eventAggregator = eventAggregator; eventAggregator.GetEvent().Subscribe(_ => Events_SelectionChangeEvent()); } @@ -45,11 +42,6 @@ private void UpdateSelection() public SelectionInfo GetSelection() { - if (_selector == null) - { - return new SelectionInfo(new List(), "No objects selected."); - } - var objectIds = new List(); var objectTypes = new List(); diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs index d49dd0ba5..f8d0d4990 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs @@ -13,7 +13,6 @@ 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; diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs index 83d0e7c10..c9999f26c 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Events.cs @@ -1,8 +1,8 @@ -using Speckle.Connectors.Common.Threading; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Eventing; -namespace Speckle.Connectors.RhinoShared; +namespace Speckle.Connectors.TeklaShared; public class SelectionChangeEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) : ThreadedEvent(threadContext, exceptionHandler); @@ -18,9 +18,10 @@ public static class TeklaEvents public static void Register(Tekla.Structures.Model.Events events, IEventAggregator eventAggregator) { events.UnRegister(); - events.SelectionChange += () => eventAggregator.GetEvent().Publish(new object()); - events.ModelObjectChanged += x => eventAggregator.GetEvent().Publish(x); - events.ModelLoad += () => eventAggregator.GetEvent().Publish(new object()); + events.SelectionChange += async () => + await eventAggregator.GetEvent().PublishAsync(new object()); + events.ModelObjectChanged += async x => await eventAggregator.GetEvent().PublishAsync(x); + events.ModelLoad += async () => await eventAggregator.GetEvent().PublishAsync(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 a8207ffb1..dd7c59dd7 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/HostApp/TeklaDocumentModelStore.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/HostApp/TeklaDocumentModelStore.cs @@ -2,7 +2,6 @@ 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,6 +11,7 @@ namespace Speckle.Connectors.TeklaShared.HostApp; public class TeklaDocumentModelStore : DocumentModelStore { private readonly ILogger _logger; + private readonly IEventAggregator _eventAggregator; private readonly ISqLiteJsonCacheManager _jsonCacheManager; private readonly TSM.Model _model; private string? _modelKey; @@ -25,21 +25,26 @@ IEventAggregator eventAggregator : base(jsonSerializer) { _logger = logger; + _eventAggregator = eventAggregator; _jsonCacheManager = jsonCacheManagerFactory.CreateForUser("ConnectorsFileData"); _model = new TSM.Model(); GenerateKey(); eventAggregator .GetEvent() - .Subscribe(_ => + .Subscribe(async _ => { GenerateKey(); LoadState(); - eventAggregator.GetEvent().Publish(new object()); + await eventAggregator.GetEvent().PublishAsync(new object()); }); + } + + public override async Task OnDocumentStoreInitialized() + { if (SpeckleTeklaPanelHost.IsInitialized) { LoadState(); - eventAggregator.GetEvent().Publish(new object()); + await _eventAggregator.GetEvent().PublishAsync(new object()); } } diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/SpeckleTeklaPanelHost.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/SpeckleTeklaPanelHost.cs index b7a938698..c39e243af 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/SpeckleTeklaPanelHost.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/SpeckleTeklaPanelHost.cs @@ -5,9 +5,9 @@ using System.Windows.Forms.Integration; using Microsoft.Extensions.DependencyInjection; using Speckle.Connectors.Common; +using Speckle.Connectors.DUI; 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; @@ -92,6 +92,7 @@ private void InitializeInstance() Container = services.BuildServiceProvider(); TeklaEvents.Register(Container.GetRequiredService(), Container.GetRequiredService()); + Container.UseDUI(); Model = new Model(); if (!Model.GetConnectionStatus()) diff --git a/Converters/Civil3d/Speckle.Converters.Civil3dShared/Helpers/CorridorDisplayValueExtractor.cs b/Converters/Civil3d/Speckle.Converters.Civil3dShared/Helpers/CorridorDisplayValueExtractor.cs index 8f49b1017..0f2c2e695 100644 --- a/Converters/Civil3d/Speckle.Converters.Civil3dShared/Helpers/CorridorDisplayValueExtractor.cs +++ b/Converters/Civil3d/Speckle.Converters.Civil3dShared/Helpers/CorridorDisplayValueExtractor.cs @@ -94,6 +94,11 @@ public void ProcessCorridorSolids(CDB.Corridor corridor) { foreach (ADB.ObjectId solidId in corridor.ExportSolids(param, corridor.Database)) { + if (solidId.IsNull) // unclear why this happens + { + continue; + } + SOG.Mesh? mesh = null; var solid = tr.GetObject(solidId, ADB.OpenMode.ForRead); if (solid is ADB.Solid3d solid3d) diff --git a/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/GeneralPropertiesExtractor.cs b/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/GeneralPropertiesExtractor.cs index 3c2478d59..753aae8ae 100644 --- a/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/GeneralPropertiesExtractor.cs +++ b/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/GeneralPropertiesExtractor.cs @@ -141,14 +141,22 @@ private void ProcessCorridorFeaturelinePoints( int pointCount = 0; foreach (CDB.FeatureLinePoint point in featureline.FeatureLinePoints) { - pointsDict[pointCount.ToString()] = new Dictionary() + Dictionary pointPropertiesDict = + new() + { + ["station"] = point.Station, + ["xyz"] = point.XYZ.ToArray(), + ["isBreak"] = point.IsBreak + }; + + // not all points have offsets. Accessing the offset property in this case will throw. + try { - ["station"] = point.Station, - ["xyz"] = point.XYZ.ToArray(), - ["isBreak"] = point.IsBreak, - ["offset"] = point.Offset - }; + pointPropertiesDict["offset"] = point.Offset; + } + catch (ArgumentException) { } // do nothing - offset property will not be included + pointsDict[pointCount.ToString()] = pointPropertiesDict; pointCount++; } @@ -303,19 +311,23 @@ CDB.FeatureLineCollection featurelineCollection in offsetFeaturelineCollection.F generalPropertiesDict["Design Critera"] = designCriteriaDict; } - // get offset alignment props + // get offset alignment props. if (alignment.IsOffsetAlignment) { - var offsetInfo = alignment.OffsetAlignmentInfo; - Dictionary offsetAlignmentDict = - new() + try + { + // accessing "OffsetAlignmentInfo" on offset alignments will sometimes throw /shrug. + // this happens when an offset alignment is unlinked from the parent and the CreateMode is still set to "ManuallyCreation" + // https://help.autodesk.com/view/CIV3D/2024/ENU/?guid=2ecbe421-4c08-cbde-d078-56a9f03b93f9 + var offsetInfo = alignment.OffsetAlignmentInfo; + generalPropertiesDict["Offset Parameters"] = new Dictionary { ["side"] = offsetInfo.Side.ToString(), ["parentAlignmentId"] = offsetInfo.ParentAlignmentId.GetSpeckleApplicationId(), ["nominalOffset"] = offsetInfo.NominalOffset }; - - generalPropertiesDict["Offset Parameters"] = offsetAlignmentDict; + } + catch (InvalidOperationException) { } // do nothing } return generalPropertiesDict; diff --git a/DUI3/Speckle.Connectors.DUI.Tests/Eventing/EventAggregatorTests.cs b/DUI3/Speckle.Connectors.DUI.Tests/Eventing/EventAggregatorTests.cs new file mode 100644 index 000000000..0441bb05d --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI.Tests/Eventing/EventAggregatorTests.cs @@ -0,0 +1,283 @@ +using FluentAssertions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +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.Eventing; + +public class TestEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : ThreadedEvent(threadContext, exceptionHandler); + +public class TestOneTimeEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : OneTimeThreadedEvent(threadContext, exceptionHandler); + +public class EventAggregatorTests : MoqTest +{ + [Test] + public async Task Sub_Async_DisposeToken() + { + s_val = false; + var services = new ServiceCollection(); + var exceptionHandler = new TopLevelExceptionHandler( + Create>().Object, + Create().Object + ); + services.AddSingleton(Create().Object); + services.AddSingleton(exceptionHandler); + services.AddTransient(); + services.AddSingleton(); + var serviceProvider = services.BuildServiceProvider(); + + var subscriptionToken = Test_Sub_Async_DisposeToken(serviceProvider); + var eventAggregator = serviceProvider.GetRequiredService(); + await eventAggregator.GetEvent().PublishAsync(new object()); + + s_val.Should().BeTrue(); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + subscriptionToken.IsActive.Should().BeTrue(); + subscriptionToken.Dispose(); + GC.Collect(); + GC.WaitForPendingFinalizers(); + subscriptionToken.IsActive.Should().BeFalse(); + } + + private static SubscriptionToken Test_Sub_Async_DisposeToken(IServiceProvider serviceProvider) + { + var eventAggregator = serviceProvider.GetRequiredService(); + var subscriptionToken = eventAggregator + .GetEvent() + .Subscribe(_ => + { + s_val = true; + return Task.CompletedTask; + }); + return subscriptionToken; + } + + [Test] + public async Task Sub_Async_SubscribeToken() + { + s_val = false; + var services = new ServiceCollection(); + var exceptionHandler = new TopLevelExceptionHandler( + Create>().Object, + Create().Object + ); + services.AddSingleton(Create().Object); + services.AddSingleton(exceptionHandler); + services.AddTransient(); + services.AddSingleton(); + var serviceProvider = services.BuildServiceProvider(); + + var subscriptionToken = Test_Sub_Async_DisposeToken(serviceProvider); + var eventAggregator = serviceProvider.GetRequiredService(); + await eventAggregator.GetEvent().PublishAsync(new object()); + + s_val.Should().BeTrue(); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + subscriptionToken.IsActive.Should().BeTrue(); + eventAggregator.GetEvent().Unsubscribe(subscriptionToken); + GC.Collect(); + GC.WaitForPendingFinalizers(); + subscriptionToken.IsActive.Should().BeFalse(); + } + + private static SubscriptionToken Test_Sub_Sync(IServiceProvider serviceProvider) + { + var eventAggregator = serviceProvider.GetRequiredService(); + var subscriptionToken = eventAggregator + .GetEvent() + .Subscribe(_ => + { + s_val = true; + }); + return subscriptionToken; + } + + [Test] + public async Task Sub_Sync() + { + s_val = false; + var services = new ServiceCollection(); + var exceptionHandler = new TopLevelExceptionHandler( + Create>().Object, + Create().Object + ); + services.AddSingleton(Create().Object); + services.AddSingleton(exceptionHandler); + services.AddTransient(); + + services.AddSingleton(); + var serviceProvider = services.BuildServiceProvider(); + + var subscriptionToken = Test_Sub_Sync(serviceProvider); + var eventAggregator = serviceProvider.GetRequiredService(); + await eventAggregator.GetEvent().PublishAsync(new object()); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + subscriptionToken.IsActive.Should().BeTrue(); + s_val.Should().BeTrue(); + eventAggregator.GetEvent().Unsubscribe(subscriptionToken); + GC.Collect(); + GC.WaitForPendingFinalizers(); + subscriptionToken.IsActive.Should().BeFalse(); + } + + private static SubscriptionToken Test_Onetime_Sub_Async(IServiceProvider serviceProvider) + { + var eventAggregator = serviceProvider.GetRequiredService(); + var subscriptionToken = eventAggregator + .GetEvent() + .OneTimeSubscribe( + "test", + _ => + { + s_val = true; + return Task.CompletedTask; + } + ); + return subscriptionToken; + } + + [Test] + public async Task Onetime_Async() + { + s_val = false; + var services = new ServiceCollection(); + var exceptionHandler = new TopLevelExceptionHandler( + Create>().Object, + Create().Object + ); + services.AddSingleton(Create().Object); + services.AddSingleton(exceptionHandler); + services.AddTransient(); + + services.AddSingleton(); + var serviceProvider = services.BuildServiceProvider(); + + var subscriptionToken = Test_Onetime_Sub_Async(serviceProvider); + var eventAggregator = serviceProvider.GetRequiredService(); + GC.Collect(); + GC.WaitForPendingFinalizers(); + subscriptionToken.IsActive.Should().BeTrue(); + + await eventAggregator.GetEvent().PublishAsync(new object()); + + s_val.Should().BeTrue(); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + subscriptionToken.IsActive.Should().BeFalse(); + subscriptionToken.Dispose(); + GC.Collect(); + GC.WaitForPendingFinalizers(); + subscriptionToken.IsActive.Should().BeFalse(); + } + + private static SubscriptionToken Test_Onetime_Sub_Sync(IServiceProvider serviceProvider) + { + var eventAggregator = serviceProvider.GetRequiredService(); + var subscriptionToken = eventAggregator + .GetEvent() + .OneTimeSubscribe( + "test", + _ => + { + s_val = true; + } + ); + return subscriptionToken; + } + + [Test] + public async Task Onetime_Sync() + { + var services = new ServiceCollection(); + var exceptionHandler = new TopLevelExceptionHandler( + Create>().Object, + Create().Object + ); + services.AddSingleton(Create().Object); + services.AddSingleton(exceptionHandler); + services.AddTransient(); + services.AddSingleton(); + var serviceProvider = services.BuildServiceProvider(); + + var subscriptionToken = Test_Onetime_Sub_Sync(serviceProvider); + var eventAggregator = serviceProvider.GetRequiredService(); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + subscriptionToken.IsActive.Should().BeTrue(); + + await eventAggregator.GetEvent().PublishAsync(new object()); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + subscriptionToken.IsActive.Should().BeFalse(); + s_val.Should().BeTrue(); + eventAggregator.GetEvent().Unsubscribe(subscriptionToken); + GC.Collect(); + GC.WaitForPendingFinalizers(); + subscriptionToken.IsActive.Should().BeFalse(); + } + + private static bool s_val; + + [Test] + public async Task Sub_WeakReference() + { + s_val = false; + var services = new ServiceCollection(); + var exceptionHandler = new TopLevelExceptionHandler( + Create>().Object, + Create().Object + ); + services.AddSingleton(Create().Object); + services.AddSingleton(exceptionHandler); + services.AddTransient(); + services.AddSingleton(); + var serviceProvider = services.BuildServiceProvider(); + TestWeakReference(serviceProvider); + + s_val.Should().BeFalse(); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + + await serviceProvider.GetRequiredService().GetEvent().PublishAsync(new object()); + s_val.Should().BeFalse(); + } + + //keep in a separate method to avoid referencing ObjectWithAction + private static void TestWeakReference(IServiceProvider serviceProvider) + { + var x = new ObjectWithAction( + new Action(() => + { + s_val = true; + }) + ); + var eventAggregator = serviceProvider.GetRequiredService(); + eventAggregator.GetEvent().Subscribe(x.Test1); + x = null; + } + + private sealed class ObjectWithAction(Action action) + { + public void Test1(object _) + { + action(); + } + } +} diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 600fae3cf..3ecaefd26 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -78,9 +78,9 @@ ITopLevelExceptionHandler topLevelExceptionHandler eventAggregator .GetEvent() .Subscribe( - ex => + async ex => { - Send( + await Send( BasicConnectorBindingCommands.SET_GLOBAL_NOTIFICATION, new { diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs index 2e98ce072..7699552a8 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs @@ -66,7 +66,7 @@ public Result CatchUnhandled(Func function) catch (Exception ex) when (!ex.IsFatal()) { _logger.LogError(ex, UNHANDLED_LOGGER_TEMPLATE); - _eventAggregator.GetEvent().Publish(ex); + _eventAggregator.GetEvent().PublishAsync(ex).Wait(); return new(ex); } catch (Exception ex) @@ -104,7 +104,7 @@ public async Task> CatchUnhandledAsync(Func> function) catch (Exception ex) when (!ex.IsFatal()) { _logger.LogError(ex, UNHANDLED_LOGGER_TEMPLATE); - _eventAggregator.GetEvent().Publish(ex); + await _eventAggregator.GetEvent().PublishAsync(ex); return new(ex); } } diff --git a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs index 517b0720d..dbda73c28 100644 --- a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs +++ b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs @@ -1,6 +1,7 @@ using System.Reflection; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Logging; using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; @@ -49,4 +50,21 @@ public static IServiceCollection AddEventsAsTransient(this IServiceCollection se return serviceCollection; } + + public static IServiceProvider UseDUI(this IServiceProvider serviceProvider) + { + //observe the unobserved! + TaskScheduler.UnobservedTaskException += async (_, args) => + { + await serviceProvider + .GetRequiredService() + .GetEvent() + .PublishAsync(args.Exception); + serviceProvider.GetRequiredService().LogError(args.Exception, "Unobserved task exception"); + args.SetObserved(); + }; + + serviceProvider.GetRequiredService().OnDocumentStoreInitialized().Wait(); + return serviceProvider; + } } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/DelegateReference.cs b/DUI3/Speckle.Connectors.DUI/Eventing/DelegateReference.cs index 8601359a9..c268769f8 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/DelegateReference.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/DelegateReference.cs @@ -1,97 +1,73 @@ using System.Reflection; +using System.Runtime.CompilerServices; +using Speckle.Sdk.Common; namespace Speckle.Connectors.DUI.Eventing; -public interface IDelegateReference +public class DelegateReference { - /// - /// 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 WeakOrStrongReference? _weakReference; private readonly MethodInfo _method; - private readonly Type _delegateType; + 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) + public DelegateReference(Delegate @delegate, EventFeatures features) { - if (@delegate == null) - { - throw new ArgumentNullException(nameof(@delegate)); - } - - if (keepReferenceAlive) - { - _delegate = @delegate; - } - else + var target = @delegate.Target; + _method = @delegate.Method; + if (target != null) { - _weakReference = new WeakReference(@delegate.Target); - _method = @delegate.GetMethodInfo(); - _delegateType = @delegate.GetType(); - } - } + //anonymous methods are always strong....should we do this? - doing a brief search says yes + if ( + features.HasFlag(EventFeatures.ForceStrongReference) + || Attribute.IsDefined(_method.DeclaringType.NotNull(), typeof(CompilerGeneratedAttribute)) + ) + { + _weakReference = WeakOrStrongReference.CreateStrong(target); + } + else + { + _weakReference = WeakOrStrongReference.CreateWeak(target); + } - /// - /// 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) + var messageType = @delegate.Method.GetParameters()[0].ParameterType; + if (features.HasFlag(EventFeatures.IsAsync)) { - return _delegate; + _delegateType = typeof(Func<,>).MakeGenericType(messageType, typeof(Task)); } else { - return TryGetDelegate(); + _delegateType = typeof(Action<>).MakeGenericType(messageType); } } + else + { + _weakReference = null; + } } - /// - /// 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) + public bool IsAlive => _weakReference == null || _weakReference.IsAlive; + + public async Task Invoke(object message) { - if (_delegate != null) + if (!IsAlive) { - return _delegate == @delegate; + return false; } - if (@delegate == null) - { - return !_method.IsStatic && !_weakReference.IsAlive; - } - return _weakReference.Target == @delegate.Target && Equals(_method, @delegate.GetMethodInfo()); - } - private Delegate? TryGetDelegate() - { - if (_method.IsStatic) + object? target = null; + if (_weakReference != null) { - return _method.CreateDelegate(_delegateType, null); + target = _weakReference.Target; } - object target = _weakReference.Target; - if (target != null) + var method = Delegate.CreateDelegate(_delegateType.NotNull(), target, _method); + + var task = method.DynamicInvoke(message) as Task; + + if (task is not null) { - return _method.CreateDelegate(_delegateType, target); + await task; } - return null; + + return true; } } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/EventBase.cs b/DUI3/Speckle.Connectors.DUI/Eventing/EventBase.cs index d0186bbce..09911fbb0 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/EventBase.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/EventBase.cs @@ -6,87 +6,32 @@ public abstract class EventBase { private readonly List _subscriptions = new(); - 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) + protected SubscriptionToken InternalSubscribe(IEventSubscription eventSubscription) { - if (eventSubscription == null) + lock (_subscriptions) { - throw new ArgumentNullException(nameof(eventSubscription)); - } - - eventSubscription.SubscriptionToken = new SubscriptionToken(Unsubscribe); - - lock (Subscriptions) - { - Subscriptions.Add(eventSubscription); + _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) + protected async Task InternalPublish(params object[] arguments) { - List> executionStrategies = PruneAndReturnStrategies(); + var 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; + await executionStrategy(arguments); } } - private List> PruneAndReturnStrategies() + private IEnumerable> PruneAndReturnStrategies() { - List> returnList = new(); - - lock (Subscriptions) + lock (_subscriptions) { - for (var i = Subscriptions.Count - 1; i >= 0; i--) + for (var i = _subscriptions.Count - 1; i >= 0; i--) { - Action? listItem = _subscriptions[i].GetExecutionStrategy(); + var listItem = _subscriptions[i].GetExecutionStrategy(); if (listItem == null) { @@ -95,22 +40,39 @@ private List> PruneAndReturnStrategies() } else { - returnList.Add(listItem); + yield return listItem; } } } + } + + public void Unsubscribe(SubscriptionToken token) + { + lock (_subscriptions) + { + IEventSubscription? subscription = _subscriptions.FirstOrDefault(evt => evt.SubscriptionToken.Equals(token)); + if (subscription != null) + { + _subscriptions.Remove(subscription); + token.Unsubscribe(); //calling dispose is circular + } + } + } - return returnList; + public bool Contains(SubscriptionToken token) + { + lock (_subscriptions) + { + IEventSubscription subscription = _subscriptions.FirstOrDefault(evt => evt.SubscriptionToken == token); + return subscription != null; + } } - /// - /// Forces the PubSubEvent to remove any subscriptions that no longer have an execution strategy. - /// public void Prune() { - lock (Subscriptions) + lock (_subscriptions) { - for (var i = Subscriptions.Count - 1; i >= 0; i--) + for (var i = _subscriptions.Count - 1; i >= 0; i--) { if (_subscriptions[i].GetExecutionStrategy() == null) { diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/EventFeatures.cs b/DUI3/Speckle.Connectors.DUI/Eventing/EventFeatures.cs new file mode 100644 index 000000000..95b9cb6bc --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Eventing/EventFeatures.cs @@ -0,0 +1,11 @@ +// ReSharper disable InconsistentNaming +namespace Speckle.Connectors.DUI.Eventing; + +[Flags] +public enum EventFeatures +{ + None = 0, + OneTime = 1, + IsAsync = 2, + ForceStrongReference = 4 +} diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs index 25543e4cd..a05fde4d5 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/EventSubscription.cs @@ -1,139 +1,56 @@ -using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.Common.Threading; +using Speckle.Connectors.DUI.Bridge; namespace Speckle.Connectors.DUI.Eventing; -public interface IEventSubscription +public class EventSubscription( + DelegateReference actionReference, + IThreadContext threadContext, + ITopLevelExceptionHandler exceptionHandler, + SubscriptionToken token, + ThreadOption threadOption, + EventFeatures features +) : IEventSubscription + where TPayload : notnull { - /// - /// Gets or sets a that identifies this . - /// - /// A token that identifies this . - SubscriptionToken SubscriptionToken { get; set; } + public SubscriptionToken SubscriptionToken => token; - /// - /// 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(); -} - -/// -/// 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; - private readonly ITopLevelExceptionHandler _exceptionHandler; - - /// - /// 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, - ITopLevelExceptionHandler exceptionHandler - ) + public Func? GetExecutionStrategy() { - if (actionReference == null) - { - throw new ArgumentNullException(nameof(actionReference)); - } - - if (actionReference.Target is not Action) - { - throw new ArgumentException(null, nameof(actionReference)); - } - - if (filterReference == null) + if (!actionReference.IsAlive) { - throw new ArgumentNullException(nameof(filterReference)); + return null; } - - if (filterReference.Target is not Predicate) + return async arguments => { - throw new ArgumentException(null, nameof(filterReference)); - } - - _actionReference = actionReference; - _filterReference = filterReference; - _exceptionHandler = exceptionHandler; + TPayload argument = (TPayload)arguments[0]; + await InvokeAction(argument); + }; } - /// - /// 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() + private async Task InvokeAction(TPayload argument) { - Action? action = Action; - if (action is null) + switch (threadOption) { - return null; + case ThreadOption.MainThread: + await threadContext.RunOnMainAsync(() => Invoke(argument)); + break; + case ThreadOption.WorkerThread: + await threadContext.RunOnWorkerAsync(() => Invoke(argument)); + break; + case ThreadOption.PublisherThread: + default: + await Invoke(argument); + break; } - 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) + private async Task Invoke(TPayload argument) { - if (action == null) + await exceptionHandler.CatchUnhandledAsync(() => actionReference.Invoke(argument)); + if (features.HasFlag(EventFeatures.OneTime)) { - throw new ArgumentNullException(nameof(action)); + SubscriptionToken.Dispose(); } - - _exceptionHandler.CatchUnhandled(() => action(argument)); } } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/IEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/IEventSubscription.cs new file mode 100644 index 000000000..64286c1d9 --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Eventing/IEventSubscription.cs @@ -0,0 +1,8 @@ +namespace Speckle.Connectors.DUI.Eventing; + +public interface IEventSubscription +{ + SubscriptionToken SubscriptionToken { get; } + + Func? GetExecutionStrategy(); +} diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs deleted file mode 100644 index c524f027f..000000000 --- a/DUI3/Speckle.Connectors.DUI/Eventing/MainThreadEventSubscription.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Speckle.Connectors.Common.Threading; -using Speckle.Connectors.DUI.Bridge; - -namespace Speckle.Connectors.DUI.Eventing; - -public class MainThreadEventSubscription( - IDelegateReference actionReference, - IDelegateReference filterReference, - IThreadContext threadContext, - 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 deleted file mode 100644 index f58e102e6..000000000 --- a/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeEventSubscription.cs +++ /dev/null @@ -1,20 +0,0 @@ -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 index 2fadb2966..75e41531b 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/OneTimeThreadedEvent.cs @@ -4,64 +4,64 @@ namespace Speckle.Connectors.DUI.Eventing; public abstract class OneTimeThreadedEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) - : ThreadedEvent(threadContext, exceptionHandler) + : SpeckleEvent(threadContext, exceptionHandler), + IDisposable where T : notnull { + private readonly SemaphoreSlim _semaphore = new(1, 1); private readonly Dictionary _activeTokens = new(); - public SubscriptionToken OneTimeSubscribe( - string id, - Func action, - ThreadOption threadOption = ThreadOption.PublisherThread, - bool keepSubscriberReferenceAlive = false, - Predicate? filter = null - ) + protected virtual void Dispose(bool isDisposing) { - return OneTimeInternal(id, t => action(t), threadOption, keepSubscriberReferenceAlive, filter); + if (isDisposing) + { + _semaphore.Dispose(); + } } - public SubscriptionToken OneTimeSubscribe( - string id, - Func action, - ThreadOption threadOption = ThreadOption.PublisherThread, - bool keepSubscriberReferenceAlive = false, - Predicate? filter = null - ) + public void Dispose() { - return OneTimeInternal(id, _ => action(), threadOption, keepSubscriberReferenceAlive, filter); + Dispose(true); + GC.SuppressFinalize(this); } - public SubscriptionToken OneTimeSubscribe( - string id, - Action action, - ThreadOption threadOption = ThreadOption.PublisherThread, - bool keepSubscriberReferenceAlive = false, - Predicate? filter = null - ) - { - return OneTimeInternal(id, action, threadOption, keepSubscriberReferenceAlive, filter); - } + ~OneTimeThreadedEvent() => Dispose(false); public SubscriptionToken OneTimeSubscribe( string id, - Action action, - ThreadOption threadOption = ThreadOption.PublisherThread, - bool keepSubscriberReferenceAlive = false, - Predicate? filter = null + Func action, + ThreadOption threadOption = ThreadOption.PublisherThread ) { - return OneTimeInternal(id, _ => action(), threadOption, keepSubscriberReferenceAlive, filter); + _semaphore.Wait(); + try + { + if (_activeTokens.TryGetValue(id, out var token)) + { + if (token.IsActive) + { + return token; + } + _activeTokens.Remove(id); + } + token = Subscribe(action, threadOption, EventFeatures.OneTime); + _activeTokens.Add(id, token); + return token; + } + finally + { + _semaphore.Release(); + } } - private SubscriptionToken OneTimeInternal( + public SubscriptionToken OneTimeSubscribe( string id, Action action, - ThreadOption threadOption, - bool keepSubscriberReferenceAlive, - Predicate? filter + ThreadOption threadOption = ThreadOption.PublisherThread ) { - lock (_activeTokens) + _semaphore.Wait(); + try { if (_activeTokens.TryGetValue(id, out var token)) { @@ -71,22 +71,32 @@ private SubscriptionToken OneTimeInternal( } _activeTokens.Remove(id); } - token = SubscribeOnceOrNot(action, threadOption, keepSubscriberReferenceAlive, filter, true); + token = Subscribe(action, threadOption, EventFeatures.OneTime); _activeTokens.Add(id, token); return token; } + finally + { + _semaphore.Release(); + } } - public override void Publish(T payload) + public override async Task PublishAsync(T payload) { - lock (_activeTokens) + await _semaphore.WaitAsync(); + try { - base.Publish(payload); + await base.PublishAsync(payload); foreach (var token in _activeTokens.Values) { token.Dispose(); } + _activeTokens.Clear(); } + finally + { + _semaphore.Release(); + } } } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs deleted file mode 100644 index 929015432..000000000 --- a/DUI3/Speckle.Connectors.DUI/Eventing/PubSubEvent.cs +++ /dev/null @@ -1,138 +0,0 @@ -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) => 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) => - 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) => - 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) => - 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 - ) => 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/Eventing/SpeckleEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs new file mode 100644 index 000000000..9414c00dd --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Eventing/SpeckleEvent.cs @@ -0,0 +1,40 @@ +using System.Diagnostics.CodeAnalysis; +using Speckle.Connectors.Common.Threading; +using Speckle.Connectors.DUI.Bridge; + +namespace Speckle.Connectors.DUI.Eventing; + +public abstract class SpeckleEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) + : EventBase, + ISpeckleEvent + where T : notnull +{ + public string Name { get; } = typeof(T).Name; + + public virtual Task PublishAsync(T payload) => InternalPublish(payload); + + protected SubscriptionToken Subscribe(Func action, ThreadOption threadOption, EventFeatures features) + { + features |= EventFeatures.IsAsync; + var actionReference = new DelegateReference(action, features); + return Subscribe(actionReference, threadOption, features); + } + + protected SubscriptionToken Subscribe(Action action, ThreadOption threadOption, EventFeatures features) + { + var actionReference = new DelegateReference(action, features); + return Subscribe(actionReference, threadOption, features); + } + + [SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope")] + private SubscriptionToken Subscribe( + DelegateReference actionReference, + ThreadOption threadOption, + EventFeatures features + ) + { + EventSubscription subscription = + new(actionReference, threadContext, exceptionHandler, new(Unsubscribe), threadOption, features); + return InternalSubscribe(subscription); + } +} diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/SubscriptionToken.cs b/DUI3/Speckle.Connectors.DUI/Eventing/SubscriptionToken.cs index 64f92b127..72ba66afc 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/SubscriptionToken.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/SubscriptionToken.cs @@ -32,17 +32,27 @@ public override bool Equals(object? obj) public bool IsActive => _unsubscribeAction != null; + public void Unsubscribe() => _unsubscribeAction = null; + + ~SubscriptionToken() => Dispose(false); + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool isDisposing) { // 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) + if (isDisposing && _unsubscribeAction != null) { _unsubscribeAction(this); - _unsubscribeAction = null; + Unsubscribe(); } } } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs index 30d8ed2de..95f714191 100644 --- a/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs +++ b/DUI3/Speckle.Connectors.DUI/Eventing/ThreadedEvent.cs @@ -4,84 +4,12 @@ namespace Speckle.Connectors.DUI.Eventing; public abstract class ThreadedEvent(IThreadContext threadContext, ITopLevelExceptionHandler exceptionHandler) - : PubSubEvent, - ISpeckleEvent + : SpeckleEvent(threadContext, exceptionHandler) where T : notnull { - public string Name { get; } = typeof(T).Name; + public SubscriptionToken Subscribe(Func action, ThreadOption threadOption = ThreadOption.PublisherThread) => + Subscribe(action, threadOption, EventFeatures.None); - public SubscriptionToken Subscribe( - Func action, - ThreadOption threadOption, - bool keepSubscriberReferenceAlive, - Predicate? filter - ) - { - return SubscribeOnceOrNot(t => action(t), threadOption, keepSubscriberReferenceAlive, filter, false); - } - - public override SubscriptionToken Subscribe( - Action action, - ThreadOption threadOption, - 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; - 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, - isOnce - ); - break; - case ThreadOption.MainThread: - subscription = new MainThreadEventSubscription( - actionReference, - filterReference, - threadContext, - exceptionHandler, - isOnce - ); - break; - case ThreadOption.PublisherThread: - default: - subscription = new OneTimeEventSubscription(actionReference, filterReference, exceptionHandler, isOnce); - break; - } - return InternalSubscribe(subscription); - } + public SubscriptionToken Subscribe(Action action, ThreadOption threadOption = ThreadOption.PublisherThread) => + Subscribe(action, threadOption, EventFeatures.None); } diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/WeakOrStrongReference.cs b/DUI3/Speckle.Connectors.DUI/Eventing/WeakOrStrongReference.cs new file mode 100644 index 000000000..98d20ea20 --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Eventing/WeakOrStrongReference.cs @@ -0,0 +1,24 @@ +using Speckle.Sdk.Common; + +namespace Speckle.Connectors.DUI.Eventing; + +public class WeakOrStrongReference(WeakReference? weakReference, object? strongReference) +{ + public static WeakOrStrongReference CreateWeak(object? reference) => new(new WeakReference(reference), null); + + public static WeakOrStrongReference CreateStrong(object? reference) => new(null, reference); + + public bool IsAlive => weakReference?.IsAlive ?? true; + + public object Target + { + get + { + if (strongReference is not null) + { + return strongReference; + } + return (weakReference?.Target).NotNull(); + } + } +} diff --git a/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs b/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs deleted file mode 100644 index 1083987be..000000000 --- a/DUI3/Speckle.Connectors.DUI/Eventing/WorkerEventSubscription.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Speckle.Connectors.Common.Threading; -using Speckle.Connectors.DUI.Bridge; - -namespace Speckle.Connectors.DUI.Eventing; - -public class WorkerEventSubscription( - IDelegateReference actionReference, - IDelegateReference filterReference, - IThreadContext threadContext, - ITopLevelExceptionHandler exceptionHandler, - bool isOnce -) : OneTimeEventSubscription(actionReference, filterReference, exceptionHandler, isOnce) -{ - public override void InvokeAction(Action action, TPayload argument) => - threadContext.RunOnWorker(() => action(argument)); -} diff --git a/DUI3/Speckle.Connectors.DUI/Models/DocumentModelStore.cs b/DUI3/Speckle.Connectors.DUI/Models/DocumentModelStore.cs index 9b6622c50..b42cd2a0e 100644 --- a/DUI3/Speckle.Connectors.DUI/Models/DocumentModelStore.cs +++ b/DUI3/Speckle.Connectors.DUI/Models/DocumentModelStore.cs @@ -25,6 +25,8 @@ public IReadOnlyList Models } } + public virtual Task OnDocumentStoreInitialized() => Task.CompletedTask; + public virtual bool IsDocumentInit { get; set; } // TODO: not sure about this, throwing an exception, needs some thought...