diff --git a/.editorconfig b/.editorconfig index 32ff38613..416023432 100644 --- a/.editorconfig +++ b/.editorconfig @@ -254,6 +254,9 @@ dotnet_diagnostic.ca1508.severity = warning # Avoid dead conditional code dotnet_diagnostic.ca1509.severity = warning # Invalid entry in code metrics configuration file dotnet_diagnostic.ca1861.severity = none # Prefer 'static readonly' fields over constant array arguments if the called method is called repeatedly and is not mutating the passed array (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1861) +# CA2007: Consider calling ConfigureAwait on the awaited task (this is not needed for application code, in fact we don't want to call anything but ConfigureAwait(true) which is the default) +dotnet_diagnostic.CA2007.severity = none + dotnet_diagnostic.cs8618.severity = suggestion # nullable problem diff --git a/Build/Github.cs b/Build/Github.cs index b62ddeb39..9c9f335a1 100644 --- a/Build/Github.cs +++ b/Build/Github.cs @@ -28,11 +28,11 @@ public static async Task BuildInstallers(string token, string runId, string vers Content = content }; request.Headers.Add("X-GitHub-Api-Version", "2022-11-28"); - var response = await client.SendAsync(request).ConfigureAwait(false); + var response = await client.SendAsync(request); if (!response.IsSuccessStatusCode) { throw new InvalidOperationException( - $"{response.StatusCode} {response.ReasonPhrase} {await response.Content.ReadAsStringAsync().ConfigureAwait(false)}" + $"{response.StatusCode} {response.ReasonPhrase} {await response.Content.ReadAsStringAsync()}" ); } } diff --git a/Build/Program.cs b/Build/Program.cs index 8604c198c..3eb8dac67 100644 --- a/Build/Program.cs +++ b/Build/Program.cs @@ -98,7 +98,7 @@ void RemoveDirectory(string d) VERSION, async () => { - var (output, _) = await ReadAsync("dotnet", "minver -v w").ConfigureAwait(false); + var (output, _) = await ReadAsync("dotnet", "minver -v w"); output = output.Trim(); Console.WriteLine($"Version: {output}"); Run("echo", $"\"version={output}\" >> $GITHUB_OUTPUT"); diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISReceiveBinding.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISReceiveBinding.cs index ef35bc039..e78caa1ea 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISReceiveBinding.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISReceiveBinding.cs @@ -78,17 +78,14 @@ public async Task Receive(string modelCardId) modelCard.GetReceiveInfo("ArcGIS"), // POC: get host app name from settings? same for GetSendInfo _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationToken), cancellationToken - ) - .ConfigureAwait(false); + ); modelCard.BakedObjectIds = receiveOperationResults.BakedObjectIds.ToList(); - await Commands - .SetModelReceiveResult( - modelCardId, - receiveOperationResults.BakedObjectIds, - receiveOperationResults.ConversionResults - ) - .ConfigureAwait(false); + await Commands.SetModelReceiveResult( + modelCardId, + receiveOperationResults.BakedObjectIds, + receiveOperationResults.ConversionResults + ); } catch (OperationCanceledException) { @@ -100,7 +97,7 @@ await Commands catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation { _logger.LogModelCardHandledError(ex); - await Commands.SetModelError(modelCardId, ex).ConfigureAwait(false); + await Commands.SetModelError(modelCardId, ex); } } diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs index 1b3dcb613..3fb41ec51 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; @@ -93,32 +92,22 @@ MapMembersUtils mapMemberUtils private void SubscribeToArcGISEvents() { LayersRemovedEvent.Subscribe( - a => - _topLevelExceptionHandler.FireAndForget(async () => await GetIdsForLayersRemovedEvent(a).ConfigureAwait(false)), + a => _topLevelExceptionHandler.FireAndForget(async () => await GetIdsForLayersRemovedEvent(a)), true ); StandaloneTablesRemovedEvent.Subscribe( - a => - _topLevelExceptionHandler.FireAndForget( - async () => await GetIdsForStandaloneTablesRemovedEvent(a).ConfigureAwait(false) - ), + a => _topLevelExceptionHandler.FireAndForget(async () => await GetIdsForStandaloneTablesRemovedEvent(a)), true ); MapPropertyChangedEvent.Subscribe( - a => - _topLevelExceptionHandler.FireAndForget( - async () => await GetIdsForMapPropertyChangedEvent(a).ConfigureAwait(false) - ), + a => _topLevelExceptionHandler.FireAndForget(async () => await GetIdsForMapPropertyChangedEvent(a)), true ); // Map units, CRS etc. MapMemberPropertiesChangedEvent.Subscribe( - a => - _topLevelExceptionHandler.FireAndForget( - async () => await GetIdsForMapMemberPropertiesChangedEvent(a).ConfigureAwait(false) - ), + a => _topLevelExceptionHandler.FireAndForget(async () => await GetIdsForMapMemberPropertiesChangedEvent(a)), true ); // e.g. Layer name @@ -139,28 +128,24 @@ private void SubscribeToArcGISEvents() private void SubscribeToMapMembersDataSourceChange() { - var task = QueuedTask.Run(() => + if (MapView.Active == null) { - if (MapView.Active == null) - { - return; - } + 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); } - }); - task.Wait(); + } + // subscribe to tables + foreach (StandaloneTable table in MapView.Active.Map.StandaloneTables) + { + SubscribeToTableDataSourceChange(table); + } } private void SubscribeToFeatureLayerDataSourceChange(FeatureLayer layer) @@ -197,7 +182,7 @@ private void SubscribeToAnyDataSourceChange(Table layerTable) (args) => Parent.TopLevelExceptionHandler.FireAndForget(async () => { - await OnRowChanged(args).ConfigureAwait(false); + await OnRowChanged(args); }), layerTable ); @@ -205,7 +190,7 @@ private void SubscribeToAnyDataSourceChange(Table layerTable) (args) => Parent.TopLevelExceptionHandler.FireAndForget(async () => { - await OnRowChanged(args).ConfigureAwait(false); + await OnRowChanged(args); }), layerTable ); @@ -213,7 +198,7 @@ private void SubscribeToAnyDataSourceChange(Table layerTable) (args) => Parent.TopLevelExceptionHandler.FireAndForget(async () => { - await OnRowChanged(args).ConfigureAwait(false); + await OnRowChanged(args); }), layerTable ); @@ -258,7 +243,7 @@ private async Task OnRowChanged(RowChangedEventArgs args) } } - await RunExpirationChecks(false).ConfigureAwait(false); + await RunExpirationChecks(false); } private async Task GetIdsForLayersRemovedEvent(LayerEventsArgs args) @@ -267,7 +252,7 @@ private async Task GetIdsForLayersRemovedEvent(LayerEventsArgs args) { ChangedObjectIds[layer.URI] = 1; } - await RunExpirationChecks(true).ConfigureAwait(false); + await RunExpirationChecks(true); } private async Task GetIdsForStandaloneTablesRemovedEvent(StandaloneTableEventArgs args) @@ -276,7 +261,7 @@ private async Task GetIdsForStandaloneTablesRemovedEvent(StandaloneTableEventArg { ChangedObjectIds[table.URI] = 1; } - await RunExpirationChecks(true).ConfigureAwait(false); + await RunExpirationChecks(true); } private async Task GetIdsForMapPropertyChangedEvent(MapPropertyChangedEventArgs args) @@ -289,7 +274,7 @@ private async Task GetIdsForMapPropertyChangedEvent(MapPropertyChangedEventArgs ChangedObjectIds[member.URI] = 1; } } - await RunExpirationChecks(false).ConfigureAwait(false); + await RunExpirationChecks(false); } private void GetIdsForLayersAddedEvent(LayerEventsArgs args) @@ -339,7 +324,7 @@ private async Task GetIdsForMapMemberPropertiesChangedEvent(MapMemberPropertiesC { ChangedObjectIds[member.URI] = 1; } - await RunExpirationChecks(false).ConfigureAwait(false); + await RunExpirationChecks(false); } } @@ -366,64 +351,52 @@ 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>() + .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) { - 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 result = 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); - - return result; - }) - .ConfigureAwait(false); - - await Commands - .SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults) - .ConfigureAwait(false); + 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 + ); + + await Commands.SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults); } catch (OperationCanceledException) { @@ -435,7 +408,7 @@ await Commands catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation { _logger.LogModelCardHandledError(ex); - await Commands.SetModelError(modelCardId, ex).ConfigureAwait(false); + await Commands.SetModelError(modelCardId, ex); } } @@ -470,7 +443,7 @@ private async Task RunExpirationChecks(bool idsDeleted) } } - await Commands.SetModelsExpired(expiredSenderIds).ConfigureAwait(false); + await Commands.SetModelsExpired(expiredSenderIds); ChangedObjectIds = new(); } } diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs index 13e0d315c..d3881899e 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; @@ -32,7 +31,7 @@ public BasicConnectorBinding(DocumentModelStore store, IBrowserBridge parent, IS _store.DocumentChanged += (_, _) => parent.TopLevelExceptionHandler.FireAndForget(async () => { - await Commands.NotifyDocumentChanged().ConfigureAwait(false); + await Commands.NotifyDocumentChanged(); }); } @@ -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); - SelectMapMembersAndFeatures(mapMembersFeatures); - mapView.ZoomToSelected(); - }) - .ConfigureAwait(false); + List mapMembersFeatures = GetMapMembers(objectIds, mapView); + ClearSelectionInTOC(); + ClearSelection(); + SelectMapMembersInTOC(mapMembersFeatures); + SelectMapMembersAndFeatures(mapMembersFeatures); + mapView.ZoomToSelected(); } 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 d6b57a0ce..301c13272 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs @@ -27,7 +27,7 @@ public static class ArcGISConnectorModule public static void AddArcGIS(this IServiceCollection serviceCollection) { serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); serviceCollection.AddDUIView(); // Register bindings diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/HostApp/ArcGISColorManager.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/HostApp/ArcGISColorManager.cs index eabf069bf..2ac406ca4 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/HostApp/ArcGISColorManager.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/HostApp/ArcGISColorManager.cs @@ -25,7 +25,7 @@ public class ArcGISColorManager /// /// /// - 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(); @@ -33,7 +33,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(); @@ -58,7 +54,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/HostApp/ArcGISLayerUnpacker.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/HostApp/ArcGISLayerUnpacker.cs index b8955f895..3db6653e0 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/HostApp/ArcGISLayerUnpacker.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/HostApp/ArcGISLayerUnpacker.cs @@ -18,7 +18,7 @@ public class ArcGISLayerUnpacker /// /// List of layers containing objects. /// Thrown when this method is *not* called on the MCT, because this method accesses mapmember fields - public async Task> UnpackSelectionAsync( + public List UnpackSelection( IEnumerable mapMembers, Collection parentCollection, List? objects = null @@ -37,7 +37,7 @@ public class ArcGISLayerUnpacker Collection containerCollection = CreateAndCacheMapMemberCollection(mapMember, true); parentCollection.elements.Add(containerCollection); - await UnpackSelectionAsync(container.Layers, containerCollection, objects).ConfigureAwait(false); + UnpackSelection(container.Layers, containerCollection, objects); break; default: diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/ArcGISHostObjectBuilder.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/ArcGISHostObjectBuilder.cs index fa71580fe..5a9ce6512 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; @@ -54,7 +53,7 @@ ArcGISColorManager colorManager _colorManager = colorManager; } - public async Task Build( + public HostObjectBuilderResult Build( Base rootObject, string projectName, string modelName, @@ -74,14 +73,14 @@ CancellationToken cancellationToken .ToList(); if (materials != null) { - await _colorManager.ParseMaterials(materials, onOperationProgressed).ConfigureAwait(false); + _colorManager.ParseMaterials(materials, onOperationProgressed); } // get colors List? colors = (rootObject[ProxyKeys.COLOR] as List)?.Cast().ToList(); if (colors != null) { - await _colorManager.ParseColors(colors, onOperationProgressed).ConfigureAwait(false); + _colorManager.ParseColors(colors, onOperationProgressed); } int count = 0; @@ -100,7 +99,7 @@ CancellationToken cancellationToken try { obj = _localToGlobalConverterUtils.TransformObjects(objectToConvert.AtomicObject, objectToConvert.Matrix); - object? conversionResult = await QueuedTask.Run(() => _converter.Convert(obj)).ConfigureAwait(false); + object conversionResult = _converter.Convert(obj); string nestedLayerPath = $"{string.Join("\\", path)}"; @@ -128,29 +127,20 @@ CancellationToken cancellationToken // 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 @@ -202,8 +192,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); @@ -231,7 +220,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)); @@ -298,80 +287,72 @@ 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}"); - 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 (MapMember)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); } - }) - .ConfigureAwait(false); + } + + 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/Operations/Send/ArcGISRootObjectBuilder.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs index 97d7f9587..aae2c1c24 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs @@ -1,6 +1,5 @@ using ArcGIS.Core.Data.Raster; using ArcGIS.Core.Geometry; -using ArcGIS.Desktop.Framework.Threading.Tasks; using Microsoft.Extensions.Logging; using Speckle.Connectors.ArcGIS.HostApp; using Speckle.Connectors.ArcGIS.HostApp.Extensions; @@ -54,11 +53,11 @@ MapMembersUtils mapMemberUtils _mapMemberUtils = mapMemberUtils; } - public async Task Build( + public RootObjectBuilderResult Build( IReadOnlyList layers, SendInfo sendInfo, IProgress onOperationProgressed, - CancellationToken ct = default + CancellationToken cancellationToken ) { // TODO: add a warning if Geographic CRS is set @@ -103,9 +102,7 @@ public async Task Build( IEnumerable layersOrdered = _mapMemberUtils.GetMapMembersInOrder(map, layers); using (var _ = _activityFactory.Start("Unpacking selection")) { - unpackedLayers = await QueuedTask - .Run(() => _layerUnpacker.UnpackSelectionAsync(layersOrdered, rootCollection)) - .ConfigureAwait(false); + unpackedLayers = _layerUnpacker.UnpackSelection(layersOrdered, rootCollection); } List results = new(unpackedLayers.Count); @@ -115,7 +112,7 @@ public async Task Build( int count = 0; foreach (ADM.MapMember layer in unpackedLayers) { - ct.ThrowIfCancellationRequested(); + cancellationToken.ThrowIfCancellationRequested(); string layerApplicationId = layer.GetSpeckleApplicationId(); try @@ -141,21 +138,15 @@ out ObjectReference? value switch (layer) { case ADM.FeatureLayer featureLayer: - List convertedFeatureLayerObjects = await QueuedTask - .Run(() => ConvertFeatureLayerObjectsAsync(featureLayer)) - .ConfigureAwait(false); + List convertedFeatureLayerObjects = ConvertFeatureLayerObjects(featureLayer); layerCollection.elements.AddRange(convertedFeatureLayerObjects); break; case ADM.RasterLayer rasterLayer: - List convertedRasterLayerObjects = await QueuedTask - .Run(() => ConvertRasterLayerObjectsAsync(rasterLayer)) - .ConfigureAwait(false); + List convertedRasterLayerObjects = ConvertRasterLayerObjects(rasterLayer); layerCollection.elements.AddRange(convertedRasterLayerObjects); break; case ADM.LasDatasetLayer lasDatasetLayer: - List convertedLasDatasetObjects = await QueuedTask - .Run(() => ConvertLasDatasetLayerObjectsAsync(lasDatasetLayer)) - .ConfigureAwait(false); + List convertedLasDatasetObjects = ConvertLasDatasetLayerObjects(lasDatasetLayer); layerCollection.elements.AddRange(convertedLasDatasetObjects); break; default: @@ -194,96 +185,78 @@ out ObjectReference? value return new RootObjectBuilderResult(rootCollection, results); } - private async Task> ConvertFeatureLayerObjectsAsync(ADM.FeatureLayer featureLayer) + private List ConvertFeatureLayerObjects(ADM.FeatureLayer featureLayer) { string layerApplicationId = featureLayer.GetSpeckleApplicationId(); List convertedObjects = new(); - await QueuedTask - .Run(() => - { - // store the layer renderer for color unpacking - _colorUnpacker.StoreRendererAndFields(featureLayer); + // store the layer renderer for color unpacking + _colorUnpacker.StoreRendererAndFields(featureLayer); - // search the rows of the layer, where each row is treated like an object - // RowCursor is IDisposable but is not being correctly picked up by IDE warnings. - // This means we need to be carefully adding using statements based on the API documentation coming from each method/class - using (ACD.RowCursor rowCursor = featureLayer.Search()) + // search the rows of the layer, where each row is treated like an object + // RowCursor is IDisposable but is not being correctly picked up by IDE warnings. + // This means we need to be carefully adding using statements based on the API documentation coming from each method/class + using (ACD.RowCursor rowCursor = featureLayer.Search()) + { + while (rowCursor.MoveNext()) + { + // Same IDisposable issue appears to happen on Row class too. Docs say it should always be disposed of manually by the caller. + using (ACD.Row row = rowCursor.Current) { - while (rowCursor.MoveNext()) - { - // Same IDisposable issue appears to happen on Row class too. Docs say it should always be disposed of manually by the caller. - using (ACD.Row row = rowCursor.Current) - { - // get application id. test for subtypes before defaulting to base type. - Base converted = _rootToSpeckleConverter.Convert(row); - string applicationId = row.GetSpeckleApplicationId(layerApplicationId); - converted.applicationId = applicationId; + // get application id. test for subtypes before defaulting to base type. + Base converted = _rootToSpeckleConverter.Convert(row); + string applicationId = row.GetSpeckleApplicationId(layerApplicationId); + converted.applicationId = applicationId; - convertedObjects.Add(converted); + convertedObjects.Add(converted); - // process the object color - _colorUnpacker.ProcessFeatureLayerColor(row, applicationId); - } - } + // process the object color + _colorUnpacker.ProcessFeatureLayerColor(row, applicationId); } - }) - .ConfigureAwait(false); + } + } return convertedObjects; } // POC: raster colors are stored as mesh vertex colors in RasterToSpeckleConverter. Should probably move to color unpacker. - private async Task> ConvertRasterLayerObjectsAsync(ADM.RasterLayer rasterLayer) + private List ConvertRasterLayerObjects(ADM.RasterLayer rasterLayer) { string layerApplicationId = rasterLayer.GetSpeckleApplicationId(); List convertedObjects = new(); - await QueuedTask - .Run(() => - { - Raster raster = rasterLayer.GetRaster(); - Base converted = _rootToSpeckleConverter.Convert(raster); - string applicationId = raster.GetSpeckleApplicationId(layerApplicationId); - converted.applicationId = applicationId; - convertedObjects.Add(converted); - }) - .ConfigureAwait(false); - + Raster raster = rasterLayer.GetRaster(); + Base converted = _rootToSpeckleConverter.Convert(raster); + string applicationId = raster.GetSpeckleApplicationId(layerApplicationId); + converted.applicationId = applicationId; + convertedObjects.Add(converted); return convertedObjects; } - private async Task> ConvertLasDatasetLayerObjectsAsync(ADM.LasDatasetLayer lasDatasetLayer) + private List ConvertLasDatasetLayerObjects(ADM.LasDatasetLayer lasDatasetLayer) { string layerApplicationId = lasDatasetLayer.GetSpeckleApplicationId(); List convertedObjects = new(); try { - await QueuedTask - .Run(() => - { - // store the layer renderer for color unpacking - _colorUnpacker.StoreRenderer(lasDatasetLayer); + // store the layer renderer for color unpacking + _colorUnpacker.StoreRenderer(lasDatasetLayer); - using ( - ACD.Analyst3D.LasPointCursor ptCursor = lasDatasetLayer.SearchPoints(new ACD.Analyst3D.LasPointFilter()) - ) + using (ACD.Analyst3D.LasPointCursor ptCursor = lasDatasetLayer.SearchPoints(new ACD.Analyst3D.LasPointFilter())) + { + while (ptCursor.MoveNext()) + { + using (ACD.Analyst3D.LasPoint pt = ptCursor.Current) { - while (ptCursor.MoveNext()) - { - using (ACD.Analyst3D.LasPoint pt = ptCursor.Current) - { - Base converted = _rootToSpeckleConverter.Convert(pt); - string applicationId = pt.GetSpeckleApplicationId(layerApplicationId); - converted.applicationId = applicationId; - convertedObjects.Add(converted); + Base converted = _rootToSpeckleConverter.Convert(pt); + string applicationId = pt.GetSpeckleApplicationId(layerApplicationId); + converted.applicationId = applicationId; + convertedObjects.Add(converted); - // process the object color - _colorUnpacker.ProcessLasLayerColor(pt, applicationId); - } - } + // process the object color + _colorUnpacker.ProcessLasLayerColor(pt, applicationId); } - }) - .ConfigureAwait(false); + } + } } catch (ACD.Exceptions.TinException ex) { diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/SpeckleDUI3ViewModel.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/SpeckleDUI3ViewModel.cs index 9d74daac4..2406f8398 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/SpeckleDUI3ViewModel.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/SpeckleDUI3ViewModel.cs @@ -18,7 +18,7 @@ internal static void Create() /// protected override async Task InitializeAsync() { - await base.InitializeAsync().ConfigureAwait(false); + await base.InitializeAsync(); } /// @@ -26,7 +26,7 @@ protected override async Task InitializeAsync() /// protected override async Task UninitializeAsync() { - await base.UninitializeAsync().ConfigureAwait(false); + await base.UninitializeAsync(); } } 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/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs new file mode 100644 index 000000000..42297eb00 --- /dev/null +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGISThreadContext.cs @@ -0,0 +1,36 @@ +using ArcGIS.Desktop.Framework.Threading.Tasks; +using Speckle.Connectors.Common.Threading; + +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) + { + if (QueuedTask.OnWorker) + { + return action(); + } + else + { + return QueuedTask.Run(async () => await action()); + } + } + + protected override Task WorkerToMainAsync(Func> action) => QueuedTask.Run(async () => await 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); +} diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/ArcGisDocumentStore.cs index 78be6af1d..0e6e5e1da 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,16 @@ 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( _ => @@ -74,52 +81,52 @@ private void OnMapViewChanged(ActiveMapViewChangedEventArgs args) OnDocumentChanged(); } - 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(); + 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")); + // Parse existing metadata + XDocument existingXmlDocument = !string.IsNullOrEmpty(existingMetadata) + ? XDocument.Parse(existingMetadata) + : new XDocument(new XElement("metadata")); - XElement xmlModelCards = new("SpeckleModelCards", modelCardState); + 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); - } + // 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()); - }); - } + map.SetMetadata(existingXmlDocument.ToString()); + }) + .FireAndForget(); - protected override void LoadState() - { - Map map = MapView.Active.Map; - QueuedTask.Run(() => - { - var metadata = map.GetMetadata(); - var root = XDocument.Parse(metadata).Root; - var element = root?.Element("SpeckleModelCards"); - if (element is null) + protected override void LoadState() => + _threadContext + .RunOnWorker(() => { - ClearAndSave(); - return; - } + 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); - }); - } + string modelsString = element.Value; + LoadFromString(modelsString); + }) + .FireAndForget(); } diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json index ef57faa21..9eeb9e707 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -328,12 +327,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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 9b77d3e6b..13fe3f649 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -367,12 +366,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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 ffe00ab30..268b73b4d 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -367,12 +366,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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 4c8a050fa..c888a99ed 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -368,12 +367,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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 2928286d0..4572ffa2f 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -323,12 +322,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs index 5a976f0fc..e5f8116f8 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs @@ -1,6 +1,7 @@ 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; @@ -19,6 +20,7 @@ public class AutocadBasicConnectorBinding : IBasicConnectorBinding private readonly DocumentModelStore _store; private readonly ISpeckleApplication _speckleApplication; + private readonly IThreadContext _threadContext; private readonly ILogger _logger; public BasicConnectorBindingCommands Commands { get; } @@ -28,7 +30,8 @@ public AutocadBasicConnectorBinding( IBrowserBridge parent, IAccountManager accountManager, ISpeckleApplication speckleApplication, - ILogger logger + ILogger logger, + IThreadContext threadContext ) { _store = store; @@ -39,9 +42,10 @@ ILogger logger _store.DocumentChanged += (_, _) => parent.TopLevelExceptionHandler.FireAndForget(async () => { - await Commands.NotifyDocumentChanged().ConfigureAwait(false); + await Commands.NotifyDocumentChanged(); }); _logger = logger; + _threadContext = threadContext; } public string GetConnectorVersion() => _speckleApplication.SpeckleVersion; @@ -79,7 +83,7 @@ public async Task HighlightObjects(IReadOnlyList objectIds) var dbObjects = doc.GetObjects(objectIds); var acadObjectIds = dbObjects.Select(tuple => tuple.Root.Id).ToArray(); - await HighlightObjectsOnView(acadObjectIds).ConfigureAwait(false); + await HighlightObjectsOnView(acadObjectIds); } public async Task HighlightModel(string modelCardId) @@ -116,79 +120,73 @@ public async Task HighlightModel(string modelCardId) if (objectIds.Length == 0) { - await Commands - .SetModelError(modelCardId, new OperationCanceledException("No objects found to highlight.")) - .ConfigureAwait(false); + await Commands.SetModelError(modelCardId, new OperationCanceledException("No objects found to highlight.")); return; } - await HighlightObjectsOnView(objectIds, modelCardId).ConfigureAwait(false); + await HighlightObjectsOnView(objectIds, modelCardId); } private async Task HighlightObjectsOnView(ObjectId[] objectIds, string? modelCardId = null) { var doc = Application.DocumentManager.MdiActiveDocument; - await Parent - .RunOnMainThreadAsync(async () => + await _threadContext.RunOnMainAsync(async () => + { + try { + doc.Editor.SetImpliedSelection([]); // Deselects try { - doc.Editor.SetImpliedSelection(Array.Empty()); // Deselects - try - { - doc.Editor.SetImpliedSelection(objectIds); - } - catch (Exception e) when (!e.IsFatal()) - { - // SWALLOW REASON: - // If the objects under the blocks, it won't be able to select them. - // If we try, API will throw the invalid input error, because we request something from API that Autocad doesn't - // handle it on its current canvas. Block elements only selectable when in its scope. - } - doc.Editor.UpdateScreen(); + doc.Editor.SetImpliedSelection(objectIds); + } + catch (Exception e) when (!e.IsFatal()) + { + // SWALLOW REASON: + // If the objects under the blocks, it won't be able to select them. + // If we try, API will throw the invalid input error, because we request something from API that Autocad doesn't + // handle it on its current canvas. Block elements only selectable when in its scope. + } + doc.Editor.UpdateScreen(); - Extents3d selectedExtents = new(); + Extents3d selectedExtents = new(); - var tr = doc.TransactionManager.StartTransaction(); - foreach (ObjectId objectId in objectIds) + var tr = doc.TransactionManager.StartTransaction(); + foreach (ObjectId objectId in objectIds) + { + try { - try + var entity = (Entity?)tr.GetObject(objectId, OpenMode.ForRead); + if (entity?.GeometricExtents != null) { - var entity = (Entity?)tr.GetObject(objectId, OpenMode.ForRead); - if (entity?.GeometricExtents != null) - { - selectedExtents.AddExtents(entity.GeometricExtents); - } - } - catch (Exception e) when (!e.IsFatal()) - { - // Note: we're swallowing exeptions here because of a weird case when receiving blocks, we would have - // acad api throw an error on accessing entity.GeometricExtents. - // may also throw Autodesk.AutoCAD.Runtime.Exception for invalid extents on objects like rays and xlines + selectedExtents.AddExtents(entity.GeometricExtents); } } + catch (Exception e) when (!e.IsFatal()) + { + // Note: we're swallowing exeptions here because of a weird case when receiving blocks, we would have + // acad api throw an error on accessing entity.GeometricExtents. + // may also throw Autodesk.AutoCAD.Runtime.Exception for invalid extents on objects like rays and xlines + } + } - doc.Editor.Zoom(selectedExtents); - tr.Commit(); - Autodesk.AutoCAD.Internal.Utils.FlushGraphics(); + doc.Editor.Zoom(selectedExtents); + tr.Commit(); + Autodesk.AutoCAD.Internal.Utils.FlushGraphics(); + } + catch (Exception ex) when (!ex.IsFatal()) + { + if (modelCardId != null) + { + await Commands.SetModelError(modelCardId, new OperationCanceledException("Failed to highlight objects.")); } - catch (Exception ex) when (!ex.IsFatal()) + else { - if (modelCardId != null) - { - await Commands - .SetModelError(modelCardId, new OperationCanceledException("Failed to highlight objects.")) - .ConfigureAwait(false); - } - else - { - // This will happen, in some cases, where we highlight individual objects. Should be caught by the top level handler and not - // crash the host app. - throw; - } + // This will happen, in some cases, where we highlight individual objects. Should be caught by the top level handler and not + // crash the host app. + throw; } - }) - .ConfigureAwait(false); + } + }); } } diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadReceiveBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadReceiveBinding.cs index d2d68a7fd..cb5b3b0a6 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadReceiveBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadReceiveBinding.cs @@ -81,12 +81,13 @@ public async Task Receive(string modelCardId) modelCard.GetReceiveInfo(_speckleApplication.Slug), _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationToken), cancellationToken - ) - .ConfigureAwait(false); + ); - await Commands - .SetModelReceiveResult(modelCardId, operationResults.BakedObjectIds, operationResults.ConversionResults) - .ConfigureAwait(false); + await Commands.SetModelReceiveResult( + modelCardId, + operationResults.BakedObjectIds, + operationResults.ConversionResults + ); } catch (OperationCanceledException) { @@ -98,7 +99,7 @@ await Commands catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation { _logger.LogModelCardHandledError(ex); - await Commands.SetModelError(modelCardId, ex).ConfigureAwait(false); + await Commands.SetModelError(modelCardId, ex); } finally { diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs index 0be4d5611..104341c33 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs @@ -1,6 +1,7 @@ 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; @@ -10,16 +11,18 @@ public class AutocadSelectionBinding : ISelectionBinding { private const string SELECTION_EVENT = "setSelection"; private readonly ITopLevelExceptionHandler _topLevelExceptionHandler; + private readonly IThreadContext _threadContext; private readonly HashSet _visitedDocuments = new(); public string Name => "selectionBinding"; public IBrowserBridge Parent { get; } - public AutocadSelectionBinding(IBrowserBridge parent) + public AutocadSelectionBinding(IBrowserBridge parent, IThreadContext threadContext) { _topLevelExceptionHandler = parent.TopLevelExceptionHandler; Parent = parent; + _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 @@ -41,9 +44,7 @@ private void TryRegisterDocumentForSelection(Document? document) if (!_visitedDocuments.Contains(document)) { document.ImpliedSelectionChanged += (_, _) => - _topLevelExceptionHandler.FireAndForget( - async () => await Parent.RunOnMainThreadAsync(OnSelectionChanged).ConfigureAwait(false) - ); + _topLevelExceptionHandler.FireAndForget(async () => await _threadContext.RunOnMainAsync(OnSelectionChanged)); _visitedDocuments.Add(document); } @@ -57,7 +58,7 @@ private void TryRegisterDocumentForSelection(Document? document) private async Task OnSelectionChanged() { _selectionInfo = GetSelectionInternal(); - await Parent.Send(SELECTION_EVENT, _selectionInfo).ConfigureAwait(false); + await Parent.Send(SELECTION_EVENT, _selectionInfo); } public SelectionInfo GetSelection() => _selectionInfo; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs index 11f840f92..5f556e623 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; @@ -38,6 +39,7 @@ public abstract class AutocadSendBaseBinding : ISendBinding private readonly ILogger _logger; private readonly ITopLevelExceptionHandler _topLevelExceptionHandler; private readonly ISpeckleApplication _speckleApplication; + 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: @@ -57,7 +59,8 @@ protected AutocadSendBaseBinding( ISendConversionCache sendConversionCache, IOperationProgressManager operationProgressManager, ILogger logger, - ISpeckleApplication speckleApplication + ISpeckleApplication speckleApplication, + IThreadContext threadContext ) { _store = store; @@ -69,6 +72,7 @@ ISpeckleApplication speckleApplication _operationProgressManager = operationProgressManager; _logger = logger; _speckleApplication = speckleApplication; + _threadContext = threadContext; _topLevelExceptionHandler = parent.TopLevelExceptionHandler; Parent = parent; Commands = new SendBindingUICommands(parent); @@ -111,10 +115,7 @@ private void OnObjectChanged(DBObject dbObject) private void OnChangeChangedObjectIds(DBObject dBObject) { ChangedObjectIds[dBObject.GetSpeckleApplicationId()] = 1; - _idleManager.SubscribeToIdle( - nameof(AutocadSendBinding), - async () => await RunExpirationChecks().ConfigureAwait(false) - ); + _idleManager.SubscribeToIdle(nameof(AutocadSendBinding), async () => await RunExpirationChecks()); } private async Task RunExpirationChecks() @@ -135,7 +136,7 @@ private async Task RunExpirationChecks() } } - await Commands.SetModelsExpired(expiredSenderIds).ConfigureAwait(false); + await Commands.SetModelsExpired(expiredSenderIds); ChangedObjectIds = new(); } @@ -144,9 +145,7 @@ private async Task RunExpirationChecks() public List GetSendSettings() => []; public async Task Send(string modelCardId) => - await Parent - .RunOnMainThreadAsync(async () => await SendInternal(modelCardId).ConfigureAwait(false)) - .ConfigureAwait(false); + await _threadContext.RunOnWorkerAsync(async () => await SendInternal(modelCardId)); protected abstract void InitializeSettings(IServiceProvider serviceProvider); @@ -188,12 +187,9 @@ private async Task SendInternal(string modelCardId) modelCard.GetSendInfo(_speckleApplication.Slug), _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationToken), cancellationToken - ) - .ConfigureAwait(false); + ); - await Commands - .SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults) - .ConfigureAwait(false); + await Commands.SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults); } catch (OperationCanceledException) { @@ -205,7 +201,7 @@ await Commands catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation { _logger.LogModelCardHandledError(ex); - await Commands.SetModelError(modelCardId, ex).ConfigureAwait(false); + await Commands.SetModelError(modelCardId, ex); } finally { diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs index bc2a28a96..ddd5c223c 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs @@ -3,6 +3,7 @@ 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; @@ -28,7 +29,8 @@ public AutocadSendBinding( IOperationProgressManager operationProgressManager, ILogger logger, IAutocadConversionSettingsFactory autocadConversionSettingsFactory, - ISpeckleApplication speckleApplication + ISpeckleApplication speckleApplication, + IThreadContext threadContext ) : base( store, @@ -40,7 +42,8 @@ ISpeckleApplication speckleApplication sendConversionCache, operationProgressManager, logger, - speckleApplication + speckleApplication, + threadContext ) { _autocadConversionSettingsFactory = autocadConversionSettingsFactory; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs index 72bc3567f..8ce12c190 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/SharedRegistration.cs @@ -10,6 +10,7 @@ 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; @@ -24,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 @@ -43,10 +44,10 @@ public static void AddAutocadBase(this IServiceCollection serviceCollection) serviceCollection.AddScoped(); serviceCollection.AddScoped(); - serviceCollection.AddScoped(); + serviceCollection.AddScoped(); serviceCollection.AddScoped(); - serviceCollection.AddScoped(); + serviceCollection.AddScoped(); serviceCollection.AddSingleton(); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadColorBaker.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadColorBaker.cs index 7395ab6e8..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 /// @@ -59,7 +54,7 @@ public void ParseColors(IReadOnlyCollection colorProxies, IProgress< } catch (Exception ex) when (!ex.IsFatal()) { - _logger.LogError(ex, "Failed parsing color proxy"); + logger.LogError(ex, "Failed parsing color proxy"); } } } diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceBaker.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceBaker.cs index 8121d97f7..e1373f54f 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceBaker.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceBaker.cs @@ -26,16 +26,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 f70d1dca4..ebd4737eb 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadLayerBaker.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadLayerBaker.cs @@ -12,15 +12,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 13fa39e4e..1e09a7f2b 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.Common; @@ -16,7 +17,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 43e5d3dea..94e0d2a80 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs @@ -20,86 +20,44 @@ 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, + IAutocadMaterialBaker materialBaker, + IAutocadColorBaker colorBaker, + AutocadContext autocadContext, + RootObjectUnpacker rootObjectUnpacker +) : 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( + public HostObjectBuilderResult Build( Base rootObject, string projectName, string modelName, IProgress onOperationProgressed, - 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( - Base rootObject, - string projectName, - string modelName, - IProgress onOperationProgressed + CancellationToken cancellationToken ) { // 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) @@ -113,7 +71,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 @@ -122,7 +80,7 @@ IProgress onOperationProgressed if (unpackedRoot.ColorProxies != null) { - _colorBaker.ParseColors(unpackedRoot.ColorProxies, onOperationProgressed); + colorBaker.ParseColors(unpackedRoot.ColorProxies, onOperationProgressed); } // 5 - Convert atomic objects @@ -134,6 +92,7 @@ IProgress onOperationProgressed { string objectId = atomicObject.applicationId ?? atomicObject.id.NotNull(); onOperationProgressed.Report(new("Converting objects", (double)++count / atomicObjects.Count)); + cancellationToken.ThrowIfCancellationRequested(); try { IReadOnlyCollection convertedObjects = ConvertObject(atomicObject, layerPath, baseLayerPrefix); @@ -158,7 +117,7 @@ IProgress onOperationProgressed } // 6 - Convert instances - var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = _instanceBaker.BakeInstances( + var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = instanceBaker.BakeInstances( instanceComponentsWithPath, applicationIdMap, baseLayerPrefix, @@ -173,7 +132,7 @@ IProgress onOperationProgressed // 7 - Create groups if (unpackedRoot.GroupProxies != null) { - IReadOnlyCollection groupResults = _groupBaker.CreateGroups( + IReadOnlyCollection groupResults = groupBaker.CreateGroups( unpackedRoot.GroupProxies, applicationIdMap ); @@ -185,20 +144,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 IReadOnlyCollection ConvertObject(Base obj, Collection[] layerPath, string baseLayerNamePrefix) { - string layerName = _layerBaker.CreateLayerForReceive(layerPath, baseLayerNamePrefix); + string layerName = layerBaker.CreateLayerForReceive(layerPath, baseLayerNamePrefix); var convertedEntities = new HashSet(); 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) @@ -219,12 +178,12 @@ private IReadOnlyCollection ConvertObject(Base obj, Collection[] layerPa private Entity BakeObject(Entity entity, Base originalObject, string layerName, Base? parentObject = null) { var objId = originalObject.applicationId ?? originalObject.id.NotNull(); - 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; } @@ -259,7 +218,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.AutocadShared/Operations/Send/AutocadRootObjectBaseBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBaseBuilder.cs index 9c8c77e15..b1de30e12 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBaseBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBaseBuilder.cs @@ -49,13 +49,6 @@ 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", @@ -65,11 +58,11 @@ It is already simplified but has many different references since it is a builder 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 + CancellationToken cancellationToken ) { // 0 - Init the root @@ -101,7 +94,7 @@ private RootObjectBuilderResult BuildSync( int count = 0; foreach (var (entity, applicationId) in atomicObjects) { - ct.ThrowIfCancellationRequested(); + cancellationToken.ThrowIfCancellationRequested(); using (var convertActivity = _activityFactory.Start("Converting object")) { // Create and add a collection for this entity if not done so already. 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.Civil3d2022/packages.lock.json b/Connectors/Autocad/Speckle.Connectors.Civil3d2022/packages.lock.json index 0ba82222b..32746a13e 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -377,12 +376,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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 919d8abdb..4ed55b592 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -377,12 +376,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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 69d222c6e..c834b8881 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -377,12 +376,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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 4a40c6637..c9ab57947 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -333,12 +332,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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.Civil3dShared/Bindings/Civil3dSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs index a1aa571b0..4b26c74ef 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs @@ -4,6 +4,7 @@ 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; @@ -32,7 +33,8 @@ public Civil3dSendBinding( ILogger logger, ICivil3dConversionSettingsFactory civil3dConversionSettingsFactory, IAutocadConversionSettingsFactory autocadConversionSettingsFactory, - ISpeckleApplication speckleApplication + ISpeckleApplication speckleApplication, + IThreadContext threadContext ) : base( store, @@ -44,7 +46,8 @@ ISpeckleApplication speckleApplication sendConversionCache, operationProgressManager, logger, - speckleApplication + speckleApplication, + threadContext ) { _civil3dConversionSettingsFactory = civil3dConversionSettingsFactory; diff --git a/Connectors/CSi/Speckle.Connectors.CSiShared/Bindings/CsiSharedSendBinding.cs b/Connectors/CSi/Speckle.Connectors.CSiShared/Bindings/CsiSharedSendBinding.cs index 785d2c2ee..0c297fd8d 100644 --- a/Connectors/CSi/Speckle.Connectors.CSiShared/Bindings/CsiSharedSendBinding.cs +++ b/Connectors/CSi/Speckle.Connectors.CSiShared/Bindings/CsiSharedSendBinding.cs @@ -107,12 +107,9 @@ public async Task Send(string modelCardId) modelCard.GetSendInfo(_speckleApplication.Slug), _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationToken), cancellationToken - ) - .ConfigureAwait(false); + ); - await Commands - .SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults) - .ConfigureAwait(false); + await Commands.SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults); } catch (OperationCanceledException) { @@ -121,7 +118,7 @@ await Commands catch (Exception ex) when (!ex.IsFatal()) { _logger.LogModelCardHandledError(ex); - await Commands.SetModelError(modelCardId, ex).ConfigureAwait(false); + await Commands.SetModelError(modelCardId, ex); } } diff --git a/Connectors/CSi/Speckle.Connectors.CSiShared/Operations/Send/CsiRootObjectBuilder.cs b/Connectors/CSi/Speckle.Connectors.CSiShared/Operations/Send/CsiRootObjectBuilder.cs index 5660a1ce6..07386452d 100644 --- a/Connectors/CSi/Speckle.Connectors.CSiShared/Operations/Send/CsiRootObjectBuilder.cs +++ b/Connectors/CSi/Speckle.Connectors.CSiShared/Operations/Send/CsiRootObjectBuilder.cs @@ -42,11 +42,11 @@ ICsiApplicationService csiApplicationService _csiApplicationService = csiApplicationService; } - public async Task Build( + public RootObjectBuilderResult Build( IReadOnlyList csiObjects, SendInfo sendInfo, IProgress onOperationProgressed, - CancellationToken cancellationToken = default + CancellationToken cancellationToken ) { using var activity = _activityFactory.Start("Build"); @@ -62,8 +62,8 @@ public async Task Build( { foreach (ICsiWrapper csiObject in csiObjects) { - using var _2 = _activityFactory.Start("Convert"); cancellationToken.ThrowIfCancellationRequested(); + using var _2 = _activityFactory.Start("Convert"); var result = ConvertCSiObject(csiObject, rootObjectCollection, sendInfo.ProjectId); results.Add(result); @@ -78,7 +78,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 572b81b46..59945da1e 100644 --- a/Connectors/CSi/Speckle.Connectors.CSiShared/ServiceRegistration.cs +++ b/Connectors/CSi/Speckle.Connectors.CSiShared/ServiceRegistration.cs @@ -1,7 +1,8 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Speckle.Connectors.Common; using Speckle.Connectors.Common.Builders; using Speckle.Connectors.Common.Operations; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.CSiShared.Bindings; using Speckle.Connectors.CSiShared.Builders; using Speckle.Connectors.CSiShared.Filters; @@ -9,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; @@ -24,11 +24,9 @@ public static IServiceCollection AddCsi(this IServiceCollection services) services.AddSingleton(); services.AddConnectorUtils(); - services.AddDUI(); + services.AddDUI(); services.AddDUIView(); - services.AddSingleton(); - services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/Connectors/CSi/Speckle.Connectors.ETABS21/packages.lock.json b/Connectors/CSi/Speckle.Connectors.ETABS21/packages.lock.json index 005abbc8c..64e7c4d7a 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -366,12 +365,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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 4175675aa..df66c1844 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -321,12 +320,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Connectors/Navisworks/Speckle.Connectors.Navisworks2020/packages.lock.json b/Connectors/Navisworks/Speckle.Connectors.Navisworks2020/packages.lock.json index f94103af1..a46dbcd5b 100644 --- a/Connectors/Navisworks/Speckle.Connectors.Navisworks2020/packages.lock.json +++ b/Connectors/Navisworks/Speckle.Connectors.Navisworks2020/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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -368,12 +367,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } }, ".NETFramework,Version=v4.8/win-x64": { diff --git a/Connectors/Navisworks/Speckle.Connectors.Navisworks2021/packages.lock.json b/Connectors/Navisworks/Speckle.Connectors.Navisworks2021/packages.lock.json index 010e2851e..f108a8e5e 100644 --- a/Connectors/Navisworks/Speckle.Connectors.Navisworks2021/packages.lock.json +++ b/Connectors/Navisworks/Speckle.Connectors.Navisworks2021/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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -368,12 +367,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } }, ".NETFramework,Version=v4.8/win-x64": { diff --git a/Connectors/Navisworks/Speckle.Connectors.Navisworks2022/packages.lock.json b/Connectors/Navisworks/Speckle.Connectors.Navisworks2022/packages.lock.json index 094f3f0de..db91385d3 100644 --- a/Connectors/Navisworks/Speckle.Connectors.Navisworks2022/packages.lock.json +++ b/Connectors/Navisworks/Speckle.Connectors.Navisworks2022/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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -368,12 +367,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } }, ".NETFramework,Version=v4.8/win-x64": { diff --git a/Connectors/Navisworks/Speckle.Connectors.Navisworks2023/packages.lock.json b/Connectors/Navisworks/Speckle.Connectors.Navisworks2023/packages.lock.json index 60b4cc5cd..c4615aa8c 100644 --- a/Connectors/Navisworks/Speckle.Connectors.Navisworks2023/packages.lock.json +++ b/Connectors/Navisworks/Speckle.Connectors.Navisworks2023/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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -368,12 +367,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } }, ".NETFramework,Version=v4.8/win-x64": { diff --git a/Connectors/Navisworks/Speckle.Connectors.Navisworks2024/packages.lock.json b/Connectors/Navisworks/Speckle.Connectors.Navisworks2024/packages.lock.json index d47f24827..f1c34b879 100644 --- a/Connectors/Navisworks/Speckle.Connectors.Navisworks2024/packages.lock.json +++ b/Connectors/Navisworks/Speckle.Connectors.Navisworks2024/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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -368,12 +367,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } }, ".NETFramework,Version=v4.8/win-x64": { diff --git a/Connectors/Navisworks/Speckle.Connectors.Navisworks2025/packages.lock.json b/Connectors/Navisworks/Speckle.Connectors.Navisworks2025/packages.lock.json index db9cf1712..9236264cf 100644 --- a/Connectors/Navisworks/Speckle.Connectors.Navisworks2025/packages.lock.json +++ b/Connectors/Navisworks/Speckle.Connectors.Navisworks2025/packages.lock.json @@ -290,8 +290,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", "Speckle.Connectors.Common": "[1.0.0, )", "Speckle.Sdk": "[3.1.0-dev.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -368,12 +367,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } }, ".NETFramework,Version=v4.8/win-x64": { diff --git a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Bindings/NavisworksBasicConnectorBinding.cs b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Bindings/NavisworksBasicConnectorBinding.cs index 62c0ffda0..8d893c8cc 100644 --- a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Bindings/NavisworksBasicConnectorBinding.cs +++ b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Bindings/NavisworksBasicConnectorBinding.cs @@ -42,20 +42,13 @@ NavisworksDocumentEvents documentEvents public string GetConnectorVersion() => _speckleApplication.SpeckleVersion; public DocumentInfo? GetDocumentInfo() => - Parent - .RunOnMainThreadAsync( - () => - Task.FromResult( - NavisworksApp.ActiveDocument is null || NavisworksApp.ActiveDocument.Models.Count == 0 - ? null - : new DocumentInfo( - NavisworksApp.ActiveDocument.CurrentFileName, - NavisworksApp.ActiveDocument.Title, - NavisworksApp.ActiveDocument.GetHashCode().ToString() - ) - ) - ) - .Result; + NavisworksApp.ActiveDocument is null || NavisworksApp.ActiveDocument.Models.Count == 0 + ? null + : new DocumentInfo( + NavisworksApp.ActiveDocument.CurrentFileName, + NavisworksApp.ActiveDocument.Title, + NavisworksApp.ActiveDocument.GetHashCode().ToString() + ); public DocumentModelStore GetDocumentState() => _store; @@ -68,11 +61,6 @@ NavisworksDocumentEvents documentEvents public Task HighlightModel(string modelCardId) => Task.CompletedTask; public async Task HighlightObjects(IReadOnlyList objectIds) => - await Parent - .RunOnMainThreadAsync(async () => - { - // TODO: Implement highlighting logic on main thread - await Task.CompletedTask.ConfigureAwait(false); - }) - .ConfigureAwait(false); + // TODO: Implement highlighting logic on main thread + await Task.CompletedTask; } diff --git a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Bindings/NavisworksSelectionBinding.cs b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Bindings/NavisworksSelectionBinding.cs index 52389c16b..d3334383e 100644 --- a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Bindings/NavisworksSelectionBinding.cs +++ b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Bindings/NavisworksSelectionBinding.cs @@ -26,10 +26,7 @@ IElementSelectionService selectionService } private void OnSelectionChange(object? o, EventArgs eventArgs) => - _appIdleManager.SubscribeToIdle( - nameof(NavisworksSelectionBinding), - async () => await UpdateSelectionAsync().ConfigureAwait(false) - ); + _appIdleManager.SubscribeToIdle(nameof(NavisworksSelectionBinding), async () => await UpdateSelectionAsync()); private void UpdateSelection() { @@ -39,11 +36,8 @@ private void UpdateSelection() private async Task UpdateSelectionAsync() { - var selInfo = await Parent - .RunOnMainThreadAsync(() => Task.FromResult(GetSelection())) - .ConfigureAwait(false); - - await Parent.Send(SELECTION_EVENT, selInfo).ConfigureAwait(false); + var selInfo = GetSelection(); + await Parent.Send(SELECTION_EVENT, selInfo); } public SelectionInfo GetSelection() diff --git a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Bindings/NavisworksSendBinding.cs b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Bindings/NavisworksSendBinding.cs index 8e5c15e3a..e67d8a7be 100644 --- a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Bindings/NavisworksSendBinding.cs +++ b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Bindings/NavisworksSendBinding.cs @@ -87,27 +87,19 @@ public async Task Send(string modelCardId) using var activity = _activityFactory.Start(); try { - await Parent - .RunOnMainThreadAsync(async () => - { - var modelCard = GetModelCard(modelCardId); + var modelCard = GetModelCard(modelCardId); - using var scope = _serviceProvider.CreateScope(); + using var scope = _serviceProvider.CreateScope(); - InitializeConverterSettings(scope, modelCard); + InitializeConverterSettings(scope, modelCard); - CancellationToken token = _cancellationManager.InitCancellationTokenSource(modelCardId); + CancellationToken token = _cancellationManager.InitCancellationTokenSource(modelCardId); - var navisworksModelItems = GetNavisworksModelItems(modelCard); + var navisworksModelItems = GetNavisworksModelItems(modelCard); - var sendResult = await ExecuteSendOperation(scope, modelCard, navisworksModelItems, token) - .ConfigureAwait(false); + var sendResult = await ExecuteSendOperation(scope, modelCard, navisworksModelItems, token); - await Commands - .SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults) - .ConfigureAwait(false); - }) - .ConfigureAwait(false); + await Commands.SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults); } catch (OperationCanceledException) { @@ -118,7 +110,7 @@ await Commands catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation { _logger.LogModelCardHandledError(ex); - await Commands.SetModelError(modelCardId, ex).ConfigureAwait(false); + await Commands.SetModelError(modelCardId, ex); } } @@ -173,8 +165,7 @@ await scope modelCard.GetSendInfo(_speckleApplication.Slug), _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCard.ModelCardId!, token), token - ) - .ConfigureAwait(false); + ); public void CancelSend(string modelCardId) => _cancellationManager.CancelOperation(modelCardId); diff --git a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/DependencyInjection/NavisworksConnectorServiceRegistration.cs b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/DependencyInjection/NavisworksConnectorServiceRegistration.cs index a1d398292..b906ddce4 100644 --- a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/DependencyInjection/NavisworksConnectorServiceRegistration.cs +++ b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/DependencyInjection/NavisworksConnectorServiceRegistration.cs @@ -9,6 +9,7 @@ using Speckle.Connectors.Common.Builders; 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; @@ -27,7 +28,7 @@ public static void AddNavisworks(this IServiceCollection serviceCollection) { // Register Core functionality serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); serviceCollection.AddDUIView(); // Register bindings diff --git a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/HostApp/NavisworksDocumentEvents.cs b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/HostApp/NavisworksDocumentEvents.cs index 26fed81ee..69e05e171 100644 --- a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/HostApp/NavisworksDocumentEvents.cs +++ b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/HostApp/NavisworksDocumentEvents.cs @@ -84,10 +84,7 @@ private void HandleDocumentModelCountChanged(object sender, EventArgs e) _topLevelExceptionHandler.CatchUnhandled( () => - _idleManager.SubscribeToIdle( - nameof(NavisworksDocumentEvents), - async () => await ProcessModelStateChangeAsync().ConfigureAwait(false) - ) + _idleManager.SubscribeToIdle(nameof(NavisworksDocumentEvents), async () => await ProcessModelStateChangeAsync()) ); } @@ -102,29 +99,24 @@ private async Task ProcessModelStateChangeAsync() try { - await _parent - .RunOnMainThreadAsync(async () => - { - var store = _serviceProvider.GetRequiredService(); - var basicBinding = _serviceProvider.GetRequiredService(); - var commands = (basicBinding as NavisworksBasicConnectorBinding)?.Commands; - - switch (_finalModelCount) - { - case 0 when _priorModelCount > 0: - store.ClearAndSave(); - break; - case > 0 when _priorModelCount == 0: - store.ReloadState(); - break; - } - - if (commands != null) - { - await commands.NotifyDocumentChanged().ConfigureAwait(false); - } - }) - .ConfigureAwait(false); + var store = _serviceProvider.GetRequiredService(); + var basicBinding = _serviceProvider.GetRequiredService(); + var commands = (basicBinding as NavisworksBasicConnectorBinding)?.Commands; + + switch (_finalModelCount) + { + case 0 when _priorModelCount > 0: + store.ClearAndSave(); + break; + case > 0 when _priorModelCount == 0: + store.ReloadState(); + break; + } + + if (commands != null) + { + await commands.NotifyDocumentChanged(); + } } finally { @@ -164,7 +156,7 @@ private async Task NotifyValidModelStateChange() if (commands != null) { - await commands.NotifyDocumentChanged().ConfigureAwait(false); + await commands.NotifyDocumentChanged(); } } finally diff --git a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Operations/Send/NavisworksRootObjectBuilder.cs b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Operations/Send/NavisworksRootObjectBuilder.cs index f58d59377..a099cb4fb 100644 --- a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Operations/Send/NavisworksRootObjectBuilder.cs +++ b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Operations/Send/NavisworksRootObjectBuilder.cs @@ -28,11 +28,11 @@ IElementSelectionService elementSelectionService { internal NavisworksConversionSettings GetCurrentSettings() => converterSettings.Current; - public Task Build( + public RootObjectBuilderResult Build( IReadOnlyList navisworksModelItems, SendInfo sendInfo, IProgress onOperationProgressed, - CancellationToken cancellationToken = default + CancellationToken cancellationToken ) { using var activity = activityFactory.Start("Build"); @@ -151,7 +151,7 @@ public Task Build( // 8. Finalize and return rootObjectCollection.elements = finalElements; - return Task.FromResult(new RootObjectBuilderResult(rootObjectCollection, results)); + return new RootObjectBuilderResult(rootObjectCollection, results); } private SendConversionResult ConvertNavisworksItem( diff --git a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Plugin/DockableConnectorPane.cs b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Plugin/DockableConnectorPane.cs index d6022ca75..b779afe43 100644 --- a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Plugin/DockableConnectorPane.cs +++ b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Plugin/DockableConnectorPane.cs @@ -4,7 +4,6 @@ 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,8 +41,6 @@ public override Control CreateControlPane() Container = services.BuildServiceProvider(); - Container.UseDUI(); - var u = Container.GetRequiredService(); var speckleHost = new ElementHost { AutoSize = true, Child = u }; diff --git a/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json b/Connectors/Revit/Speckle.Connectors.Revit2022/packages.lock.json index 6ac2990a3..9230a33ff 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.logging": { @@ -388,12 +387,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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 461bb2a01..68844dc7c 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.logging": { @@ -388,12 +387,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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 329428e70..1143d418c 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.logging": { @@ -388,12 +387,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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 3e5b56850..99b6ca2af 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.logging": { @@ -337,12 +336,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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.RevitShared.Cef/CefSharpPanel.xaml.cs b/Connectors/Revit/Speckle.Connectors.RevitShared.Cef/CefSharpPanel.xaml.cs index ae78681ed..98e98c88f 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 ExecuteScript(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/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs index 49f973536..c4ce8e66c 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/BasicConnectorBindingRevit.cs @@ -1,9 +1,7 @@ using Autodesk.Revit.DB; -using Revit.Async; 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; @@ -20,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, @@ -35,7 +31,6 @@ ISpeckleApplication speckleApplication { Name = "baseBinding"; Parent = parent; - _apiContext = apiContext; _store = store; _revitContext = revitContext; _speckleApplication = speckleApplication; @@ -45,7 +40,7 @@ ISpeckleApplication speckleApplication _store.DocumentChanged += (_, _) => parent.TopLevelExceptionHandler.FireAndForget(async () => { - await Commands.NotifyDocumentChanged().ConfigureAwait(false); + await Commands.NotifyDocumentChanged(); }); } @@ -97,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); + var view = revitViewsFilter.GetView(); + if (view is not null) + { + _revitContext.UIApplication.ActiveUIDocument.ActiveView = view; + } return; } @@ -136,51 +126,42 @@ await _apiContext if (elementIds.Count == 0) { - await Commands - .SetModelError(modelCardId, new InvalidOperationException("No objects found to highlight.")) - .ConfigureAwait(false); + await Commands.SetModelError(modelCardId, new InvalidOperationException("No objects found to highlight.")); 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"); - // 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); + activeUIDoc.Selection.SetElementIds(objectIds); + activeUIDoc.ShowElements(objectIds); ; } } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitReceiveBinding.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitReceiveBinding.cs index 2abd95945..1f52cd26d 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitReceiveBinding.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitReceiveBinding.cs @@ -83,13 +83,14 @@ public async Task Receive(string modelCardId) modelCard.GetReceiveInfo(_speckleApplication.Slug), _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationToken), cancellationToken - ) - .ConfigureAwait(false); + ); modelCard.BakedObjectIds = conversionResults.BakedObjectIds.ToList(); - await Commands - .SetModelReceiveResult(modelCardId, conversionResults.BakedObjectIds, conversionResults.ConversionResults) - .ConfigureAwait(false); + await Commands.SetModelReceiveResult( + modelCardId, + conversionResults.BakedObjectIds, + conversionResults.ConversionResults + ); } catch (OperationCanceledException) { @@ -100,7 +101,7 @@ await Commands catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation { _logger.LogModelCardHandledError(ex); - await Commands.SetModelError(modelCardId, ex).ConfigureAwait(false); + await Commands.SetModelError(modelCardId, ex); } finally { diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs index c491b7fac..27cb51e56 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,8 +27,7 @@ namespace Speckle.Connectors.Revit.Bindings; internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding { - private readonly IRevitIdleManager _idleManager; - private readonly APIContext _apiContext; + private readonly IAppIdleManager _idleManager; private readonly CancellationManager _cancellationManager; private readonly IServiceProvider _serviceProvider; private readonly ISendConversionCache _sendConversionCache; @@ -49,9 +47,8 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding private ConcurrentDictionary ChangedObjectIds { get; set; } = new(); public RevitSendBinding( - IRevitIdleManager idleManager, + IAppIdleManager idleManager, RevitContext revitContext, - APIContext apiContext, DocumentModelStore store, CancellationManager cancellationManager, IBrowserBridge bridge, @@ -67,7 +64,6 @@ ISpeckleApplication speckleApplication : base("sendBinding", store, bridge, revitContext) { _idleManager = idleManager; - _apiContext = apiContext; _cancellationManager = cancellationManager; _serviceProvider = serviceProvider; _sendConversionCache = sendConversionCache; @@ -82,20 +78,17 @@ 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)); + + revitContext.UIApplication.NotNull().Application.DocumentChanged += (_, e) => + topLevelExceptionHandler.CatchUnhandled(() => DocChangeHandler(e)); + Store.DocumentChanged += (_, _) => topLevelExceptionHandler.FireAndForget(async () => await OnDocumentChanged()); } public List GetSendFilters() => [ new RevitSelectionFilter() { IsDefault = true }, - new RevitViewsFilter(RevitContext, _apiContext), - new RevitCategoriesFilter(RevitContext, _apiContext) + new RevitViewsFilter(RevitContext), + new RevitCategoriesFilter(RevitContext) ]; public List GetSendSettings() => @@ -133,7 +126,7 @@ public async Task Send(string modelCardId) ) ); - List elements = await RefreshElementsOnSender(modelCard.NotNull()).ConfigureAwait(false); + List elements = await RefreshElementsOnSender(modelCard.NotNull()); List elementIds = elements.Select(el => el.Id).ToList(); if (elementIds.Count == 0) @@ -149,12 +142,9 @@ public async Task Send(string modelCardId) modelCard.GetSendInfo(_speckleApplication.Slug), _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationToken), cancellationToken - ) - .ConfigureAwait(false); + ); - await Commands - .SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults) - .ConfigureAwait(false); + await Commands.SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults); } catch (OperationCanceledException) { @@ -165,7 +155,7 @@ await Commands catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation { _logger.LogModelCardHandledError(ex); - await Commands.SetModelError(modelCardId, ex).ConfigureAwait(false); + await Commands.SetModelError(modelCardId, ex); } finally { @@ -182,12 +172,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)) @@ -204,9 +192,11 @@ private async Task> RefreshElementsOnSender(SenderModelCard modelC } // We update the state on the UI SenderModelCard to prevent potential inconsistencies between hostApp IdMap in sendfilters. - await Commands - .SetFilterObjectIds(modelCard.ModelCardId.NotNull(), modelCard.SendFilter.IdMap, newSelectedObjectIds) - .ConfigureAwait(false); + await Commands.SetFilterObjectIds( + modelCard.ModelCardId.NotNull(), + modelCard.SendFilter.IdMap, + newSelectedObjectIds + ); } return elements; @@ -315,7 +305,7 @@ private async Task PostSetObjectIds() { foreach (var sender in Store.GetSenders().ToList()) { - await RefreshElementsOnSender(sender).ConfigureAwait(false); + await RefreshElementsOnSender(sender); } } @@ -330,12 +320,12 @@ private async Task CheckFilterExpiration() // var intersection = ChangedObjectIds.Keys.Intersect(views).ToList(); // if (intersection.Count != 0) // { - // await Commands.RefreshSendFilters().ConfigureAwait(false); + // await Commands.RefreshSendFilters(); // } if (ChangedObjectIds.Keys.Any(e => RevitContext.UIApplication?.ActiveUIDocument.Document.GetElement(e) is View)) { - await Commands.RefreshSendFilters().ConfigureAwait(false); + await Commands.RefreshSendFilters(); } } @@ -394,7 +384,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; @@ -406,7 +396,7 @@ private async Task RunExpirationChecks() } } - await Commands.SetModelsExpired(expiredSenderIds).ConfigureAwait(false); + await Commands.SetModelsExpired(expiredSenderIds); ChangedObjectIds = new(); } @@ -419,13 +409,11 @@ private async Task OnDocumentChanged() if (_cancellationManager.NumberOfOperations > 0) { _cancellationManager.CancelAllOperations(); - await Commands - .SetGlobalNotification( - ToastNotificationType.INFO, - "Document Switch", - "Operations cancelled because of document swap!" - ) - .ConfigureAwait(false); + await Commands.SetGlobalNotification( + ToastNotificationType.INFO, + "Document Switch", + "Operations cancelled because of document swap!" + ); } } } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SelectionBinding.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SelectionBinding.cs index 174131ee2..eabb03f7f 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); - }); + + 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 8302eb18f..b719cc2d4 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/DependencyInjection/RevitConnectorModule.cs @@ -25,7 +25,7 @@ public static class ServiceRegistration public static void AddRevit(this IServiceCollection serviceCollection) { serviceCollection.AddConnectorUtils(); - serviceCollection.AddDUI(); + serviceCollection.AddDUI(); RegisterUiDependencies(serviceCollection); // Storage Schema @@ -41,7 +41,7 @@ public static void AddRevit(this IServiceCollection serviceCollection) serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.RegisterTopLevelExceptionHandler(); @@ -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/HostApp/RevitDocumentStore.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs index d3254822e..5b8629853 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/HostApp/RevitDocumentStore.cs @@ -2,11 +2,9 @@ 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.Utils; -using Speckle.Connectors.Revit.Plugin; using Speckle.Converters.RevitShared.Helpers; using Speckle.Sdk.Common; @@ -19,12 +17,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, @@ -38,18 +36,15 @@ ITopLevelExceptionHandler topLevelExceptionHandler _documentModelStorageSchema = documentModelStorageSchema; _idStorageSchema = idStorageSchema; - _idleManager.RunAsync(() => - { - 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); // 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". @@ -92,23 +87,21 @@ protected override void HostAppSaveState(string modelCardState) { return; } - 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); + 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 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(); } protected override void LoadState() diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs index a0acbddfc..59ba3a395 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs @@ -1,6 +1,5 @@ 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; @@ -24,64 +23,24 @@ namespace Speckle.Connectors.Revit.Operations.Receive; -internal sealed class RevitHostObjectBuilder : 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< +public 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, 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( + > localToGlobalDirectShapeConverter +) : IHostObjectBuilder, IDisposable +{ + public HostObjectBuilderResult Build( Base rootObject, string projectName, string modelName, @@ -92,27 +51,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() ); @@ -120,14 +79,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 @@ -136,26 +95,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; @@ -170,7 +129,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; @@ -182,7 +141,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. @@ -208,17 +167,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) { @@ -237,7 +196,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); @@ -253,7 +212,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; } @@ -270,7 +229,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); } } } @@ -279,12 +238,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/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/RevitRootObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs index 2b374c37d..0e1fcd55e 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs @@ -1,6 +1,5 @@ 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; @@ -11,61 +10,32 @@ 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 +) : 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( - IReadOnlyList objects, - SendInfo sendInfo, - IProgress onOperationProgressed, - CancellationToken ct = default - ) => await RevitTask.RunAsync(() => BuildSync(objects, sendInfo, onOperationProgressed, ct)).ConfigureAwait(false); - private RootObjectBuilderResult BuildSync( + public RootObjectBuilderResult Build( IReadOnlyList objects, SendInfo sendInfo, IProgress onOperationProgressed, - CancellationToken ct = default + CancellationToken cancellationToken ) { - var doc = _converterSettings.Current.Document; + var doc = converterSettings.Current.Document; if (doc.IsFamilyDocument) { @@ -74,15 +44,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,38 +67,38 @@ 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; foreach (Element revitElement in atomicObjects) { - ct.ThrowIfCancellationRequested(); + cancellationToken.ThrowIfCancellationRequested(); string applicationId = revitElement.UniqueId; string sourceType = revitElement.GetType().Name; 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 +110,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/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/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/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs index cce89b5dd..3154fb3bd 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitIdleManager.cs @@ -6,12 +6,7 @@ namespace Speckle.Connectors.Revit.Plugin; -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; @@ -42,13 +37,4 @@ protected override void AddEvent() private void RevitAppOnIdle(object? sender, IdlingEventArgs e) => _idleCallManager.AppOnIdle(() => OnIdle -= RevitAppOnIdle); - - public void RunAsync(Action action) - { -#if REVIT2025 - global::Revit.Async.RevitTask.RunAsync(action); -#else - action(); -#endif - } } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs new file mode 100644 index 000000000..957b3959c --- /dev/null +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/RevitThreadContext.cs @@ -0,0 +1,16 @@ +using Revit.Async; +using Speckle.Connectors.Common.Threading; + +namespace Speckle.Connectors.Revit.Plugin; + +public class RevitThreadContext : ThreadContext +{ + protected override Task MainToWorkerAsync(Func> action) => action(); + + protected override Task WorkerToMainAsync(Func> action) => + RevitTask.RunAsync(async () => await action()); + + protected override Task MainToWorker(Func action) => Task.FromResult(action()); + + protected override Task WorkerToMain(Func 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 42e4adfb0..5293ad708 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 @@ - @@ -47,7 +46,8 @@ - + + \ No newline at end of file diff --git a/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json b/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json index 3e42944ad..13088a422 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -376,12 +375,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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 3bd23465c..256cbc422 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -376,12 +375,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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.RhinoShared/Bindings/RhinoBasicConnectorBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoBasicConnectorBinding.cs index 432c2c81f..b34e002d0 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoBasicConnectorBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoBasicConnectorBinding.cs @@ -38,7 +38,7 @@ ISpeckleApplication speckleApplication _store.DocumentChanged += (_, _) => parent.TopLevelExceptionHandler.FireAndForget(async () => { - await Commands.NotifyDocumentChanged().ConfigureAwait(false); + await Commands.NotifyDocumentChanged(); // Note: this prevents scaling issues when copy-pasting from one rhino doc to another in the same session. _sendConversionCache.ClearCache(); }); @@ -100,9 +100,7 @@ public async Task HighlightModel(string modelCardId) if (objectIds.Count == 0) { - await Commands - .SetModelError(modelCardId, new OperationCanceledException("No objects found to highlight.")) - .ConfigureAwait(false); + await Commands.SetModelError(modelCardId, new OperationCanceledException("No objects found to highlight.")); return; } @@ -112,9 +110,7 @@ await Commands if (objects.rhinoObjects.Count == 0 && objects.groups.Count == 0) { - await Commands - .SetModelError(modelCardId, new OperationCanceledException("No objects found to highlight.")) - .ConfigureAwait(false); + await Commands.SetModelError(modelCardId, new OperationCanceledException("No objects found to highlight.")); return; } diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoReceiveBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoReceiveBinding.cs index dcf60ab73..c0599f6b9 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoReceiveBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoReceiveBinding.cs @@ -77,13 +77,14 @@ public async Task Receive(string modelCardId) modelCard.GetReceiveInfo(_speckleApplication.Slug), _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationToken), cancellationToken - ) - .ConfigureAwait(false); + ); modelCard.BakedObjectIds = conversionResults.BakedObjectIds.ToList(); - await Commands - .SetModelReceiveResult(modelCardId, conversionResults.BakedObjectIds, conversionResults.ConversionResults) - .ConfigureAwait(false); + await Commands.SetModelReceiveResult( + modelCardId, + conversionResults.BakedObjectIds, + conversionResults.ConversionResults + ); } catch (OperationCanceledException) { @@ -95,7 +96,7 @@ await Commands catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation { _logger.LogModelCardHandledError(ex); - await Commands.SetModelError(modelCardId, ex).ConfigureAwait(false); + await Commands.SetModelError(modelCardId, ex); } } diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs index 23bf041ff..5809b80af 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs @@ -111,7 +111,7 @@ private void SubscribeToRhinoEvents() { PreviousUnitSystem = newUnit; - await InvalidateAllSender().ConfigureAwait(false); + await InvalidateAllSender(); } }; @@ -245,12 +245,9 @@ public async Task Send(string modelCardId) modelCard.GetSendInfo(_speckleApplication.Slug), _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationToken), cancellationToken - ) - .ConfigureAwait(false); + ); - await Commands - .SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults) - .ConfigureAwait(false); + await Commands.SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults); } catch (OperationCanceledException) { @@ -262,7 +259,7 @@ await Commands catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation { _logger.LogModelCardHandledError(ex); - await Commands.SetModelError(modelCardId, ex).ConfigureAwait(false); + await Commands.SetModelError(modelCardId, ex); } } @@ -314,7 +311,7 @@ private async Task RunExpirationChecks() } } - await Commands.SetModelsExpired(expiredSenderIds).ConfigureAwait(false); + await Commands.SetModelsExpired(expiredSenderIds); ChangedObjectIds = new(); ChangedMaterialIndexes = new(); } @@ -323,6 +320,6 @@ private async Task InvalidateAllSender() { _sendConversionCache.ClearCache(); var senderModelCardIds = _store.GetSenders().Select(s => s.ModelCardId.NotNull()); - await Commands.SetModelsExpired(senderModelCardIds).ConfigureAwait(false); + await Commands.SetModelsExpired(senderModelCardIds); } } diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs index fbcf65ae5..82eb7d706 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,7 +44,8 @@ public RhinoHostObjectBuilder( RhinoMaterialBaker materialBaker, RhinoColorBaker colorBaker, RhinoGroupBaker groupBaker, - ISdkActivityFactory activityFactory + ISdkActivityFactory activityFactory, + IThreadContext threadContext ) { _converter = converter; @@ -54,10 +57,11 @@ ISdkActivityFactory activityFactory _layerBaker = layerBaker; _groupBaker = groupBaker; _activityFactory = activityFactory; + _threadContext = threadContext; } #pragma warning disable CA1506 - public Task Build( + public HostObjectBuilderResult Build( #pragma warning restore CA1506 Base rootObject, string projectName, @@ -112,13 +116,16 @@ CancellationToken cancellationToken onOperationProgressed.Report(new("Baking layers (redraw disabled)", null)); using (var _ = _activityFactory.Start("Pre baking layers")) { - RhinoApp.InvokeAndWait(() => - { - 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); - }); + //Rhino 8 doesn't play nice with Eto and layers + _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(cancellationToken); } // 5 - Convert atomic objects @@ -136,6 +143,7 @@ CancellationToken cancellationToken onOperationProgressed.Report( new("Converting objects", (double)++count / atomicObjectsWithoutInstanceComponentsForConverter.Count) ); + cancellationToken.ThrowIfCancellationRequested(); try { // 0: get pre-created layer from cache in layer baker @@ -229,7 +237,7 @@ CancellationToken cancellationToken } _converterSettings.Current.Document.Views.Redraw(); - return Task.FromResult(new HostObjectBuilderResult(bakedObjectIds, conversionResults)); + return new HostObjectBuilderResult(bakedObjectIds, conversionResults); } private void PreReceiveDeepClean(string baseLayerName) @@ -241,35 +249,38 @@ private void PreReceiveDeepClean(string baseLayerName) RhinoMath.UnsetIntIndex ); - RhinoApp.InvokeAndWait(() => - { - _instanceBaker.PurgeInstances(baseLayerName); - _materialBaker.PurgeMaterials(baseLayerName); - - var doc = _converterSettings.Current.Document; - // Cleans up any previously received objects - if (rootLayerIndex != RhinoMath.UnsetIntIndex) + //Rhino 8 doesn't play nice with Eto and layers + _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); - }); + // Cleans up any previously received group + _groupBaker.PurgeGroups(baseLayerName); + }) + .Wait(); } /// diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Send/RhinoRootObjectBuilder.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Send/RhinoRootObjectBuilder.cs index 5f337e491..ceec97b2c 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Send/RhinoRootObjectBuilder.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Send/RhinoRootObjectBuilder.cs @@ -60,11 +60,11 @@ ISdkActivityFactory activityFactory _activityFactory = activityFactory; } - public async Task Build( + public RootObjectBuilderResult Build( IReadOnlyList rhinoObjects, SendInfo sendInfo, IProgress onOperationProgressed, - CancellationToken cancellationToken = default + CancellationToken cancellationToken ) { using var activity = _activityFactory.Start("Build"); @@ -95,8 +95,8 @@ public async Task Build( { foreach (RhinoObject rhinoObject in atomicObjects) { - using var _2 = _activityFactory.Start("Convert"); cancellationToken.ThrowIfCancellationRequested(); + using var _2 = _activityFactory.Start("Convert"); // handle layer Layer layer = _converterSettings.Current.Document.Layers[rhinoObject.Attributes.LayerIndex]; @@ -130,7 +130,6 @@ public async Task Build( rootObjectCollection[ProxyKeys.COLOR] = _colorUnpacker.UnpackColors(atomicObjects, versionLayers.ToList()); } - await Task.Yield(); return new RootObjectBuilderResult(rootObjectCollection, results); } 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/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs index 086c513a8..a5ad1c12d 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Registration/ServiceRegistration.cs @@ -8,6 +8,7 @@ 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; @@ -32,12 +33,9 @@ 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! - // builder.AddSingletonInstance(); - // Register other connector specific types serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); diff --git a/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json b/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json index 8c195941a..1564d07ac 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -427,12 +426,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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 40d9fbbe6..ebd693812 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -508,12 +507,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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.TeklaShared/Bindings/TeklaBasicConnectorBinding.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaBasicConnectorBinding.cs index bc1449c7c..519ac132e 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaBasicConnectorBinding.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaBasicConnectorBinding.cs @@ -37,7 +37,7 @@ TSM.Model model _store.DocumentChanged += (_, _) => parent.TopLevelExceptionHandler.FireAndForget(async () => { - await Commands.NotifyDocumentChanged().ConfigureAwait(false); + await Commands.NotifyDocumentChanged(); }); } @@ -80,18 +80,16 @@ public async Task HighlightModel(string modelCardId) if (objectIds.Count == 0) { - await Commands - .SetModelError(modelCardId, new OperationCanceledException("No objects found to highlight.")) - .ConfigureAwait(false); + await Commands.SetModelError(modelCardId, new OperationCanceledException("No objects found to highlight.")); return; } - await HighlightObjects(objectIds).ConfigureAwait(false); + await HighlightObjects(objectIds); } catch (InvalidOperationException ex) { _logger.LogError(ex, "Failed to highlight model"); - await Commands.SetModelError(modelCardId, ex).ConfigureAwait(false); + await Commands.SetModelError(modelCardId, ex); } } @@ -100,48 +98,47 @@ public async Task HighlightObjects(IReadOnlyList objectIds) try { await Task.Run(() => - { - // passing an empty list to create current selection - var selector = new TSMUI.ModelObjectSelector(); - selector.Select(new ArrayList()); + { + // passing an empty list to create current selection + var selector = new TSMUI.ModelObjectSelector(); + selector.Select(new ArrayList()); - if (objectIds.Count > 0) - { - var modelObjects = objectIds - .Select(id => _model.SelectModelObject(new Identifier(new Guid(id)))) - .Where(obj => obj != null) - .ToList(); + if (objectIds.Count > 0) + { + var modelObjects = objectIds + .Select(id => _model.SelectModelObject(new Identifier(new Guid(id)))) + .Where(obj => obj != null) + .ToList(); - selector.Select(new ArrayList(modelObjects)); + selector.Select(new ArrayList(modelObjects)); - // to find the min and max coordinates of the selected objects - // with that we can create a bounding box and zoom selected - var points = new List(); - foreach (var obj in modelObjects) + // to find the min and max coordinates of the selected objects + // with that we can create a bounding box and zoom selected + var points = new List(); + foreach (var obj in modelObjects) + { + points.Add(obj.GetCoordinateSystem().Origin); + foreach (TSM.ModelObject child in obj.GetChildren()) { - points.Add(obj.GetCoordinateSystem().Origin); - foreach (TSM.ModelObject child in obj.GetChildren()) - { - points.Add(child.GetCoordinateSystem().Origin); - } + points.Add(child.GetCoordinateSystem().Origin); } + } - var minX = points.Min(p => p.X); - var minY = points.Min(p => p.Y); - var minZ = points.Min(p => p.Z); - var maxX = points.Max(p => p.X); - var maxY = points.Max(p => p.Y); - var maxZ = points.Max(p => p.Z); + var minX = points.Min(p => p.X); + var minY = points.Min(p => p.Y); + var minZ = points.Min(p => p.Z); + var maxX = points.Max(p => p.X); + var maxY = points.Max(p => p.Y); + var maxZ = points.Max(p => p.Z); - // create the bounding box - var bounds = new AABB { MinPoint = new Point(minX, minY, minZ), MaxPoint = new Point(maxX, maxY, maxZ) }; + // create the bounding box + var bounds = new AABB { MinPoint = new Point(minX, minY, minZ), MaxPoint = new Point(maxX, maxY, maxZ) }; - // zoom in to bounding box - TSMUI.ViewHandler.ZoomToBoundingBox(bounds); - } - _model.CommitChanges(); - }) - .ConfigureAwait(false); + // zoom in to bounding box + TSMUI.ViewHandler.ZoomToBoundingBox(bounds); + } + _model.CommitChanges(); + }); } catch (InvalidOperationException ex) { 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(); } } diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs index 54d99146e..cff0f1198 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs @@ -150,12 +150,9 @@ public async Task Send(string modelCardId) modelCard.GetSendInfo(_speckleApplication.Slug), _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationToken), cancellationToken - ) - .ConfigureAwait(false); + ); - await Commands - .SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults) - .ConfigureAwait(false); + await Commands.SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults); } catch (OperationCanceledException) { @@ -164,7 +161,7 @@ await Commands catch (Exception ex) when (!ex.IsFatal()) { _logger.LogModelCardHandledError(ex); - await Commands.SetModelError(modelCardId, ex).ConfigureAwait(false); + await Commands.SetModelError(modelCardId, ex); } } @@ -194,7 +191,7 @@ private async Task RunExpirationChecks() } } - await Commands.SetModelsExpired(expiredSenderIds).ConfigureAwait(false); + await Commands.SetModelsExpired(expiredSenderIds); ChangedObjectIds = new ConcurrentDictionary(); } diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Operations/Send/TeklaRootObjectBuilder.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Operations/Send/TeklaRootObjectBuilder.cs index 69da6664c..1f5bb8a2c 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,11 @@ TeklaMaterialUnpacker materialUnpacker _materialUnpacker = materialUnpacker; } - public async Task Build( + public RootObjectBuilderResult Build( IReadOnlyList teklaObjects, SendInfo sendInfo, IProgress onOperationProgressed, - CancellationToken cancellationToken = default + CancellationToken cancellationToken ) { using var activity = _activityFactory.Start("Build"); @@ -66,8 +65,8 @@ public async Task Build( { foreach (TSM.ModelObject teklaObject in teklaObjects) { - using var _2 = _activityFactory.Start("Convert"); cancellationToken.ThrowIfCancellationRequested(); + using var _2 = _activityFactory.Start("Convert"); var result = ConvertTeklaObject(teklaObject, rootObjectCollection, sendInfo.ProjectId); results.Add(result); @@ -88,7 +87,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 b112365cb..d9d42e0cf 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/ServiceRegistration.cs @@ -4,6 +4,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; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; @@ -31,7 +32,7 @@ public static IServiceCollection AddTekla(this IServiceCollection services) services.AddSingleton(); services.AddConnectorUtils(); - services.AddDUI(); + services.AddDUI(); services.AddDUIView(); services.AddSingleton(); diff --git a/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionSettingsFactory.cs b/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionSettingsFactory.cs index 5ae9ae250..e0464be1b 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 2a0613efd..81bd19a87 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 ) @@ -134,13 +134,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 @@ -203,7 +202,6 @@ public async Task CreateDatasets( } onOperationProgressed.Invoke("Writing to Database", count++ / featureClassElements.Count); - await Task.Yield(); } } diff --git a/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json b/Converters/Autocad/Speckle.Converters.Autocad2024/packages.lock.json index 1746e6ca9..2745b420f 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -360,12 +359,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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 c02306f83..644ac5291 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -315,12 +314,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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 e1c2988a6..7f32d3318 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.dui.webview": { @@ -324,12 +323,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Converters/Navisworks/Speckle.Converters.Navisworks2020/packages.lock.json b/Converters/Navisworks/Speckle.Converters.Navisworks2020/packages.lock.json index bb34ae7c9..a42e08815 100644 --- a/Converters/Navisworks/Speckle.Converters.Navisworks2020/packages.lock.json +++ b/Converters/Navisworks/Speckle.Converters.Navisworks2020/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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.logging": { @@ -347,12 +346,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Converters/Navisworks/Speckle.Converters.Navisworks2021/packages.lock.json b/Converters/Navisworks/Speckle.Converters.Navisworks2021/packages.lock.json index 2d16a81f3..6372a4c5b 100644 --- a/Converters/Navisworks/Speckle.Converters.Navisworks2021/packages.lock.json +++ b/Converters/Navisworks/Speckle.Converters.Navisworks2021/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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.logging": { @@ -347,12 +346,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Converters/Navisworks/Speckle.Converters.Navisworks2022/packages.lock.json b/Converters/Navisworks/Speckle.Converters.Navisworks2022/packages.lock.json index a65080ed1..d868b6b61 100644 --- a/Converters/Navisworks/Speckle.Converters.Navisworks2022/packages.lock.json +++ b/Converters/Navisworks/Speckle.Converters.Navisworks2022/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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.logging": { @@ -347,12 +346,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Converters/Navisworks/Speckle.Converters.Navisworks2023/packages.lock.json b/Converters/Navisworks/Speckle.Converters.Navisworks2023/packages.lock.json index 8d7228f42..7fae36030 100644 --- a/Converters/Navisworks/Speckle.Converters.Navisworks2023/packages.lock.json +++ b/Converters/Navisworks/Speckle.Converters.Navisworks2023/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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.logging": { @@ -347,12 +346,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Converters/Navisworks/Speckle.Converters.Navisworks2024/packages.lock.json b/Converters/Navisworks/Speckle.Converters.Navisworks2024/packages.lock.json index d18eea0e3..82f435381 100644 --- a/Converters/Navisworks/Speckle.Converters.Navisworks2024/packages.lock.json +++ b/Converters/Navisworks/Speckle.Converters.Navisworks2024/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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.logging": { @@ -347,12 +346,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" } } } diff --git a/Converters/Navisworks/Speckle.Converters.Navisworks2025/packages.lock.json b/Converters/Navisworks/Speckle.Converters.Navisworks2025/packages.lock.json index a80b0e7e9..984c3e5ab 100644 --- a/Converters/Navisworks/Speckle.Converters.Navisworks2025/packages.lock.json +++ b/Converters/Navisworks/Speckle.Converters.Navisworks2025/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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.logging": { @@ -347,12 +346,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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/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.Tests/Speckle.Connectors.DUI.Tests.csproj b/DUI3/Speckle.Connectors.DUI.Tests/Speckle.Connectors.DUI.Tests.csproj index 0b607cbe3..b5bbadceb 100644 --- a/DUI3/Speckle.Connectors.DUI.Tests/Speckle.Connectors.DUI.Tests.csproj +++ b/DUI3/Speckle.Connectors.DUI.Tests/Speckle.Connectors.DUI.Tests.csproj @@ -5,12 +5,6 @@ true Debug;Release;Local System.Runtime.CompilerServices.IsExternalInit;System.Runtime.CompilerServices.RequiresLocationAttribute - - - - CA2007; - $(NoWarn) - diff --git a/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json b/DUI3/Speckle.Connectors.DUI.Tests/packages.lock.json index fece2ae4f..107659d2c 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.logging": { @@ -406,12 +405,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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/DUI3ControlWebView.xaml.cs b/DUI3/Speckle.Connectors.DUI.WebView/DUI3ControlWebView.xaml.cs index c401a3289..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 Task ExecuteScriptAsyncMethod(string script, CancellationToken cancellationToken) + public void ExecuteScript(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.WebView/packages.lock.json b/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json index 81fa95ed9..2f7ce647b 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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.logging": { @@ -340,12 +339,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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.218, )", - "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" + "Speckle.Sdk.Dependencies": "[3.1.0-dev.218, )" } }, "speckle.connectors.logging": { @@ -648,12 +640,6 @@ "requested": "[3.1.0-dev.218, )", "resolved": "3.1.0-dev.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" - }, - "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/Bindings/IBasicConnectorBinding.cs b/DUI3/Speckle.Connectors.DUI/Bindings/IBasicConnectorBinding.cs index 2677926d4..28a229d6d 100644 --- a/DUI3/Speckle.Connectors.DUI/Bindings/IBasicConnectorBinding.cs +++ b/DUI3/Speckle.Connectors.DUI/Bindings/IBasicConnectorBinding.cs @@ -53,8 +53,7 @@ public BasicConnectorBindingCommands(IBrowserBridge bridge) Bridge = bridge; } - public async Task NotifyDocumentChanged() => - await Bridge.Send(NOTIFY_DOCUMENT_CHANGED_EVENT_NAME).ConfigureAwait(false); + public async Task NotifyDocumentChanged() => await Bridge.Send(NOTIFY_DOCUMENT_CHANGED_EVENT_NAME); /// /// Use it whenever you want to send global toast notification to UI. @@ -69,21 +68,17 @@ public async Task SetGlobalNotification( string message, bool autoClose = true ) => - await Bridge - .Send( - SET_GLOBAL_NOTIFICATION, - new - { - type, - title, - description = message, - autoClose - } - ) - .ConfigureAwait(false); + await Bridge.Send( + SET_GLOBAL_NOTIFICATION, + new + { + type, + title, + description = message, + autoClose + } + ); public async Task SetModelError(string modelCardId, Exception error) => - await Bridge - .Send(SET_MODEL_ERROR_UI_COMMAND_NAME, new { modelCardId, error = error.Message }) - .ConfigureAwait(false); + await Bridge.Send(SET_MODEL_ERROR_UI_COMMAND_NAME, new { modelCardId, error = error.Message }); } diff --git a/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs b/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs index 992aaf669..3724eed44 100644 --- a/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs +++ b/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs @@ -30,20 +30,18 @@ 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 +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 - await SendProgress(bridge, modelCardId, progress).ConfigureAwait(false); + SendProgress(bridge, modelCardId, progress); return; } @@ -72,9 +70,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/Bindings/ReceiveBindingUICommands.cs b/DUI3/Speckle.Connectors.DUI/Bindings/ReceiveBindingUICommands.cs index 0c7bd3428..2cabe20dd 100644 --- a/DUI3/Speckle.Connectors.DUI/Bindings/ReceiveBindingUICommands.cs +++ b/DUI3/Speckle.Connectors.DUI/Bindings/ReceiveBindingUICommands.cs @@ -17,16 +17,14 @@ public async Task SetModelReceiveResult( IEnumerable conversionResults ) { - await Bridge - .Send( - SET_MODEL_RECEIVE_RESULT_UI_COMMAND_NAME, - new - { - ModelCardId = modelCardId, - bakedObjectIds, - conversionResults - } - ) - .ConfigureAwait(false); + await Bridge.Send( + SET_MODEL_RECEIVE_RESULT_UI_COMMAND_NAME, + new + { + ModelCardId = modelCardId, + bakedObjectIds, + conversionResults + } + ); } } diff --git a/DUI3/Speckle.Connectors.DUI/Bindings/SendBindingUICommands.cs b/DUI3/Speckle.Connectors.DUI/Bindings/SendBindingUICommands.cs index 72569f5ac..45e3ff23f 100644 --- a/DUI3/Speckle.Connectors.DUI/Bindings/SendBindingUICommands.cs +++ b/DUI3/Speckle.Connectors.DUI/Bindings/SendBindingUICommands.cs @@ -12,43 +12,38 @@ public class SendBindingUICommands(IBrowserBridge bridge) : BasicConnectorBindin private const string SET_ID_MAP_COMMAND_NAME = "setIdMap"; // POC.. the only reasons this needs the bridge is to send? realtionship to these messages and the bridge is unclear - public async Task RefreshSendFilters() => - await Bridge.Send(REFRESH_SEND_FILTERS_UI_COMMAND_NAME).ConfigureAwait(false); + public async Task RefreshSendFilters() => await Bridge.Send(REFRESH_SEND_FILTERS_UI_COMMAND_NAME); public async Task SetModelsExpired(IEnumerable expiredModelIds) => - await Bridge.Send(SET_MODELS_EXPIRED_UI_COMMAND_NAME, expiredModelIds).ConfigureAwait(false); + await Bridge.Send(SET_MODELS_EXPIRED_UI_COMMAND_NAME, expiredModelIds); public async Task SetFilterObjectIds( string modelCardId, Dictionary idMap, List newSelectedObjectIds ) => - await Bridge - .Send( - SET_ID_MAP_COMMAND_NAME, - new - { - modelCardId, - idMap, - newSelectedObjectIds - } - ) - .ConfigureAwait(false); + await Bridge.Send( + SET_ID_MAP_COMMAND_NAME, + new + { + modelCardId, + idMap, + newSelectedObjectIds + } + ); public async Task SetModelSendResult( string modelCardId, string versionId, IEnumerable sendConversionResults ) => - await Bridge - .Send( - SET_MODEL_SEND_RESULT_UI_COMMAND_NAME, - new - { - modelCardId, - versionId, - sendConversionResults - } - ) - .ConfigureAwait(false); + await Bridge.Send( + SET_MODEL_SEND_RESULT_UI_COMMAND_NAME, + new + { + modelCardId, + versionId, + sendConversionResults + } + ); } diff --git a/DUI3/Speckle.Connectors.DUI/Bindings/TestBinding.cs b/DUI3/Speckle.Connectors.DUI/Bindings/TestBinding.cs index a5e095fbc..f43a0bd42 100644 --- a/DUI3/Speckle.Connectors.DUI/Bindings/TestBinding.cs +++ b/DUI3/Speckle.Connectors.DUI/Bindings/TestBinding.cs @@ -46,22 +46,20 @@ public async Task TriggerEvent(string eventName) switch (eventName) { case "emptyTestEvent": - await Parent.Send("emptyTestEvent").ConfigureAwait(false); + await Parent.Send("emptyTestEvent"); break; case "testEvent": default: - await Parent - .Send( - "testEvent", - new - { - IsOk = true, - Name = "foo", - Count = 42 - } - ) - .ConfigureAwait(false); + await Parent.Send( + "testEvent", + new + { + IsOk = true, + Name = "foo", + Count = 42 + } + ); break; } } diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 252119ab2..f692e41c3 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -3,8 +3,8 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.InteropServices; -using System.Threading.Tasks.Dataflow; using Microsoft.Extensions.Logging; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Utils; using Speckle.Newtonsoft.Json; @@ -27,15 +27,14 @@ public sealed class BrowserBridge : IBrowserBridge /// private readonly ConcurrentDictionary _resultsStore = new(); - private readonly SynchronizationContext _mainThreadContext; public ITopLevelExceptionHandler TopLevelExceptionHandler { get; } + private readonly IThreadContext _threadContext; + private readonly IThreadOptions _threadOptions; private readonly IBrowserScriptExecutor _browserScriptExecutor; private readonly IJsonSerializer _jsonSerializer; private IReadOnlyDictionary _bindingMethodCache = new Dictionary(); - - private ActionBlock? _actionBlock; private IBinding? _binding; private Type? _bindingType; @@ -57,26 +56,22 @@ private set } } - private struct RunMethodArgs - { - public string MethodName; - public string RequestId; - public string MethodArgs; - } - public BrowserBridge( + IThreadContext threadContext, IJsonSerializer jsonSerializer, ILogger logger, ILogger topLogger, - IBrowserScriptExecutor browserScriptExecutor + IBrowserScriptExecutor browserScriptExecutor, + IThreadOptions threadOptions ) { + _threadContext = threadContext; _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; + _threadOptions = threadOptions; } public void AssociateWithBinding(IBinding binding) @@ -95,30 +90,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 - ? _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. /// @@ -130,81 +104,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) - { - TopLevelExceptionHandler.CatchUnhandled(Post); - return; - - void Post() - { - bool wasAccepted = _actionBlock - .NotNull() - .Post( - new RunMethodArgs + //don't wait for browser runs on purpose + public void RunMethod(string methodName, string requestId, string methodArgs) => + _threadContext + .RunOnThreadAsync( + async () => + { + var task = await TopLevelExceptionHandler.CatchUnhandledAsync(async () => + { + var result = await ExecuteMethod(methodName, methodArgs); + string resultJson = _jsonSerializer.Serialize(result); + NotifyUIMethodCallResultReady(requestId, resultJson); + }); + if (task.Exception is not null) { - MethodName = methodName, - RequestId = requestId, - MethodArgs = args + string resultJson = SerializeFormattedException(task.Exception); + NotifyUIMethodCallResultReady(requestId, resultJson); } - ); - if (!wasAccepted) - { - throw new InvalidOperationException($"Action block declined to Post ({methodName} {requestId} {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; - } + }, + _threadOptions.RunCommandsOnMainThread + ) + .FireAndForget(); /// /// Used by the action block to invoke the actual method called by the UI. @@ -266,7 +186,7 @@ public Task RunOnMainThreadAsync(Func> action) } // It's an async call - await resultTypedTask.ConfigureAwait(false); + await resultTypedTask; // If has a "Result" property return the value otherwise null (Task etc) PropertyInfo? resultProperty = resultTypedTask.GetType().GetProperty(nameof(Task.Result)); @@ -296,16 +216,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.ExecuteScript(script); } /// @@ -339,7 +255,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) { @@ -348,10 +264,27 @@ public async Task Send(string eventName, CancellationToken cancellationToken = d var script = $"{FrontendBoundName}.emit('{eventName}')"; - await _browserScriptExecutor.ExecuteScriptAsyncMethod(script, cancellationToken).ConfigureAwait(false); + _browserScriptExecutor.ExecuteScript(script); + return Task.CompletedTask; + } + + public Task Send(string eventName, T data, CancellationToken cancellationToken = default) + 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); + return Task.CompletedTask; } - public async Task Send(string eventName, T data, CancellationToken cancellationToken = default) + public void Send2(string eventName, T data) where T : class { if (_binding is null) @@ -363,6 +296,6 @@ 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.ExecuteScript(script); } } diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs index 7bd772978..65ec766df 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserBridge.cs @@ -29,22 +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 public Task Send(string eventName, CancellationToken cancellationToken = default); @@ -56,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/IBrowserScriptExecutor.cs b/DUI3/Speckle.Connectors.DUI/Bridge/IBrowserScriptExecutor.cs index 6c3fb69f9..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 Task ExecuteScriptAsyncMethod(string script, CancellationToken cancellationToken); + public void ExecuteScript(string script); public bool IsBrowserInitialized { get; } diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/IdleCallManager.cs b/DUI3/Speckle.Connectors.DUI/Bridge/IdleCallManager.cs index 0b3e83504..d25c63d42 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/IdleCallManager.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/IdleCallManager.cs @@ -57,13 +57,13 @@ internal void SubscribeInternal(string id, Func action, Action addEvent) } public void AppOnIdle(Action removeEvent) => - _topLevelExceptionHandler.FireAndForget(async () => await AppOnIdleInternal(removeEvent).ConfigureAwait(false)); + _topLevelExceptionHandler.FireAndForget(async () => await AppOnIdleInternal(removeEvent)); internal async Task AppOnIdleInternal(Action removeEvent) { foreach (KeyValuePair> kvp in Calls) { - await _topLevelExceptionHandler.CatchUnhandledAsync(kvp.Value).ConfigureAwait(false); + await _topLevelExceptionHandler.CatchUnhandledAsync(kvp.Value); } Calls.Clear(); diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/SyncToUIThread.cs b/DUI3/Speckle.Connectors.DUI/Bridge/SyncToUIThread.cs deleted file mode 100644 index bb7bbe0c3..000000000 --- a/DUI3/Speckle.Connectors.DUI/Bridge/SyncToUIThread.cs +++ /dev/null @@ -1,18 +0,0 @@ -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); -} diff --git a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs index b8b78ee97..1684e3c81 100644 --- a/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs +++ b/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs @@ -58,14 +58,32 @@ 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(); + return new Result(); + } + catch (Exception ex) when (!ex.IsFatal()) { - await function().ConfigureAwait(false); - return null; - }) - .ConfigureAwait(false); + _logger.LogError(ex, UNHANDLED_LOGGER_TEMPLATE); + await SetGlobalNotification( + ToastNotificationType.DANGER, + "Unhandled Exception Occured", + ex.ToFormattedString(), + false + ); + return new(ex); + } + } + catch (Exception ex) + { + _logger.LogCritical(ex, UNHANDLED_LOGGER_TEMPLATE); + throw; + } } /// @@ -75,11 +93,11 @@ public async Task> CatchUnhandledAsync(Func> function) { try { - return new(await function.Invoke().ConfigureAwait(false)); + return new(await function.Invoke()); } catch (Exception ex) when (!ex.IsFatal()) { - await HandleException(ex).ConfigureAwait(false); + await HandleException(ex); return new(ex); } } @@ -97,12 +115,11 @@ private async Task HandleException(Exception ex) try { await SetGlobalNotification( - ToastNotificationType.DANGER, - "Unhandled Exception Occured", - ex.ToFormattedString(), - false - ) - .ConfigureAwait(false); + ToastNotificationType.DANGER, + "Unhandled Exception Occured", + ex.ToFormattedString(), + false + ); } catch (Exception toastEx) { @@ -126,19 +143,17 @@ 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); 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); + 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 + } + ); } diff --git a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs index 05f78b842..f922d234f 100644 --- a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs +++ b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs @@ -1,6 +1,6 @@ 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; @@ -11,22 +11,20 @@ namespace Speckle.Connectors.DUI; public static class ContainerRegistration { - public static void AddDUI(this IServiceCollection serviceCollection) + public static void AddDUI(this IServiceCollection serviceCollection) where TDocumentStore : DocumentModelStore + where TThreadContext : IThreadContext, new() { + // send operation and dependencies + serviceCollection.AddSingleton(new TThreadContext()); serviceCollection.AddSingleton(); - // send operation and dependencies - 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/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 23479f132..7e3e486e3 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.218", "contentHash": "c3lAtu/HXPd18dD64r4GVid6b9/4AoB/MDhJGOGJeQlcGPejBh4r9HuTGoPxMc25pdCwbiTUe4R1NPckEka4XA==" }, - "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 3d72a918e..ccc54be46 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -36,6 +36,7 @@ + @@ -44,8 +45,6 @@ - - diff --git a/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs b/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs index 7d9e150dc..112af1952 100644 --- a/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs +++ b/Sdk/Speckle.Connectors.Common/Builders/IHostObjectBuilder.cs @@ -14,11 +14,10 @@ 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, diff --git a/Sdk/Speckle.Connectors.Common/Builders/IRootObjectBuilder.cs b/Sdk/Speckle.Connectors.Common/Builders/IRootObjectBuilder.cs index f3584c726..747df3acd 100644 --- a/Sdk/Speckle.Connectors.Common/Builders/IRootObjectBuilder.cs +++ b/Sdk/Speckle.Connectors.Common/Builders/IRootObjectBuilder.cs @@ -6,11 +6,11 @@ namespace Speckle.Connectors.Common.Builders; public interface IRootObjectBuilder { - public Task Build( + public RootObjectBuilderResult Build( IReadOnlyList objects, SendInfo sendInfo, IProgress onOperationProgressed, - CancellationToken ct = default + CancellationToken cancellationToken ); } 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); -} diff --git a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs index caaa0162f..5827a715f 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; @@ -14,7 +15,9 @@ public sealed class ReceiveOperation( IReceiveProgress receiveProgress, ISdkActivityFactory activityFactory, IOperations operations, - IClientFactory clientFactory + IClientFactory clientFactory, + IThreadContext threadContext, + IThreadOptions threadOptions ) { public async Task Execute( @@ -30,41 +33,49 @@ CancellationToken cancellationToken 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) - .ConfigureAwait(false); + var version = await apiClient.Version.Get(receiveInfo.SelectedVersionId, receiveInfo.ProjectId, cancellationToken); - receiveProgress.Begin(); - Base? commitObject = await operations - .Receive2( - new Uri(account.serverInfo.url), - receiveInfo.ProjectId, - version.referencedObject, - account.token, - onProgressAction: new PassthroughProgress(args => receiveProgress.Report(onOperationProgressed, args)), - cancellationToken: cancellationToken - ) - .ConfigureAwait(false); - - cancellationToken.ThrowIfCancellationRequested(); + var commitObject = await threadContext.RunOnWorkerAsync( + () => ReceiveData(account, version, receiveInfo, onOperationProgressed, cancellationToken) + ); // 4 - Convert objects - HostObjectBuilderResult? res = await ConvertObjects( - commitObject, - receiveInfo, - onOperationProgressed, - cancellationToken - ) - .ConfigureAwait(false); + HostObjectBuilderResult res = await threadContext.RunOnThread( + () => ConvertObjects(commitObject, receiveInfo, onOperationProgressed, cancellationToken), + threadOptions.RunReceiveBuildOnMainThread + ); - await apiClient - .Version.Received(new(version.id, receiveInfo.ProjectId, receiveInfo.SourceApplication), cancellationToken) - .ConfigureAwait(false); + await apiClient.Version.Received( + new(version.id, receiveInfo.ProjectId, receiveInfo.SourceApplication), + cancellationToken + ); return res; } - private async Task ConvertObjects( + private async Task ReceiveData( + Account account, + Speckle.Sdk.Api.GraphQL.Models.Version version, + ReceiveInfo receiveInfo, + IProgress onOperationProgressed, + CancellationToken cancellationToken + ) + { + receiveProgress.Begin(); + Base commitObject = await operations.Receive2( + new Uri(account.serverInfo.url), + receiveInfo.ProjectId, + version.referencedObject, + account.token, + onProgressAction: new PassthroughProgress(args => receiveProgress.Report(onOperationProgressed, args)), + cancellationToken: cancellationToken + ); + + cancellationToken.ThrowIfCancellationRequested(); + return commitObject; + } + + private HostObjectBuilderResult ConvertObjects( Base commitObject, ReceiveInfo receiveInfo, IProgress onOperationProgressed, @@ -81,9 +92,13 @@ 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, + cancellationToken + ); conversionActivity?.SetStatus(SdkActivityStatusCode.Ok); return res; } diff --git a/Sdk/Speckle.Connectors.Common/Operations/ReceiveProgress.cs b/Sdk/Speckle.Connectors.Common/Operations/ReceiveProgress.cs index a0ca61bc4..2939496f3 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/ReceiveProgress.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/ReceiveProgress.cs @@ -13,34 +13,32 @@ public sealed class ReceiveProgress(IProgressDisplayManager progressDisplayManag public void Report(IProgress onOperationProgressed, ProgressArgs args) { + switch (args.ProgressEvent) { - switch (args.ProgressEvent) - { - case ProgressEvent.CacheCheck: - _previousPercentage = progressDisplayManager.CalculatePercentage(args); - break; - case ProgressEvent.DownloadBytes: - _previousSpeed = progressDisplayManager.CalculateSpeed(args); - break; - } + case ProgressEvent.CacheCheck: + _previousPercentage = progressDisplayManager.CalculatePercentage(args); + break; + case ProgressEvent.DownloadBytes: + _previousSpeed = progressDisplayManager.CalculateSpeed(args); + break; + } - if (!progressDisplayManager.ShouldUpdate()) - { - return; - } + if (!progressDisplayManager.ShouldUpdate()) + { + return; + } - switch (args.ProgressEvent) - { - case ProgressEvent.CacheCheck: - onOperationProgressed.Report(new("Checking cache... ", _previousPercentage)); - break; - case ProgressEvent.DownloadBytes: - onOperationProgressed.Report(new($"Downloading... ({_previousSpeed})", null)); - break; - case ProgressEvent.DeserializeObject: - onOperationProgressed.Report(new("Deserializing ...", progressDisplayManager.CalculatePercentage(args))); - break; - } + switch (args.ProgressEvent) + { + case ProgressEvent.CacheCheck: + onOperationProgressed.Report(new("Checking cache... ", _previousPercentage)); + break; + case ProgressEvent.DownloadBytes: + onOperationProgressed.Report(new($"Downloading... ({_previousSpeed})", null)); + break; + case ProgressEvent.DeserializeObject: + onOperationProgressed.Report(new("Deserializing ...", progressDisplayManager.CalculatePercentage(args))); + break; } } } diff --git a/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs b/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs index 19a9d3524..3f432ddbf 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs @@ -1,6 +1,7 @@ using Speckle.Connectors.Common.Builders; using Speckle.Connectors.Common.Caching; using Speckle.Connectors.Common.Conversion; +using Speckle.Connectors.Common.Threading; using Speckle.Connectors.Logging; using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Inputs; @@ -19,7 +20,8 @@ public sealed class SendOperation( ISendProgress sendProgress, IOperations operations, IClientFactory clientFactory, - ISdkActivityFactory activityFactory + ISdkActivityFactory activityFactory, + IThreadContext threadContext ) { public async Task Execute( @@ -29,7 +31,9 @@ public async Task Execute( CancellationToken ct = default ) { - var buildResult = await rootObjectBuilder.Build(objects, sendInfo, onOperationProgressed, ct).ConfigureAwait(false); + var buildResult = await threadContext.RunOnMain( + () => rootObjectBuilder.Build(objects, sendInfo, onOperationProgressed, ct) + ); // POC: Jonathon asks on behalf of willow twin - let's explore how this can work // buildResult.RootObject["@report"] = new Report { ConversionResults = buildResult.ConversionResults }; @@ -37,8 +41,9 @@ 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 Send(buildResult.RootObject, sendInfo, onOperationProgressed, ct) - .ConfigureAwait(false); + var (rootObjId, convertedReferences) = await threadContext.RunOnWorkerAsync( + () => Send(buildResult.RootObject, sendInfo, onOperationProgressed, ct) + ); return new(rootObjId, convertedReferences, buildResult.ConversionResults); } @@ -59,16 +64,14 @@ public async Task Send( using var activity = activityFactory.Start("SendOperation"); sendProgress.Begin(); - var sendResult = await operations - .Send2( - sendInfo.ServerUrl, - sendInfo.ProjectId, - account.token, - commitObject, - onProgressAction: new PassthroughProgress(args => sendProgress.Report(onOperationProgressed, args)), - ct - ) - .ConfigureAwait(false); + var sendResult = await operations.Send2( + sendInfo.ServerUrl, + sendInfo.ProjectId, + account.token, + commitObject, + onProgressAction: new PassthroughProgress(args => sendProgress.Report(onOperationProgressed, args)), + ct + ); sendConversionCache.StoreSendResult(sendInfo.ProjectId, sendResult.ConvertedReferences); diff --git a/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs b/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs new file mode 100644 index 000000000..5c5f2194b --- /dev/null +++ b/Sdk/Speckle.Connectors.Common/Threading/DefaultThreadContext.cs @@ -0,0 +1,72 @@ +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 action(); + tcs.SetResult(result); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }, + null + ); + return tcs.Task; + } + + protected override Task MainToWorkerAsync(Func> action) + { + Task> f = Task.Factory.StartNew( + async () => await 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( + _ => + { + try + { + T result = action(); + 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/TaskExtensions.cs b/Sdk/Speckle.Connectors.Common/Threading/TaskExtensions.cs new file mode 100644 index 000000000..3ebc31b8c --- /dev/null +++ b/Sdk/Speckle.Connectors.Common/Threading/TaskExtensions.cs @@ -0,0 +1,8 @@ +namespace Speckle.Connectors.Common.Threading; + +public static class TaskExtensions +{ +#pragma warning disable CA1030 + public static async void FireAndForget(this Task valueTask) => await valueTask; +#pragma warning restore CA1030 +} diff --git a/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs b/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs new file mode 100644 index 000000000..e98d7d5cc --- /dev/null +++ b/Sdk/Speckle.Connectors.Common/Threading/ThreadContext.cs @@ -0,0 +1,122 @@ +using Speckle.InterfaceGenerator; + +namespace Speckle.Connectors.Common.Threading; + +[GenerateAutoInterface] +public abstract class ThreadContext : IThreadContext +{ + private static readonly Task s_empty = Task.FromResult(null); + public static bool IsMainThread => Environment.CurrentManagedThreadId == 1; + + public async Task RunOnThread(Action action, bool useMain) + { + if (useMain) + { + if (IsMainThread) + { + action(); + } + else + { + await WorkerToMainAsync(() => + { + action(); + return s_empty; + }); + } + } + else + { + if (IsMainThread) + { + await MainToWorkerAsync(() => + { + action(); + return s_empty; + }); + } + else + { + action(); + } + } + } + + public virtual Task RunOnThread(Func action, bool useMain) + { + if (useMain) + { + if (IsMainThread) + { + return Task.FromResult(action()); + } + + return WorkerToMain(action); + } + if (IsMainThread) + { + return MainToWorker(action); + } + + return Task.FromResult(action()); + } + + public async Task RunOnThreadAsync(Func action, bool useMain) + { + if (useMain) + { + if (IsMainThread) + { + await action(); + } + else + { + await WorkerToMainAsync(async () => + { + await action(); + return Task.FromResult(null); + }); + } + } + else + { + if (IsMainThread) + { + await MainToWorkerAsync(async () => + { + await action(); + return Task.FromResult(null); + }); + } + else + { + await action(); + } + } + } + + public Task RunOnThreadAsync(Func> action, bool useMain) + { + if (useMain) + { + if (IsMainThread) + { + return action(); + } + + return WorkerToMainAsync(action); + } + if (IsMainThread) + { + return MainToWorkerAsync(action); + } + return action(); + } + + protected abstract Task WorkerToMainAsync(Func> action); + + protected abstract Task MainToWorkerAsync(Func> action); + protected abstract Task WorkerToMain(Func action); + + protected abstract Task MainToWorker(Func action); +} diff --git a/Sdk/Speckle.Connectors.Common/Threading/ThreadContextExtensions.cs b/Sdk/Speckle.Connectors.Common/Threading/ThreadContextExtensions.cs new file mode 100644 index 000000000..b6dbf2c59 --- /dev/null +++ b/Sdk/Speckle.Connectors.Common/Threading/ThreadContextExtensions.cs @@ -0,0 +1,28 @@ +namespace Speckle.Connectors.Common.Threading; + +public static class ThreadContextExtensions +{ + public static Task RunOnMain(this IThreadContext threadContext, Action action) => + threadContext.RunOnThread(action, true); + + public static Task 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); + + 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); +} diff --git a/Sdk/Speckle.Connectors.Common/Threading/ThreadOptions.cs b/Sdk/Speckle.Connectors.Common/Threading/ThreadOptions.cs new file mode 100644 index 000000000..3ef94b7f2 --- /dev/null +++ b/Sdk/Speckle.Connectors.Common/Threading/ThreadOptions.cs @@ -0,0 +1,12 @@ +using Speckle.InterfaceGenerator; +using Speckle.Sdk; +using Speckle.Sdk.Host; + +namespace Speckle.Connectors.Common.Threading; + +[GenerateAutoInterface] +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.Tests/ActivityScopeTests.cs b/Sdk/Speckle.Connectors.Tests/ActivityScopeTests.cs index 3305d84f4..e92d64788 100644 --- a/Sdk/Speckle.Connectors.Tests/ActivityScopeTests.cs +++ b/Sdk/Speckle.Connectors.Tests/ActivityScopeTests.cs @@ -9,7 +9,7 @@ public class ActivityScopeTests public async Task TestAsyncLocal() { Logging.ActivityScope.SetTag("test", "me"); - await Task.Delay(10).ConfigureAwait(false); + await Task.Delay(10); Logging.ActivityScope.Tags.ContainsKey("test").Should().BeTrue(); Logging.ActivityScope.Tags["test"].Should().Be("me"); }