diff --git a/Backup/Speckle.Connectors.sln b/Backup/Speckle.Connectors.sln deleted file mode 100644 index 3f260cbb4..000000000 --- a/Backup/Speckle.Connectors.sln +++ /dev/null @@ -1,424 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.10.35027.167 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Config", "Config", "{85A13E25-EB29-4F31-8853-B9EE83275B3D}" - ProjectSection(SolutionItems) = preProject - .csharpierrc.yaml = .csharpierrc.yaml - .editorconfig = .editorconfig - codecov.yml = codecov.yml - Directory.Build.props = Directory.Build.props - Directory.Build.targets = Directory.Build.targets - Directory.Packages.props = Directory.Packages.props - global.json = global.json - README.md = README.md - CodeMetricsConfig.txt = CodeMetricsConfig.txt - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DUI3", "DUI3", "{FD4D6594-D81E-456F-8F2E-35B09E04A755}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Revit", "Revit", "{D92751C8-1039-4005-90B2-913E55E0B8BD}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sdk", "Sdk", "{2E00592E-558D-492D-88F9-3ECEE4C0C7DA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.Revit2023", "Connectors\Revit\Speckle.Connectors.Revit2023\Speckle.Connectors.Revit2023.csproj", "{01F98733-7352-47AD-A594-537D979DE3DE}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Connectors.RevitShared", "Connectors\Revit\Speckle.Connectors.RevitShared\Speckle.Connectors.RevitShared.shproj", "{DC570FFF-6FE5-47BD-8BC1-B471A6067786}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Converters.RevitShared", "Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.shproj", "{E1C43415-3200-45F4-8BF9-A4DD7D7F2ED6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2023.DependencyInjection", "Converters\Revit\Speckle.Converters.Revit2023.DependencyInjection\Speckle.Converters.Revit2023.DependencyInjection.csproj", "{83EAD6F0-3CB3-456A-AD81-072127D0DE0E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2023", "Converters\Revit\Speckle.Converters.Revit2023\Speckle.Converters.Revit2023.csproj", "{26391930-F86F-47E0-A5F6-B89919E38CE1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.DUI", "DUI3\Speckle.Connectors.DUI\Speckle.Connectors.DUI.csproj", "{D81C0B87-F0C1-4297-A147-02F001FB7E1E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Autofac", "Sdk\Speckle.Autofac\Speckle.Autofac.csproj", "{C9D4CA21-182B-4ED2-81BB-280A6FD713F6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.Utils", "Sdk\Speckle.Connectors.Utils\Speckle.Connectors.Utils.csproj", "{7291B93C-615D-42DE-B8C1-3F9DF643E0FC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Common", "Sdk\Speckle.Converters.Common\Speckle.Converters.Common.csproj", "{8AEF06C0-CA5C-4460-BC2D-ADE5F35D0434}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Rhino", "Rhino", "{9584AEE5-CD59-46E6-93E6-2DC2B5285B75}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.Rhino7", "Connectors\Rhino\Speckle.Connectors.Rhino7\Speckle.Connectors.Rhino7.csproj", "{1E2644A9-6B31-4350-8772-CEAAD6EE0B21}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Rhino7", "Converters\Rhino\Speckle.Converters.Rhino7\Speckle.Converters.Rhino7.csproj", "{65A2F556-F14A-49F3-8A92-7F2E1E7ED3B5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Rhino7.DependencyInjection", "Converters\Rhino\Speckle.Converters.Rhino7.DependencyInjection\Speckle.Converters.Rhino7.DependencyInjection.csproj", "{9C1ECA1D-DE98-4FB7-92D0-FC45BB308E5D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.ArcGIS3", "Connectors\ArcGIS\Speckle.Connectors.ArcGIS3\Speckle.Connectors.ArcGIS3.csproj", "{A97F7177-86C7-4B38-A6ED-DA51BF762471}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.ArcGIS3", "Converters\ArcGIS\Speckle.Converters.ArcGIS3\Speckle.Converters.ArcGIS3.csproj", "{139F7A79-69E4-4B8A-B2A5-6A30A66C495C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.ArcGIS3.DependencyInjection", "Converters\ArcGIS\Speckle.Converters.ArcGIS3.DependencyInjection\Speckle.Converters.ArcGIS3.DependencyInjection.csproj", "{7DFF1591-237D-499E-A767-EE37B93FB958}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ArcGIS", "ArcGIS", "{CCF48B65-33D1-4E8B-A57B-E03394730B21}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.Autocad2023", "Connectors\Autocad\Speckle.Connectors.Autocad2023\Speckle.Connectors.Autocad2023.csproj", "{89C4CBC7-1606-40DE-B6DA-FBE3AAC98395}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Connectors.AutocadShared", "Connectors\Autocad\Speckle.Connectors.AutocadShared\Speckle.Connectors.AutocadShared.shproj", "{41BC679F-887F-44CF-971D-A5502EE87DB0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Common.DependencyInjection", "Sdk\Speckle.Converters.Common.DependencyInjection\Speckle.Converters.Common.DependencyInjection.csproj", "{11F7D41B-AFCA-4D29-BC08-285A14BF3A3B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Autocad", "Autocad", "{804E065F-914C-414A-AF84-009312C3CFF6}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Converters.AutocadShared", "Converters\Autocad\Speckle.Converters.AutocadShared\Speckle.Converters.AutocadShared.shproj", "{9ADD1B7A-6401-4202-8613-F668E2FBC0A4}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Autocad2023", "Converters\Autocad\Speckle.Converters.Autocad2023\Speckle.Converters.Autocad2023.csproj", "{631C295A-7CCF-4B42-8686-7034E31469E7}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Autocad2023.DependencyInjection", "Converters\Autocad\Speckle.Converters.Autocad2023.DependencyInjection\Speckle.Converters.Autocad2023.DependencyInjection.csproj", "{D940853C-003A-482C-BDB0-665367F274A0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.DUI.WebView", "DUI3\Speckle.Connectors.DUI.WebView\Speckle.Connectors.DUI.WebView.csproj", "{7420652C-3046-4F38-BE64-9B9E69D76FA2}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Build", "Build\Build.csproj", "{C50AA3E3-8C31-4131-9DEC-1D8B377D5A89}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HostApps", "HostApps", "{42826721-9A18-4762-8BA9-F1429DD5C5B1}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{59E8E8F3-4E42-4E92-83B3-B1C2AB901D18}" - ProjectSection(SolutionItems) = preProject - .github\workflows\ci.yml = .github\workflows\ci.yml - .github\workflows\main.yml = .github\workflows\main.yml - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.Civil3d2024", "Connectors\Autocad\Speckle.Connectors.Civil3d2024\Speckle.Connectors.Civil3d2024.csproj", "{CA8EAE01-AB9F-4EC1-B6F3-73721487E9E1}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Converters.Civil3dShared", "Converters\Civil3d\Speckle.Converters.Civil3dShared\Speckle.Converters.Civil3dShared.shproj", "{35175682-DA83-4C0A-A49D-B191F5885D8E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Civil3d2024.DependencyInjection", "Converters\Civil3d\Speckle.Converters.Civil3d2024.DependencyInjection\Speckle.Converters.Civil3d2024.DependencyInjection.csproj", "{80F965C4-E2A8-4F54-985D-73D06E45F9CE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Autocad2024", "Converters\Autocad\Speckle.Converters.Autocad2024\Speckle.Converters.Autocad2024.csproj", "{C2DE264A-AA87-4012-B954-17E3F403A237}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Autocad2024.DependencyInjection", "Converters\Autocad\Speckle.Converters.Autocad2024.DependencyInjection\Speckle.Converters.Autocad2024.DependencyInjection.csproj", "{AF507D61-6766-4C20-9F58-23DC29508219}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Civil3d2024", "Converters\Civil3d\Speckle.Converters.Civil3d2024\Speckle.Converters.Civil3d2024.csproj", "{25172C49-7AA4-4739-BB07-69785094C379}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Converters.RhinoShared", "Converters\Rhino\Speckle.Converters.RhinoShared\Speckle.Converters.RhinoShared.shproj", "{E1C43415-3200-45F4-8BF9-A4DD7D7F2ED9}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Rhino7.Tests", "Converters\Rhino\Speckle.Converters.Rhino7.Tests\Speckle.Converters.Rhino7.Tests.csproj", "{AC2DB416-F05C-4296-9040-56D6AD4FCD27}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2023.Tests", "Converters\Revit\Speckle.Converters.Revit2023.Tests\Speckle.Converters.Revit2023.Tests.csproj", "{68CF9BDF-94AC-4D2D-A7BD-D1C064F97051}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Testing", "Sdk\Speckle.Testing\Speckle.Testing.csproj", "{A3869243-B462-4986-914B-94E407D8D20F}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Converters.RevitShared.DependencyInjection", "Converters\Revit\Speckle.Converters.RevitShared.DependencyInjection\Speckle.Converters.RevitShared.DependencyInjection.shproj", "{6067BA60-D279-4156-8AE1-6B44E2D19187}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.Revit2024", "Connectors\Revit\Speckle.Connectors.Revit2024\Speckle.Connectors.Revit2024.csproj", "{617BD3C7-87D9-4D28-8AC9-4910945BB9FC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2024", "Converters\Revit\Speckle.Converters.Revit2024\Speckle.Converters.Revit2024.csproj", "{67B888D9-C6C4-49F1-883C-5B964151D889}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2024.DependencyInjection", "Converters\Revit\Speckle.Converters.Revit2024.DependencyInjection\Speckle.Converters.Revit2024.DependencyInjection.csproj", "{7F3055BA-70AA-424C-8748-345AF35127E9}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2023", "2023", "{E9DEBA00-50A4-485D-BA65-D8AB3E3467AB}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2024", "2024", "{57F59C0C-5687-4AF9-AE1C-1933B539F0E4}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{FC224610-32D3-454E-9BC1-1219FE8ACD5F}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Converters.RevitShared.Tests", "Converters\Revit\Speckle.Converters.RevitShared.Tests\Speckle.Converters.RevitShared.Tests.shproj", "{E1C43415-3202-45F4-8BF9-A4DD7D7F2ED6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2024.Tests", "Converters\Revit\Speckle.Converters.Revit2024.Tests\Speckle.Converters.Revit2024.Tests.csproj", "{C32274D9-1B66-4D5C-82F9-EB3F10F46752}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Connectors.RevitShared.Cef", "Connectors\Revit\Speckle.Connectors.RevitShared.Cef\Speckle.Connectors.RevitShared.Cef.shproj", "{6A40CBE4-ECAB-4CED-9917-5C64CBF75DA6}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2025", "2025", "{8AC2AD6D-6C74-4B24-8DF6-42717FC9B804}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.Revit2025", "Connectors\Revit\Speckle.Connectors.Revit2025\Speckle.Connectors.Revit2025.csproj", "{A6DE3DA0-B242-4F49-AEF0-4E26AF92D16C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2025", "Converters\Revit\Speckle.Converters.Revit2025\Speckle.Converters.Revit2025.csproj", "{4D40A101-07E6-4FF2-8934-83434932591D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2025.DependencyInjection", "Converters\Revit\Speckle.Converters.Revit2025.DependencyInjection\Speckle.Converters.Revit2025.DependencyInjection.csproj", "{20751904-0DFC-4126-BF2A-834B53841010}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.Revit2022", "Connectors\Revit\Speckle.Connectors.Revit2022\Speckle.Connectors.Revit2022.csproj", "{7F1FDCF2-0CE8-4119-B3C1-F2CC6D7E1C36}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2022", "Converters\Revit\Speckle.Converters.Revit2022\Speckle.Converters.Revit2022.csproj", "{19424B55-058C-4E9C-B86F-700AEF9EAEC3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2022.DependencyInjection", "Converters\Revit\Speckle.Converters.Revit2022.DependencyInjection\Speckle.Converters.Revit2022.DependencyInjection.csproj", "{881D71A3-D276-4108-98C6-0FFD32129B9C}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2022", "2022", "{0AF38BA3-65A0-481B-8CBB-B82E406E1575}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Connectors.DUI.Tests", "DUI3\Speckle.Connectors.DUI.Tests\Speckle.Connectors.DUI.Tests.csproj", "{EB83A3A3-F9B6-4281-8EBF-F7289FB5D885}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2022.Tests", "Converters\Revit\Speckle.Converters.Revit2022.Tests\Speckle.Converters.Revit2022.Tests.csproj", "{D8069A23-AD2E-4C9E-8574-7E8C45296A46}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2023", "2023", "{2D5AE63D-85C0-43D1-84BF-04418ED93F63}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2024", "2024", "{2F45036E-D817-41E9-B82F-DBE013EC95D0}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Civil3d", "Civil3d", "{91D70DE1-DC8E-4AE1-B100-0671D6263FC5}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{4721AA15-AF6E-4A62-A2C3-65564DC563E6}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {01F98733-7352-47AD-A594-537D979DE3DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {01F98733-7352-47AD-A594-537D979DE3DE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {01F98733-7352-47AD-A594-537D979DE3DE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {01F98733-7352-47AD-A594-537D979DE3DE}.Release|Any CPU.Build.0 = Release|Any CPU - {83EAD6F0-3CB3-456A-AD81-072127D0DE0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {83EAD6F0-3CB3-456A-AD81-072127D0DE0E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {83EAD6F0-3CB3-456A-AD81-072127D0DE0E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {83EAD6F0-3CB3-456A-AD81-072127D0DE0E}.Release|Any CPU.Build.0 = Release|Any CPU - {26391930-F86F-47E0-A5F6-B89919E38CE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {26391930-F86F-47E0-A5F6-B89919E38CE1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {26391930-F86F-47E0-A5F6-B89919E38CE1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {26391930-F86F-47E0-A5F6-B89919E38CE1}.Release|Any CPU.Build.0 = Release|Any CPU - {D81C0B87-F0C1-4297-A147-02F001FB7E1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D81C0B87-F0C1-4297-A147-02F001FB7E1E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D81C0B87-F0C1-4297-A147-02F001FB7E1E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D81C0B87-F0C1-4297-A147-02F001FB7E1E}.Release|Any CPU.Build.0 = Release|Any CPU - {C9D4CA21-182B-4ED2-81BB-280A6FD713F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C9D4CA21-182B-4ED2-81BB-280A6FD713F6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C9D4CA21-182B-4ED2-81BB-280A6FD713F6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C9D4CA21-182B-4ED2-81BB-280A6FD713F6}.Release|Any CPU.Build.0 = Release|Any CPU - {7291B93C-615D-42DE-B8C1-3F9DF643E0FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7291B93C-615D-42DE-B8C1-3F9DF643E0FC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7291B93C-615D-42DE-B8C1-3F9DF643E0FC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7291B93C-615D-42DE-B8C1-3F9DF643E0FC}.Release|Any CPU.Build.0 = Release|Any CPU - {8AEF06C0-CA5C-4460-BC2D-ADE5F35D0434}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8AEF06C0-CA5C-4460-BC2D-ADE5F35D0434}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8AEF06C0-CA5C-4460-BC2D-ADE5F35D0434}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8AEF06C0-CA5C-4460-BC2D-ADE5F35D0434}.Release|Any CPU.Build.0 = Release|Any CPU - {1E2644A9-6B31-4350-8772-CEAAD6EE0B21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1E2644A9-6B31-4350-8772-CEAAD6EE0B21}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1E2644A9-6B31-4350-8772-CEAAD6EE0B21}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1E2644A9-6B31-4350-8772-CEAAD6EE0B21}.Release|Any CPU.Build.0 = Release|Any CPU - {65A2F556-F14A-49F3-8A92-7F2E1E7ED3B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {65A2F556-F14A-49F3-8A92-7F2E1E7ED3B5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {65A2F556-F14A-49F3-8A92-7F2E1E7ED3B5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {65A2F556-F14A-49F3-8A92-7F2E1E7ED3B5}.Release|Any CPU.Build.0 = Release|Any CPU - {9C1ECA1D-DE98-4FB7-92D0-FC45BB308E5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9C1ECA1D-DE98-4FB7-92D0-FC45BB308E5D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9C1ECA1D-DE98-4FB7-92D0-FC45BB308E5D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9C1ECA1D-DE98-4FB7-92D0-FC45BB308E5D}.Release|Any CPU.Build.0 = Release|Any CPU - {A97F7177-86C7-4B38-A6ED-DA51BF762471}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A97F7177-86C7-4B38-A6ED-DA51BF762471}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A97F7177-86C7-4B38-A6ED-DA51BF762471}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A97F7177-86C7-4B38-A6ED-DA51BF762471}.Release|Any CPU.Build.0 = Release|Any CPU - {139F7A79-69E4-4B8A-B2A5-6A30A66C495C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {139F7A79-69E4-4B8A-B2A5-6A30A66C495C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {139F7A79-69E4-4B8A-B2A5-6A30A66C495C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {139F7A79-69E4-4B8A-B2A5-6A30A66C495C}.Release|Any CPU.Build.0 = Release|Any CPU - {7DFF1591-237D-499E-A767-EE37B93FB958}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7DFF1591-237D-499E-A767-EE37B93FB958}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7DFF1591-237D-499E-A767-EE37B93FB958}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7DFF1591-237D-499E-A767-EE37B93FB958}.Release|Any CPU.Build.0 = Release|Any CPU - {89C4CBC7-1606-40DE-B6DA-FBE3AAC98395}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {89C4CBC7-1606-40DE-B6DA-FBE3AAC98395}.Debug|Any CPU.Build.0 = Debug|Any CPU - {89C4CBC7-1606-40DE-B6DA-FBE3AAC98395}.Release|Any CPU.ActiveCfg = Release|Any CPU - {89C4CBC7-1606-40DE-B6DA-FBE3AAC98395}.Release|Any CPU.Build.0 = Release|Any CPU - {11F7D41B-AFCA-4D29-BC08-285A14BF3A3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {11F7D41B-AFCA-4D29-BC08-285A14BF3A3B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {11F7D41B-AFCA-4D29-BC08-285A14BF3A3B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {11F7D41B-AFCA-4D29-BC08-285A14BF3A3B}.Release|Any CPU.Build.0 = Release|Any CPU - {631C295A-7CCF-4B42-8686-7034E31469E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {631C295A-7CCF-4B42-8686-7034E31469E7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {631C295A-7CCF-4B42-8686-7034E31469E7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {631C295A-7CCF-4B42-8686-7034E31469E7}.Release|Any CPU.Build.0 = Release|Any CPU - {D940853C-003A-482C-BDB0-665367F274A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D940853C-003A-482C-BDB0-665367F274A0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D940853C-003A-482C-BDB0-665367F274A0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D940853C-003A-482C-BDB0-665367F274A0}.Release|Any CPU.Build.0 = Release|Any CPU - {7420652C-3046-4F38-BE64-9B9E69D76FA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7420652C-3046-4F38-BE64-9B9E69D76FA2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7420652C-3046-4F38-BE64-9B9E69D76FA2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7420652C-3046-4F38-BE64-9B9E69D76FA2}.Release|Any CPU.Build.0 = Release|Any CPU - {C50AA3E3-8C31-4131-9DEC-1D8B377D5A89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C50AA3E3-8C31-4131-9DEC-1D8B377D5A89}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C50AA3E3-8C31-4131-9DEC-1D8B377D5A89}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C50AA3E3-8C31-4131-9DEC-1D8B377D5A89}.Release|Any CPU.Build.0 = Release|Any CPU - {CA8EAE01-AB9F-4EC1-B6F3-73721487E9E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CA8EAE01-AB9F-4EC1-B6F3-73721487E9E1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CA8EAE01-AB9F-4EC1-B6F3-73721487E9E1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CA8EAE01-AB9F-4EC1-B6F3-73721487E9E1}.Release|Any CPU.Build.0 = Release|Any CPU - {80F965C4-E2A8-4F54-985D-73D06E45F9CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {80F965C4-E2A8-4F54-985D-73D06E45F9CE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {80F965C4-E2A8-4F54-985D-73D06E45F9CE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {80F965C4-E2A8-4F54-985D-73D06E45F9CE}.Release|Any CPU.Build.0 = Release|Any CPU - {C2DE264A-AA87-4012-B954-17E3F403A237}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C2DE264A-AA87-4012-B954-17E3F403A237}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C2DE264A-AA87-4012-B954-17E3F403A237}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C2DE264A-AA87-4012-B954-17E3F403A237}.Release|Any CPU.Build.0 = Release|Any CPU - {AF507D61-6766-4C20-9F58-23DC29508219}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AF507D61-6766-4C20-9F58-23DC29508219}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AF507D61-6766-4C20-9F58-23DC29508219}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AF507D61-6766-4C20-9F58-23DC29508219}.Release|Any CPU.Build.0 = Release|Any CPU - {25172C49-7AA4-4739-BB07-69785094C379}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {25172C49-7AA4-4739-BB07-69785094C379}.Debug|Any CPU.Build.0 = Debug|Any CPU - {25172C49-7AA4-4739-BB07-69785094C379}.Release|Any CPU.ActiveCfg = Release|Any CPU - {25172C49-7AA4-4739-BB07-69785094C379}.Release|Any CPU.Build.0 = Release|Any CPU - {AC2DB416-F05C-4296-9040-56D6AD4FCD27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AC2DB416-F05C-4296-9040-56D6AD4FCD27}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AC2DB416-F05C-4296-9040-56D6AD4FCD27}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AC2DB416-F05C-4296-9040-56D6AD4FCD27}.Release|Any CPU.Build.0 = Release|Any CPU - {68CF9BDF-94AC-4D2D-A7BD-D1C064F97051}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {68CF9BDF-94AC-4D2D-A7BD-D1C064F97051}.Debug|Any CPU.Build.0 = Debug|Any CPU - {68CF9BDF-94AC-4D2D-A7BD-D1C064F97051}.Release|Any CPU.ActiveCfg = Release|Any CPU - {68CF9BDF-94AC-4D2D-A7BD-D1C064F97051}.Release|Any CPU.Build.0 = Release|Any CPU - {A3869243-B462-4986-914B-94E407D8D20F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A3869243-B462-4986-914B-94E407D8D20F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A3869243-B462-4986-914B-94E407D8D20F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A3869243-B462-4986-914B-94E407D8D20F}.Release|Any CPU.Build.0 = Release|Any CPU - {617BD3C7-87D9-4D28-8AC9-4910945BB9FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {617BD3C7-87D9-4D28-8AC9-4910945BB9FC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {617BD3C7-87D9-4D28-8AC9-4910945BB9FC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {617BD3C7-87D9-4D28-8AC9-4910945BB9FC}.Release|Any CPU.Build.0 = Release|Any CPU - {67B888D9-C6C4-49F1-883C-5B964151D889}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {67B888D9-C6C4-49F1-883C-5B964151D889}.Debug|Any CPU.Build.0 = Debug|Any CPU - {67B888D9-C6C4-49F1-883C-5B964151D889}.Release|Any CPU.ActiveCfg = Release|Any CPU - {67B888D9-C6C4-49F1-883C-5B964151D889}.Release|Any CPU.Build.0 = Release|Any CPU - {7F3055BA-70AA-424C-8748-345AF35127E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7F3055BA-70AA-424C-8748-345AF35127E9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7F3055BA-70AA-424C-8748-345AF35127E9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7F3055BA-70AA-424C-8748-345AF35127E9}.Release|Any CPU.Build.0 = Release|Any CPU - {C32274D9-1B66-4D5C-82F9-EB3F10F46752}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C32274D9-1B66-4D5C-82F9-EB3F10F46752}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C32274D9-1B66-4D5C-82F9-EB3F10F46752}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C32274D9-1B66-4D5C-82F9-EB3F10F46752}.Release|Any CPU.Build.0 = Release|Any CPU - {A6DE3DA0-B242-4F49-AEF0-4E26AF92D16C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A6DE3DA0-B242-4F49-AEF0-4E26AF92D16C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A6DE3DA0-B242-4F49-AEF0-4E26AF92D16C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A6DE3DA0-B242-4F49-AEF0-4E26AF92D16C}.Release|Any CPU.Build.0 = Release|Any CPU - {4D40A101-07E6-4FF2-8934-83434932591D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4D40A101-07E6-4FF2-8934-83434932591D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4D40A101-07E6-4FF2-8934-83434932591D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4D40A101-07E6-4FF2-8934-83434932591D}.Release|Any CPU.Build.0 = Release|Any CPU - {20751904-0DFC-4126-BF2A-834B53841010}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {20751904-0DFC-4126-BF2A-834B53841010}.Debug|Any CPU.Build.0 = Debug|Any CPU - {20751904-0DFC-4126-BF2A-834B53841010}.Release|Any CPU.ActiveCfg = Release|Any CPU - {20751904-0DFC-4126-BF2A-834B53841010}.Release|Any CPU.Build.0 = Release|Any CPU - {7F1FDCF2-0CE8-4119-B3C1-F2CC6D7E1C36}.Debug|Any CPU.ActiveCfg = Debug|x64 - {7F1FDCF2-0CE8-4119-B3C1-F2CC6D7E1C36}.Debug|Any CPU.Build.0 = Debug|x64 - {7F1FDCF2-0CE8-4119-B3C1-F2CC6D7E1C36}.Release|Any CPU.ActiveCfg = Debug|x64 - {7F1FDCF2-0CE8-4119-B3C1-F2CC6D7E1C36}.Release|Any CPU.Build.0 = Debug|x64 - {19424B55-058C-4E9C-B86F-700AEF9EAEC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {19424B55-058C-4E9C-B86F-700AEF9EAEC3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {19424B55-058C-4E9C-B86F-700AEF9EAEC3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {19424B55-058C-4E9C-B86F-700AEF9EAEC3}.Release|Any CPU.Build.0 = Release|Any CPU - {881D71A3-D276-4108-98C6-0FFD32129B9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {881D71A3-D276-4108-98C6-0FFD32129B9C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {881D71A3-D276-4108-98C6-0FFD32129B9C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {881D71A3-D276-4108-98C6-0FFD32129B9C}.Release|Any CPU.Build.0 = Release|Any CPU - {EB83A3A3-F9B6-4281-8EBF-F7289FB5D885}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EB83A3A3-F9B6-4281-8EBF-F7289FB5D885}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EB83A3A3-F9B6-4281-8EBF-F7289FB5D885}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EB83A3A3-F9B6-4281-8EBF-F7289FB5D885}.Release|Any CPU.Build.0 = Release|Any CPU - {D8069A23-AD2E-4C9E-8574-7E8C45296A46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D8069A23-AD2E-4C9E-8574-7E8C45296A46}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D8069A23-AD2E-4C9E-8574-7E8C45296A46}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D8069A23-AD2E-4C9E-8574-7E8C45296A46}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {D92751C8-1039-4005-90B2-913E55E0B8BD} = {42826721-9A18-4762-8BA9-F1429DD5C5B1} - {01F98733-7352-47AD-A594-537D979DE3DE} = {E9DEBA00-50A4-485D-BA65-D8AB3E3467AB} - {DC570FFF-6FE5-47BD-8BC1-B471A6067786} = {FC224610-32D3-454E-9BC1-1219FE8ACD5F} - {E1C43415-3200-45F4-8BF9-A4DD7D7F2ED6} = {FC224610-32D3-454E-9BC1-1219FE8ACD5F} - {83EAD6F0-3CB3-456A-AD81-072127D0DE0E} = {E9DEBA00-50A4-485D-BA65-D8AB3E3467AB} - {26391930-F86F-47E0-A5F6-B89919E38CE1} = {E9DEBA00-50A4-485D-BA65-D8AB3E3467AB} - {D81C0B87-F0C1-4297-A147-02F001FB7E1E} = {FD4D6594-D81E-456F-8F2E-35B09E04A755} - {C9D4CA21-182B-4ED2-81BB-280A6FD713F6} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA} - {7291B93C-615D-42DE-B8C1-3F9DF643E0FC} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA} - {8AEF06C0-CA5C-4460-BC2D-ADE5F35D0434} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA} - {9584AEE5-CD59-46E6-93E6-2DC2B5285B75} = {42826721-9A18-4762-8BA9-F1429DD5C5B1} - {1E2644A9-6B31-4350-8772-CEAAD6EE0B21} = {9584AEE5-CD59-46E6-93E6-2DC2B5285B75} - {65A2F556-F14A-49F3-8A92-7F2E1E7ED3B5} = {9584AEE5-CD59-46E6-93E6-2DC2B5285B75} - {9C1ECA1D-DE98-4FB7-92D0-FC45BB308E5D} = {9584AEE5-CD59-46E6-93E6-2DC2B5285B75} - {A97F7177-86C7-4B38-A6ED-DA51BF762471} = {CCF48B65-33D1-4E8B-A57B-E03394730B21} - {139F7A79-69E4-4B8A-B2A5-6A30A66C495C} = {CCF48B65-33D1-4E8B-A57B-E03394730B21} - {7DFF1591-237D-499E-A767-EE37B93FB958} = {CCF48B65-33D1-4E8B-A57B-E03394730B21} - {CCF48B65-33D1-4E8B-A57B-E03394730B21} = {42826721-9A18-4762-8BA9-F1429DD5C5B1} - {11F7D41B-AFCA-4D29-BC08-285A14BF3A3B} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA} - {804E065F-914C-414A-AF84-009312C3CFF6} = {42826721-9A18-4762-8BA9-F1429DD5C5B1} - {7420652C-3046-4F38-BE64-9B9E69D76FA2} = {FD4D6594-D81E-456F-8F2E-35B09E04A755} - {C50AA3E3-8C31-4131-9DEC-1D8B377D5A89} = {59E8E8F3-4E42-4E92-83B3-B1C2AB901D18} - {E1C43415-3200-45F4-8BF9-A4DD7D7F2ED9} = {9584AEE5-CD59-46E6-93E6-2DC2B5285B75} - {AC2DB416-F05C-4296-9040-56D6AD4FCD27} = {9584AEE5-CD59-46E6-93E6-2DC2B5285B75} - {68CF9BDF-94AC-4D2D-A7BD-D1C064F97051} = {E9DEBA00-50A4-485D-BA65-D8AB3E3467AB} - {A3869243-B462-4986-914B-94E407D8D20F} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA} - {6067BA60-D279-4156-8AE1-6B44E2D19187} = {FC224610-32D3-454E-9BC1-1219FE8ACD5F} - {617BD3C7-87D9-4D28-8AC9-4910945BB9FC} = {57F59C0C-5687-4AF9-AE1C-1933B539F0E4} - {67B888D9-C6C4-49F1-883C-5B964151D889} = {57F59C0C-5687-4AF9-AE1C-1933B539F0E4} - {7F3055BA-70AA-424C-8748-345AF35127E9} = {57F59C0C-5687-4AF9-AE1C-1933B539F0E4} - {E9DEBA00-50A4-485D-BA65-D8AB3E3467AB} = {D92751C8-1039-4005-90B2-913E55E0B8BD} - {57F59C0C-5687-4AF9-AE1C-1933B539F0E4} = {D92751C8-1039-4005-90B2-913E55E0B8BD} - {FC224610-32D3-454E-9BC1-1219FE8ACD5F} = {D92751C8-1039-4005-90B2-913E55E0B8BD} - {E1C43415-3202-45F4-8BF9-A4DD7D7F2ED6} = {FC224610-32D3-454E-9BC1-1219FE8ACD5F} - {C32274D9-1B66-4D5C-82F9-EB3F10F46752} = {57F59C0C-5687-4AF9-AE1C-1933B539F0E4} - {6A40CBE4-ECAB-4CED-9917-5C64CBF75DA6} = {FC224610-32D3-454E-9BC1-1219FE8ACD5F} - {8AC2AD6D-6C74-4B24-8DF6-42717FC9B804} = {D92751C8-1039-4005-90B2-913E55E0B8BD} - {A6DE3DA0-B242-4F49-AEF0-4E26AF92D16C} = {8AC2AD6D-6C74-4B24-8DF6-42717FC9B804} - {4D40A101-07E6-4FF2-8934-83434932591D} = {8AC2AD6D-6C74-4B24-8DF6-42717FC9B804} - {20751904-0DFC-4126-BF2A-834B53841010} = {8AC2AD6D-6C74-4B24-8DF6-42717FC9B804} - {7F1FDCF2-0CE8-4119-B3C1-F2CC6D7E1C36} = {0AF38BA3-65A0-481B-8CBB-B82E406E1575} - {19424B55-058C-4E9C-B86F-700AEF9EAEC3} = {0AF38BA3-65A0-481B-8CBB-B82E406E1575} - {881D71A3-D276-4108-98C6-0FFD32129B9C} = {0AF38BA3-65A0-481B-8CBB-B82E406E1575} - {0AF38BA3-65A0-481B-8CBB-B82E406E1575} = {D92751C8-1039-4005-90B2-913E55E0B8BD} - {EB83A3A3-F9B6-4281-8EBF-F7289FB5D885} = {FD4D6594-D81E-456F-8F2E-35B09E04A755} - {D8069A23-AD2E-4C9E-8574-7E8C45296A46} = {0AF38BA3-65A0-481B-8CBB-B82E406E1575} - {2D5AE63D-85C0-43D1-84BF-04418ED93F63} = {804E065F-914C-414A-AF84-009312C3CFF6} - {89C4CBC7-1606-40DE-B6DA-FBE3AAC98395} = {2D5AE63D-85C0-43D1-84BF-04418ED93F63} - {631C295A-7CCF-4B42-8686-7034E31469E7} = {2D5AE63D-85C0-43D1-84BF-04418ED93F63} - {D940853C-003A-482C-BDB0-665367F274A0} = {2D5AE63D-85C0-43D1-84BF-04418ED93F63} - {2F45036E-D817-41E9-B82F-DBE013EC95D0} = {804E065F-914C-414A-AF84-009312C3CFF6} - {C2DE264A-AA87-4012-B954-17E3F403A237} = {2F45036E-D817-41E9-B82F-DBE013EC95D0} - {AF507D61-6766-4C20-9F58-23DC29508219} = {2F45036E-D817-41E9-B82F-DBE013EC95D0} - {91D70DE1-DC8E-4AE1-B100-0671D6263FC5} = {804E065F-914C-414A-AF84-009312C3CFF6} - {CA8EAE01-AB9F-4EC1-B6F3-73721487E9E1} = {91D70DE1-DC8E-4AE1-B100-0671D6263FC5} - {25172C49-7AA4-4739-BB07-69785094C379} = {91D70DE1-DC8E-4AE1-B100-0671D6263FC5} - {80F965C4-E2A8-4F54-985D-73D06E45F9CE} = {91D70DE1-DC8E-4AE1-B100-0671D6263FC5} - {35175682-DA83-4C0A-A49D-B191F5885D8E} = {91D70DE1-DC8E-4AE1-B100-0671D6263FC5} - {4721AA15-AF6E-4A62-A2C3-65564DC563E6} = {804E065F-914C-414A-AF84-009312C3CFF6} - {41BC679F-887F-44CF-971D-A5502EE87DB0} = {4721AA15-AF6E-4A62-A2C3-65564DC563E6} - {9ADD1B7A-6401-4202-8613-F668E2FBC0A4} = {4721AA15-AF6E-4A62-A2C3-65564DC563E6} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {EE253116-7070-4E9A-BCE8-2911C251B8C8} - EndGlobalSection - GlobalSection(SharedMSBuildProjectFiles) = preSolution - Connectors\Revit\Speckle.Connectors.RevitShared.Cef\Speckle.Connectors.RevitShared.Cef.projitems*{01f98733-7352-47ad-a594-537d979de3de}*SharedItemsImports = 5 - Connectors\Revit\Speckle.Connectors.RevitShared\Speckle.Connectors.RevitShared.projitems*{01f98733-7352-47ad-a594-537d979de3de}*SharedItemsImports = 5 - Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{19424b55-058c-4e9c-b86f-700aef9eaec3}*SharedItemsImports = 5 - Converters\Revit\Speckle.Converters.RevitShared.DependencyInjection\Speckle.Converters.RevitShared.DependencyInjection.projitems*{20751904-0dfc-4126-bf2a-834b53841010}*SharedItemsImports = 5 - Converters\Autocad\Speckle.Converters.AutocadShared\Speckle.Converters.AutocadShared.projitems*{25172c49-7aa4-4739-bb07-69785094c379}*SharedItemsImports = 5 - Converters\Civil3d\Speckle.Converters.Civil3dShared\Speckle.Converters.Civil3dShared.projitems*{25172c49-7aa4-4739-bb07-69785094c379}*SharedItemsImports = 5 - Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{26391930-f86f-47e0-a5f6-b89919e38ce1}*SharedItemsImports = 5 - Converters\Civil3d\Speckle.Converters.Civil3dShared\Speckle.Converters.Civil3dShared.projitems*{35175682-da83-4c0a-a49d-b191f5885d8e}*SharedItemsImports = 13 - Connectors\Autocad\Speckle.Connectors.AutocadShared\Speckle.Connectors.AutocadShared.projitems*{41bc679f-887f-44cf-971d-a5502ee87db0}*SharedItemsImports = 13 - Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{4d40a101-07e6-4ff2-8934-83434932591d}*SharedItemsImports = 5 - Converters\Revit\Speckle.Converters.RevitShared.DependencyInjection\Speckle.Converters.RevitShared.DependencyInjection.projitems*{6067ba60-d279-4156-8ae1-6b44e2d19187}*SharedItemsImports = 13 - Connectors\Revit\Speckle.Connectors.RevitShared.Cef\Speckle.Connectors.RevitShared.Cef.projitems*{617bd3c7-87d9-4d28-8ac9-4910945bb9fc}*SharedItemsImports = 5 - Connectors\Revit\Speckle.Connectors.RevitShared\Speckle.Connectors.RevitShared.projitems*{617bd3c7-87d9-4d28-8ac9-4910945bb9fc}*SharedItemsImports = 5 - Converters\Autocad\Speckle.Converters.AutocadShared\Speckle.Converters.AutocadShared.projitems*{631c295a-7ccf-4b42-8686-7034e31469e7}*SharedItemsImports = 5 - Converters\Rhino\Speckle.Converters.RhinoShared\Speckle.Converters.RhinoShared.projitems*{65a2f556-f14a-49f3-8a92-7f2e1e7ed3b5}*SharedItemsImports = 5 - Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{67b888d9-c6c4-49f1-883c-5b964151d889}*SharedItemsImports = 5 - Converters\Revit\Speckle.Converters.RevitShared.Tests\Speckle.Converters.RevitShared.Tests.projitems*{68cf9bdf-94ac-4d2d-a7bd-d1c064f97051}*SharedItemsImports = 5 - Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{68cf9bdf-94ac-4d2d-a7bd-d1c064f97051}*SharedItemsImports = 5 - Connectors\Revit\Speckle.Connectors.RevitShared.Cef\Speckle.Connectors.RevitShared.Cef.projitems*{6a40cbe4-ecab-4ced-9917-5c64cbf75da6}*SharedItemsImports = 13 - Connectors\Revit\Speckle.Connectors.RevitShared.Cef\Speckle.Connectors.RevitShared.Cef.projitems*{7f1fdcf2-0ce8-4119-b3c1-f2cc6d7e1c36}*SharedItemsImports = 5 - Connectors\Revit\Speckle.Connectors.RevitShared\Speckle.Connectors.RevitShared.projitems*{7f1fdcf2-0ce8-4119-b3c1-f2cc6d7e1c36}*SharedItemsImports = 5 - Converters\Revit\Speckle.Converters.RevitShared.DependencyInjection\Speckle.Converters.RevitShared.DependencyInjection.projitems*{7f3055ba-70aa-424c-8748-345af35127e9}*SharedItemsImports = 5 - Converters\Revit\Speckle.Converters.RevitShared.DependencyInjection\Speckle.Converters.RevitShared.DependencyInjection.projitems*{83ead6f0-3cb3-456a-ad81-072127d0de0e}*SharedItemsImports = 5 - Converters\Revit\Speckle.Converters.RevitShared.DependencyInjection\Speckle.Converters.RevitShared.DependencyInjection.projitems*{881d71a3-d276-4108-98c6-0ffd32129b9c}*SharedItemsImports = 5 - Connectors\Autocad\Speckle.Connectors.AutocadShared\Speckle.Connectors.AutocadShared.projitems*{89c4cbc7-1606-40de-b6da-fbe3aac98395}*SharedItemsImports = 5 - Converters\Autocad\Speckle.Converters.AutocadShared\Speckle.Converters.AutocadShared.projitems*{9add1b7a-6401-4202-8613-f668e2fbc0a4}*SharedItemsImports = 13 - Connectors\Revit\Speckle.Connectors.RevitShared\Speckle.Connectors.RevitShared.projitems*{a6de3da0-b242-4f49-aef0-4e26af92d16c}*SharedItemsImports = 5 - Converters\Rhino\Speckle.Converters.RhinoShared\Speckle.Converters.RhinoShared.projitems*{ac2db416-f05c-4296-9040-56d6ad4fcd27}*SharedItemsImports = 5 - Converters\Autocad\Speckle.Converters.AutocadShared\Speckle.Converters.AutocadShared.projitems*{c2de264a-aa87-4012-b954-17e3f403a237}*SharedItemsImports = 5 - Converters\Revit\Speckle.Converters.RevitShared.Tests\Speckle.Converters.RevitShared.Tests.projitems*{c32274d9-1b66-4d5c-82f9-eb3f10f46752}*SharedItemsImports = 5 - Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{c32274d9-1b66-4d5c-82f9-eb3f10f46752}*SharedItemsImports = 5 - Connectors\Autocad\Speckle.Connectors.AutocadShared\Speckle.Connectors.AutocadShared.projitems*{ca8eae01-ab9f-4ec1-b6f3-73721487e9e1}*SharedItemsImports = 5 - Converters\Revit\Speckle.Converters.RevitShared.Tests\Speckle.Converters.RevitShared.Tests.projitems*{d8069a23-ad2e-4c9e-8574-7e8c45296a46}*SharedItemsImports = 5 - Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{d8069a23-ad2e-4c9e-8574-7e8c45296a46}*SharedItemsImports = 5 - Connectors\Revit\Speckle.Connectors.RevitShared\Speckle.Connectors.RevitShared.projitems*{dc570fff-6fe5-47bd-8bc1-b471a6067786}*SharedItemsImports = 13 - Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{e1c43415-3200-45f4-8bf9-a4dd7d7f2ed6}*SharedItemsImports = 13 - Converters\Rhino\Speckle.Converters.RhinoShared\Speckle.Converters.RhinoShared.projitems*{e1c43415-3200-45f4-8bf9-a4dd7d7f2ed9}*SharedItemsImports = 13 - Converters\Revit\Speckle.Converters.RevitShared.Tests\Speckle.Converters.RevitShared.Tests.projitems*{e1c43415-3202-45f4-8bf9-a4dd7d7f2ed6}*SharedItemsImports = 13 - EndGlobalSection -EndGlobal diff --git a/Build/Solutions.cs b/Build/Solutions.cs index 64571c73b..6bb4eb41c 100644 --- a/Build/Solutions.cs +++ b/Build/Solutions.cs @@ -1,48 +1,49 @@ -using Microsoft.Build.Construction; -using Microsoft.VisualStudio.SolutionPersistence.Model; +using Microsoft.VisualStudio.SolutionPersistence.Model; using Microsoft.VisualStudio.SolutionPersistence.Serializer; namespace Build; public static class Solutions { - private static bool ValidProjects(KeyValuePair projectInSolution) => - projectInSolution.Value.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat; - - public static void CompareConnectorsToLocal() +#pragma warning disable CA1802 +#pragma warning disable IDE1006 + private static readonly string DIRECTORY = Environment.CurrentDirectory; +#pragma warning restore IDE1006 +#pragma warning restore CA1802 + public static async Task CompareConnectorsToLocal() { - var localSln = SolutionFile.Parse(Path.Combine(Environment.CurrentDirectory, "Local.sln")); - var connectorsSln = SolutionFile.Parse(Path.Combine(Environment.CurrentDirectory, "Speckle.Connectors.sln")); - var localProjects = localSln.ProjectsByGuid.Where(ValidProjects).ToDictionary(); + var localSln = await GetSolution("Local.sln"); + var connectorsSln = await GetSolution("Speckle.Connectors.sln"); + var localProjects = localSln.SolutionProjects.ToList(); - foreach ((string? _, ProjectInSolution? value) in connectorsSln.ProjectsByGuid.Where(ValidProjects)) + foreach (var value in connectorsSln.SolutionProjects) { - var localProject = localProjects.Values.FirstOrDefault(x => x.ProjectName == value.ProjectName); + var localProject = localProjects.FirstOrDefault(x => x.ActualDisplayName == value.ActualDisplayName); if (localProject is null) { - throw new InvalidOperationException($"Could not find in LOCAL solution: {value.ProjectName}"); + throw new InvalidOperationException($"Could not find in LOCAL solution: {value.ActualDisplayName}"); } - if (value.ProjectName != localProject.ProjectName) + if (value.ActualDisplayName != localProject.ActualDisplayName) { throw new InvalidOperationException( "Projects with different names have same Guid in solution: " - + value.ProjectName + + value.ActualDisplayName + " and " - + localProject.ProjectName + + localProject.ActualDisplayName ); } - localProjects.Remove(localProjects.Single(x => x.Value.ProjectName == value.ProjectName).Key); + localProjects.Remove(localProjects.Single(x => x.ActualDisplayName == value.ActualDisplayName)); } void CheckAndRemoveKnown(string projectName) { - var localProject = localProjects.Values.FirstOrDefault(x => x.ProjectName == projectName); + var localProject = localProjects.FirstOrDefault(x => x.ActualDisplayName == projectName); if (localProject is null) { throw new InvalidOperationException($"Could not find in LOCAL solution: {projectName}"); } - localProjects.Remove(localProjects.Single(x => x.Value.ProjectName == projectName).Key); + localProjects.Remove(localProjects.Single(x => x.ActualDisplayName == projectName)); } CheckAndRemoveKnown("Speckle.Objects"); @@ -51,7 +52,7 @@ public static class Solutions if (localProjects.Count != 0) { throw new InvalidOperationException( - "Could not find in CONNECTOR solution: " + localProjects.First().Value.ProjectName + "Could not find in CONNECTOR solution: " + localProjects.First().ActualDisplayName ); } } @@ -61,9 +62,9 @@ public static class Solutions await GenerateLocalSlnx(); foreach (var group in Consts.ProjectGroups) { - var path = group.Projects[0].ProjectPath.Split('/'); - var folder = $"/{path[0]}/{path[1]}/"; - await GenerateConnector(group.HostAppSlug, folder); + var connectors = await GetFullSlnx(); + var slug = group.HostAppSlug; + await GenerateConnector(connectors, group, string.Concat(slug[0].ToString().ToUpper(), slug.AsSpan(1))); } } @@ -73,16 +74,20 @@ public static class Solutions connectors.AddProject("..\\speckle-sharp-sdk\\src\\Speckle.Objects\\Speckle.Objects.csproj"); connectors.AddProject("..\\speckle-sharp-sdk\\src\\Speckle.Sdk\\Speckle.Sdk.csproj"); connectors.AddProject("..\\speckle-sharp-sdk\\src\\Speckle.Sdk.Dependencies\\Speckle.Sdk.Dependencies.csproj"); - var sln = Path.Combine("C:\\Users\\adam\\Git\\speckle-sharp-connectors", "Local.slnx"); + var sln = Path.Combine(DIRECTORY, "Local.slnx"); await SolutionSerializers.SlnXml.SaveAsync(sln, connectors, default); - sln = Path.Combine(Environment.CurrentDirectory, "Local.sln"); + sln = Path.Combine(DIRECTORY, "Local.sln"); await SolutionSerializers.SlnFileV12.SaveAsync(sln, connectors, default); + + var revit = Consts.ProjectGroups.Single(x => x.HostAppSlug.Equals("revit")); + await GenerateConnector(connectors, revit, "Revit.Local"); + await GenerateMacSolutions(); } - public static async Task GenerateConnector(string slug, string folder) + public static async Task GenerateConnector(SolutionModel connectors, ProjectGroup group, string? name) { - slug = string.Concat(slug[0].ToString().ToUpper(), slug.AsSpan(1)); - var connectors = await GetFullSlnx(); + var path = group.Projects[0].ProjectPath.Split('/'); + var folder = $"/{path[0]}/{path[1]}/"; var foldersToRemove = connectors .SolutionFolders.Where(x => //need base folder @@ -95,13 +100,38 @@ public static class Solutions { connectors.RemoveFolder(folderToRemove); } - var sln = Path.Combine(Environment.CurrentDirectory, $"Speckle.{slug}.slnx"); + var sln = Path.Combine(DIRECTORY, $"Speckle.{name}.slnx"); await SolutionSerializers.SlnXml.SaveAsync(sln, connectors, default); } public static async Task GetFullSlnx() { - var connectorsSln = Path.Combine(Environment.CurrentDirectory, "Speckle.Connectors.slnx"); + var connectorsSln = Path.Combine(DIRECTORY, "Speckle.Connectors.slnx"); return await SolutionSerializers.SlnXml.OpenAsync(connectorsSln, default); } + + public static async Task GetSolution(string solutionName) + { + var connectorsSln = Path.Combine(DIRECTORY, solutionName); + return await SolutionSerializers.SlnFileV12.OpenAsync(connectorsSln, default); + } + + public static async Task GenerateMacSolutions() + { + var connectors = await GetFullSlnx(); + var foldersToRemove = connectors + .SolutionFolders.Where(x => + //need base folder + !x.Path.Equals("/Connectors/") + //don't grab all + && (x.Path.StartsWith("/Connectors/")) + ) + .ToList(); + foreach (var folderToRemove in foldersToRemove) + { + connectors.RemoveFolder(folderToRemove); + } + var sln = Path.Combine(DIRECTORY, $"Speckle.Connectors.Mac.slnx"); + await SolutionSerializers.SlnXml.SaveAsync(sln, connectors, default); + } } diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadReceiveBaseBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadReceiveBaseBinding.cs index eb58a6783..8b8bb05fe 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadReceiveBaseBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadReceiveBaseBinding.cs @@ -1,119 +1,58 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; 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.Logging; -using Speckle.Connectors.DUI.Models; -using Speckle.Connectors.DUI.Models.Card; -using Speckle.Sdk; namespace Speckle.Connectors.Autocad.Bindings; -public abstract class AutocadReceiveBaseBinding : IReceiveBinding +public abstract class AutocadReceiveBaseBinding( + IBrowserBridge parent, + ICancellationManager cancellationManager, + IThreadContext threadContext, + IReceiveOperationManagerFactory receiveOperationManagerFactory +) : IReceiveBinding { public string Name => "receiveBinding"; - public IBrowserBridge Parent { get; } + public IBrowserBridge Parent { get; } = parent; - private readonly DocumentModelStore _store; - private readonly ICancellationManager _cancellationManager; - private readonly IServiceProvider _serviceProvider; - private readonly IOperationProgressManager _operationProgressManager; - private readonly ILogger _logger; - private readonly ISpeckleApplication _speckleApplication; - private readonly IThreadContext _threadContext; - - private ReceiveBindingUICommands Commands { get; } - - protected AutocadReceiveBaseBinding( - DocumentModelStore store, - IBrowserBridge parent, - ICancellationManager cancellationManager, - IServiceProvider serviceProvider, - IOperationProgressManager operationProgressManager, - ILogger logger, - ISpeckleApplication speckleApplication, - IThreadContext threadContext - ) - { - _store = store; - _cancellationManager = cancellationManager; - _serviceProvider = serviceProvider; - _operationProgressManager = operationProgressManager; - _logger = logger; - _speckleApplication = speckleApplication; - _threadContext = threadContext; - Parent = parent; - Commands = new ReceiveBindingUICommands(parent); - } + private ReceiveBindingUICommands Commands { get; } = new(parent); protected abstract void InitializeSettings(IServiceProvider serviceProvider); - public void CancelReceive(string modelCardId) => _cancellationManager.CancelOperation(modelCardId); + public void CancelReceive(string modelCardId) => cancellationManager.CancelOperation(modelCardId); public async Task Receive(string modelCardId) => - await _threadContext.RunOnMainAsync(async () => await ReceiveInternal(modelCardId)); + await threadContext.RunOnMainAsync(async () => await ReceiveInternal(modelCardId)); private async Task ReceiveInternal(string modelCardId) { - using var scope = _serviceProvider.CreateScope(); - InitializeSettings(scope.ServiceProvider); - - try - { - // Get receiver card - if (_store.GetModelById(modelCardId) is not ReceiverModelCard modelCard) + using var manager = receiveOperationManagerFactory.Create(); + await manager.Process( + Commands, + modelCardId, + InitializeSettings, + async (_, processor) => { - // Handle as GLOBAL ERROR at BrowserBridge - throw new InvalidOperationException("No download model card was found."); + try + { + // Disable document activation (document creation and document switch) + // Not disabling results in DUI model card being out of sync with the active document + // The DocumentActivated event isn't usable probably because it is pushed to back of main thread queue + Application.DocumentManager.DocumentActivationEnabled = false; + return await processor(); + } + finally + { + // reenable document activation + Application.DocumentManager.DocumentActivationEnabled = true; + + // regenerate doc to flush graphics, sometimes some objects (ellipses, nurbs curves) do not appear fully visible after receive. + // Adding a regen (must be run on main thread) here, but it doesn't seem to work: + // it's run on main thread, tried sending the "regen" string to execute, also tried regen after every object bake, but still can't fix. + // the objects should appear visible if you manually call the "regen" command after the operation finishes, or click on a view on the view cube which also calls regen. + Application.DocumentManager.CurrentDocument.Editor.Regen(); + } } - - using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId); - - // Disable document activation (document creation and document switch) - // Not disabling results in DUI model card being out of sync with the active document - // The DocumentActivated event isn't usable probably because it is pushed to back of main thread queue - Application.DocumentManager.DocumentActivationEnabled = false; - - // Receive host objects - var operationResults = await scope - .ServiceProvider.GetRequiredService() - .Execute( - modelCard.GetReceiveInfo(_speckleApplication.Slug), - _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationItem.Token), - cancellationItem.Token - ); - - await Commands.SetModelReceiveResult( - modelCardId, - operationResults.BakedObjectIds, - operationResults.ConversionResults - ); - } - catch (OperationCanceledException) - { - // SWALLOW -> UI handles it immediately, so we do not need to handle anything for now! - // Idea for later -> when cancel called, create promise from UI to solve it later with this catch block. - // So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled - return; - } - 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); - } - finally - { - // reenable document activation - Application.DocumentManager.DocumentActivationEnabled = true; - - // regenerate doc to flush graphics, sometimes some objects (ellipses, nurbs curves) do not appear fully visible after receive. - // Adding a regen (must be run on main thread) here, but it doesn't seem to work: - // it's run on main thread, tried sending the "regen" string to execute, also tried regen after every object bake, but still can't fix. - // the objects should appear visible if you manually call the "regen" command after the operation finishes, or click on a view on the view cube which also calls regen. - Application.DocumentManager.CurrentDocument.Editor.Regen(); - } + ); } } diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadReceiveBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadReceiveBinding.cs index fb2295040..4718aef6b 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadReceiveBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadReceiveBinding.cs @@ -1,13 +1,10 @@ using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Speckle.Connectors.Common.Cancellation; using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; -using Speckle.Connectors.DUI.Models; using Speckle.Converters.Autocad; using Speckle.Converters.Common; -using Speckle.Sdk; namespace Speckle.Connectors.Autocad.Bindings; @@ -16,26 +13,13 @@ public sealed class AutocadReceiveBinding : AutocadReceiveBaseBinding private readonly IAutocadConversionSettingsFactory _autocadConversionSettingsFactory; public AutocadReceiveBinding( - DocumentModelStore store, IBrowserBridge parent, ICancellationManager cancellationManager, - IServiceProvider serviceProvider, - IOperationProgressManager operationProgressManager, - ILogger logger, IAutocadConversionSettingsFactory autocadConversionSettingsFactory, - ISpeckleApplication speckleApplication, - IThreadContext threadContext + IThreadContext threadContext, + IReceiveOperationManagerFactory receiveOperationManagerFactory ) - : base( - store, - parent, - cancellationManager, - serviceProvider, - operationProgressManager, - logger, - speckleApplication, - threadContext - ) + : base(parent, cancellationManager, threadContext, receiveOperationManagerFactory) { _autocadConversionSettingsFactory = autocadConversionSettingsFactory; } diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs index c6e5d73d1..c63b83228 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBaseBinding.cs @@ -1,23 +1,16 @@ using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using Autodesk.AutoCAD.DatabaseServices; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Speckle.Connectors.Autocad.HostApp.Extensions; -using Speckle.Connectors.Autocad.Operations.Send; 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; -using Speckle.Connectors.DUI.Logging; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Connectors.DUI.Settings; -using Speckle.Sdk; using Speckle.Sdk.Common; namespace Speckle.Connectors.Autocad.Bindings; @@ -33,14 +26,11 @@ public abstract class AutocadSendBaseBinding : ISendBinding private readonly DocumentModelStore _store; private readonly List _sendFilters; private readonly ICancellationManager _cancellationManager; - private readonly IServiceProvider _serviceProvider; private readonly ISendConversionCache _sendConversionCache; - private readonly IOperationProgressManager _operationProgressManager; - private readonly ILogger _logger; - private readonly ISpeckleApplication _speckleApplication; private readonly IThreadContext _threadContext; private readonly ITopLevelExceptionHandler _topLevelExceptionHandler; private readonly IAppIdleManager _idleManager; + private readonly ISendOperationManagerFactory _sendOperationManagerFactory; /// /// 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: @@ -55,27 +45,21 @@ public abstract class AutocadSendBaseBinding : ISendBinding IBrowserBridge parent, IEnumerable sendFilters, ICancellationManager cancellationManager, - IServiceProvider serviceProvider, ISendConversionCache sendConversionCache, - IOperationProgressManager operationProgressManager, - ILogger logger, - ISpeckleApplication speckleApplication, IThreadContext threadContext, ITopLevelExceptionHandler topLevelExceptionHandler, - IAppIdleManager idleManager + IAppIdleManager idleManager, + ISendOperationManagerFactory sendOperationManagerFactory ) { _store = store; - _serviceProvider = serviceProvider; _cancellationManager = cancellationManager; _sendFilters = sendFilters.ToList(); _sendConversionCache = sendConversionCache; - _operationProgressManager = operationProgressManager; - _logger = logger; - _speckleApplication = speckleApplication; _threadContext = threadContext; _topLevelExceptionHandler = topLevelExceptionHandler; _idleManager = idleManager; + _sendOperationManagerFactory = sendOperationManagerFactory; Parent = parent; Commands = new SendBindingUICommands(parent); @@ -152,55 +136,17 @@ public abstract class AutocadSendBaseBinding : ISendBinding { try { - if (_store.GetModelById(modelCardId) is not SenderModelCard modelCard) - { - // Handle as GLOBAL ERROR at BrowserBridge - throw new InvalidOperationException("No publish model card was found."); - } - - using var scope = _serviceProvider.CreateScope(); - InitializeSettings(scope.ServiceProvider); - - using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId); - + using var manager = _sendOperationManagerFactory.Create(); // Disable document activation (document creation and document switch) // Not disabling results in DUI model card being out of sync with the active document // The DocumentActivated event isn't usable probably because it is pushed to back of main thread queue Application.DocumentManager.DocumentActivationEnabled = false; - - // Get elements to convert - List autocadObjects = Application.DocumentManager.CurrentDocument.GetObjects( - modelCard.SendFilter.NotNull().RefreshObjectIds() + await manager.Process( + Commands, + modelCardId, + (sp, card) => InitializeSettings(sp), + card => Application.DocumentManager.CurrentDocument.GetObjects(card.SendFilter.NotNull().RefreshObjectIds()) ); - - if (autocadObjects.Count == 0) - { - // Handle as CARD ERROR in this function - throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!"); - } - - var sendResult = await scope - .ServiceProvider.GetRequiredService>() - .Execute( - autocadObjects, - modelCard.GetSendInfo(_speckleApplication.ApplicationAndVersion), - _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationItem.Token), - cancellationItem.Token - ); - - await Commands.SetModelSendResult(modelCardId, sendResult.VersionId, sendResult.ConversionResults); - } - catch (OperationCanceledException) - { - // SWALLOW -> UI handles it immediately, so we do not need to handle anything for now! - // Idea for later -> when cancel called, create promise from UI to solve it later with this catch block. - // So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled - return; - } - 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); } finally { diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs index 5968bcdca..d99725beb 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Speckle.Connectors.Common.Caching; using Speckle.Connectors.Common.Cancellation; using Speckle.Connectors.Common.Threading; @@ -9,7 +8,6 @@ using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Converters.Autocad; using Speckle.Converters.Common; -using Speckle.Sdk; namespace Speckle.Connectors.Autocad.Bindings; @@ -22,29 +20,23 @@ public sealed class AutocadSendBinding : AutocadSendBaseBinding IBrowserBridge parent, IEnumerable sendFilters, ICancellationManager cancellationManager, - IServiceProvider serviceProvider, ISendConversionCache sendConversionCache, - IOperationProgressManager operationProgressManager, - ILogger logger, IAutocadConversionSettingsFactory autocadConversionSettingsFactory, - ISpeckleApplication speckleApplication, IThreadContext threadContext, ITopLevelExceptionHandler topLevelExceptionHandler, - IAppIdleManager appIdleManager + IAppIdleManager appIdleManager, + ISendOperationManagerFactory sendOperationManagerFactory ) : base( store, parent, sendFilters, cancellationManager, - serviceProvider, sendConversionCache, - operationProgressManager, - logger, - speckleApplication, threadContext, topLevelExceptionHandler, - appIdleManager + appIdleManager, + sendOperationManagerFactory ) { _autocadConversionSettingsFactory = autocadConversionSettingsFactory; diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs index 6cba21874..91c0248f4 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs @@ -7,7 +7,6 @@ using Speckle.Connectors.Common.Extensions; using Speckle.Connectors.Common.Operations; using Speckle.Connectors.Common.Operations.Receive; using Speckle.Converters.Common; -using Speckle.Sdk; using Speckle.Sdk.Common; using Speckle.Sdk.Dependencies; using Speckle.Sdk.Models; @@ -28,7 +27,8 @@ public class AutocadHostObjectBuilder( IAutocadMaterialBaker materialBaker, IAutocadColorBaker colorBaker, AutocadContext autocadContext, - RootObjectUnpacker rootObjectUnpacker + RootObjectUnpacker rootObjectUnpacker, + IReceiveConversionHandler conversionHandler ) : IHostObjectBuilder { public Task Build( @@ -90,11 +90,11 @@ public class AutocadHostObjectBuilder( var count = 0; foreach (var (layerPath, atomicObject) in atomicObjectsWithPath) { - string objectId = atomicObject.applicationId ?? atomicObject.id.NotNull(); onOperationProgressed.Report(new("Converting objects", (double)++count / atomicObjects.Count)); - cancellationToken.ThrowIfCancellationRequested(); - try + var ex = conversionHandler.TryConvert(() => { + cancellationToken.ThrowIfCancellationRequested(); + string objectId = atomicObject.applicationId ?? atomicObject.id.NotNull(); IReadOnlyCollection convertedObjects = ConvertObject(atomicObject, layerPath, baseLayerPrefix); applicationIdMap[objectId] = convertedObjects; @@ -109,8 +109,8 @@ public class AutocadHostObjectBuilder( ); bakedObjectIds.UnionWith(convertedObjects.Select(e => e.GetSpeckleApplicationId())); - } - catch (Exception ex) when (!ex.IsFatal()) + }); + if (ex != null) { results.Add(new(Status.ERROR, atomicObject, null, null, ex)); } diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Plugin/AutocadCommand.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Plugin/AutocadCommand.cs index a87e7240e..c8ad7ad2a 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Plugin/AutocadCommand.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Plugin/AutocadCommand.cs @@ -17,7 +17,7 @@ namespace Speckle.Connectors.Autocad.Plugin; public class AutocadCommand { private static PaletteSet? PaletteSet { get; set; } - private static readonly Guid s_id = new("3223E594-1B09-4E54-B3DD-8EA0BECE7BA5"); + private static readonly Guid s_id = new("7C27DD2B-86E8-4D31-B3DE-B34B267B1DC8"); public ServiceProvider? Container { get; private set; } private IDisposable? _disposableLogger; public const string COMMAND_STRING = "Speckle"; diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dReceiveBinding.cs b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dReceiveBinding.cs index a986aea62..194cfdbe1 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dReceiveBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dReceiveBinding.cs @@ -1,15 +1,12 @@ using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Speckle.Connectors.Autocad.Bindings; using Speckle.Connectors.Common.Cancellation; using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; -using Speckle.Connectors.DUI.Models; using Speckle.Converters.Autocad; using Speckle.Converters.Civil3dShared; using Speckle.Converters.Common; -using Speckle.Sdk; namespace Speckle.Connectors.Civil3dShared.Bindings; @@ -19,27 +16,14 @@ public sealed class Civil3dReceiveBinding : AutocadReceiveBaseBinding private readonly IAutocadConversionSettingsFactory _autocadConversionSettingsFactory; public Civil3dReceiveBinding( - DocumentModelStore store, IBrowserBridge parent, ICancellationManager cancellationManager, - IServiceProvider serviceProvider, - IOperationProgressManager operationProgressManager, - ILogger logger, ICivil3dConversionSettingsFactory civil3dConversionSettingsFactory, IAutocadConversionSettingsFactory autocadConversionSettingsFactory, - ISpeckleApplication speckleApplication, - IThreadContext threadContext + IThreadContext threadContext, + IReceiveOperationManagerFactory receiveOperationManagerFactory ) - : base( - store, - parent, - cancellationManager, - serviceProvider, - operationProgressManager, - logger, - speckleApplication, - threadContext - ) + : base(parent, cancellationManager, threadContext, receiveOperationManagerFactory) { _civil3dConversionSettingsFactory = civil3dConversionSettingsFactory; _autocadConversionSettingsFactory = autocadConversionSettingsFactory; diff --git a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs index d497027e6..140c46063 100644 --- a/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.Civil3dShared/Bindings/Civil3dSendBinding.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Speckle.Connectors.Autocad.Bindings; using Speckle.Connectors.Common.Caching; using Speckle.Connectors.Common.Cancellation; @@ -11,7 +10,6 @@ using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Converters.Autocad; using Speckle.Converters.Civil3dShared; using Speckle.Converters.Common; -using Speckle.Sdk; namespace Speckle.Connectors.Civil3dShared.Bindings; @@ -25,30 +23,24 @@ public sealed class Civil3dSendBinding : AutocadSendBaseBinding IBrowserBridge parent, IEnumerable sendFilters, ICancellationManager cancellationManager, - IServiceProvider serviceProvider, ISendConversionCache sendConversionCache, - IOperationProgressManager operationProgressManager, - ILogger logger, ICivil3dConversionSettingsFactory civil3dConversionSettingsFactory, IAutocadConversionSettingsFactory autocadConversionSettingsFactory, - ISpeckleApplication speckleApplication, IThreadContext threadContext, ITopLevelExceptionHandler topLevelExceptionHandler, - IAppIdleManager appIdleManager + IAppIdleManager appIdleManager, + ISendOperationManagerFactory sendOperationManagerFactory ) : base( store, parent, sendFilters, cancellationManager, - serviceProvider, sendConversionCache, - operationProgressManager, - logger, - speckleApplication, threadContext, topLevelExceptionHandler, - appIdleManager + appIdleManager, + sendOperationManagerFactory ) { _civil3dConversionSettingsFactory = civil3dConversionSettingsFactory; diff --git a/Connectors/CSi/Speckle.Connectors.CSiShared/Bindings/CsiSharedSendBinding.cs b/Connectors/CSi/Speckle.Connectors.CSiShared/Bindings/CsiSharedSendBinding.cs index a7eb53de9..62aa2a2d0 100644 --- a/Connectors/CSi/Speckle.Connectors.CSiShared/Bindings/CsiSharedSendBinding.cs +++ b/Connectors/CSi/Speckle.Connectors.CSiShared/Bindings/CsiSharedSendBinding.cs @@ -1,22 +1,14 @@ using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Speckle.Connectors.Common.Cancellation; -using Speckle.Connectors.Common.Operations; using Speckle.Connectors.CSiShared.HostApp; using Speckle.Connectors.CSiShared.Utils; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; -using Speckle.Connectors.DUI.Exceptions; -using Speckle.Connectors.DUI.Logging; -using Speckle.Connectors.DUI.Models; -using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Connectors.DUI.Settings; using Speckle.Converters.Common; using Speckle.Converters.CSiShared; -using Speckle.Sdk; using Speckle.Sdk.Common; -using Speckle.Sdk.Logging; namespace Speckle.Connectors.CSiShared.Bindings; @@ -26,43 +18,28 @@ public sealed class CsiSharedSendBinding : ISendBinding public SendBindingUICommands Commands { get; } public IBrowserBridge Parent { get; } - private readonly DocumentModelStore _store; - private readonly IServiceProvider _serviceProvider; private readonly List _sendFilters; private readonly ICancellationManager _cancellationManager; - private readonly IOperationProgressManager _operationProgressManager; - private readonly ILogger _logger; private readonly ICsiApplicationService _csiApplicationService; private readonly ICsiConversionSettingsFactory _csiConversionSettingsFactory; - private readonly ISpeckleApplication _speckleApplication; - private readonly ISdkActivityFactory _activityFactory; + private readonly ISendOperationManagerFactory _sendOperationManagerFactory; public CsiSharedSendBinding( - DocumentModelStore store, IBrowserBridge parent, IEnumerable sendFilters, - IServiceProvider serviceProvider, ICancellationManager cancellationManager, - IOperationProgressManager operationProgressManager, - ILogger logger, ICsiConversionSettingsFactory csiConversionSettingsFactory, - ISpeckleApplication speckleApplication, - ISdkActivityFactory activityFactory, - ICsiApplicationService csiApplicationService + ICsiApplicationService csiApplicationService, + ISendOperationManagerFactory sendOperationManagerFactory ) { - _store = store; - _serviceProvider = serviceProvider; _sendFilters = sendFilters.ToList(); _cancellationManager = cancellationManager; - _operationProgressManager = operationProgressManager; - _logger = logger; Parent = parent; Commands = new SendBindingUICommands(parent); _csiConversionSettingsFactory = csiConversionSettingsFactory; - _speckleApplication = speckleApplication; - _activityFactory = activityFactory; _csiApplicationService = csiApplicationService; + _sendOperationManagerFactory = sendOperationManagerFactory; } public List GetSendFilters() => _sendFilters; @@ -71,52 +48,15 @@ public sealed class CsiSharedSendBinding : ISendBinding public async Task Send(string modelCardId) { - using var activity = _activityFactory.Start(); - - try - { - if (_store.GetModelById(modelCardId) is not SenderModelCard modelCard) - { - throw new InvalidOperationException("No publish model card was found."); - } - using var scope = _serviceProvider.CreateScope(); - scope - .ServiceProvider.GetRequiredService>() - .Initialize(_csiConversionSettingsFactory.Create(_csiApplicationService.SapModel)); - - using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId); - - List wrappers = modelCard - .SendFilter.NotNull() - .RefreshObjectIds() - .Select(DecodeObjectIdentifier) - .ToList(); - - if (wrappers.Count == 0) - { - throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!"); - } - - var sendResult = await scope - .ServiceProvider.GetRequiredService>() - .Execute( - wrappers, - modelCard.GetSendInfo(_speckleApplication.ApplicationAndVersion), - _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationItem.Token), - cancellationItem.Token - ); - - await Commands.SetModelSendResult(modelCardId, sendResult.VersionId, sendResult.ConversionResults); - } - catch (OperationCanceledException) - { - return; - } - catch (Exception ex) when (!ex.IsFatal()) - { - _logger.LogModelCardHandledError(ex); - await Commands.SetModelError(modelCardId, ex); - } + using var manager = _sendOperationManagerFactory.Create(); + await manager.Process( + Commands, + modelCardId, + (sp, _) => + sp.GetRequiredService>() + .Initialize(_csiConversionSettingsFactory.Create(_csiApplicationService.SapModel)), + card => card.SendFilter.NotNull().RefreshObjectIds().Select(DecodeObjectIdentifier).ToList() + ); } private ICsiWrapper DecodeObjectIdentifier(string encodedId) diff --git a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Bindings/NavisworksSendBinding.cs b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Bindings/NavisworksSendBinding.cs index 8c29c5ff1..7603083a6 100644 --- a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Bindings/NavisworksSendBinding.cs +++ b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Bindings/NavisworksSendBinding.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Speckle.Connector.Navisworks.Operations.Send.Filters; using Speckle.Connector.Navisworks.Operations.Send.Settings; using Speckle.Connector.Navisworks.Services; @@ -9,7 +8,6 @@ using Speckle.Connectors.Common.Threading; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Exceptions; -using Speckle.Connectors.DUI.Logging; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.DUI.Models.Card.SendFilter; @@ -18,7 +16,6 @@ using Speckle.Converter.Navisworks.Settings; using Speckle.Converters.Common; using Speckle.Sdk; using Speckle.Sdk.Common; -using Speckle.Sdk.Logging; namespace Speckle.Connector.Navisworks.Bindings; @@ -30,45 +27,36 @@ public class NavisworksSendBinding : ISendBinding public SendBindingUICommands Commands { get; } private readonly DocumentModelStore _store; - private readonly IServiceProvider _serviceProvider; private readonly ICancellationManager _cancellationManager; - private readonly IOperationProgressManager _operationProgressManager; - private readonly ILogger _logger; private readonly ISpeckleApplication _speckleApplication; - private readonly ISdkActivityFactory _activityFactory; private readonly INavisworksConversionSettingsFactory _conversionSettingsFactory; private readonly ToSpeckleSettingsManagerNavisworks _toSpeckleSettingsManagerNavisworks; private readonly IElementSelectionService _selectionService; private readonly IThreadContext _threadContext; + private readonly ISendOperationManagerFactory _sendOperationManagerFactory; public NavisworksSendBinding( DocumentModelStore store, IBrowserBridge parent, - IServiceProvider serviceProvider, ICancellationManager cancellationManager, - IOperationProgressManager operationProgressManager, - ILogger logger, ISpeckleApplication speckleApplication, - ISdkActivityFactory activityFactory, INavisworksConversionSettingsFactory conversionSettingsFactory, ToSpeckleSettingsManagerNavisworks toSpeckleSettingsManagerNavisworks, IElementSelectionService selectionService, - IThreadContext threadContext + IThreadContext threadContext, + ISendOperationManagerFactory sendOperationManagerFactory ) { Parent = parent; Commands = new SendBindingUICommands(parent); _store = store; - _serviceProvider = serviceProvider; _cancellationManager = cancellationManager; - _operationProgressManager = operationProgressManager; - _logger = logger; _speckleApplication = speckleApplication; - _activityFactory = activityFactory; _conversionSettingsFactory = conversionSettingsFactory; _toSpeckleSettingsManagerNavisworks = toSpeckleSettingsManagerNavisworks; _selectionService = selectionService; _threadContext = threadContext; + _sendOperationManagerFactory = sendOperationManagerFactory; SubscribeToNavisworksEvents(); } @@ -78,7 +66,8 @@ public class NavisworksSendBinding : ISendBinding public List GetSendFilters() => [ new NavisworksSelectionFilter() { IsDefault = true }, - new NavisworksSavedSetsFilter(new ElementSelectionService()) + new NavisworksSavedSetsFilter(new ElementSelectionService()), + new NavisworksSavedViewsFilter(new ElementSelectionService()) ]; public List GetSendSettings() => @@ -95,60 +84,13 @@ public class NavisworksSendBinding : ISendBinding private async Task SendInternal(string modelCardId) { - using var activity = _activityFactory.Start(); - try - { - var modelCard = GetModelCard(modelCardId); - - using var scope = _serviceProvider.CreateScope(); - - InitializeConverterSettings(scope, modelCard); - - using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId); - - var progress = _operationProgressManager.CreateOperationProgressEventHandler( - Parent, - modelCard.ModelCardId.NotNull(), - cancellationItem.Token - ); - - var navisworksModelItems = await GetNavisworksModelItems(modelCard, progress); - - var sendResult = await ExecuteSendOperation( - scope, - modelCard, - navisworksModelItems, - progress, - cancellationItem.Token - ); - - await Commands.SetModelSendResult(modelCardId, sendResult.VersionId, sendResult.ConversionResults); - } - catch (OperationCanceledException) - { - // SWALLOW -> UI handles it immediately, so we do not need to handle anything for now! - // Idea for later -> when cancel called, create promise from UI to solve it later with this catch block. - // So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled - } - 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); - } - finally - { - // otherwise the id of the operation persists on the cancellation manager and triggers 'Operations cancelled because of document swap!' message to UI. - _cancellationManager.CancelOperation(modelCardId); - } + using var manager = _sendOperationManagerFactory.Create(); + await manager.Process(Commands, modelCardId, InitializeConverterSettings, GetNavisworksModelItems); } - private SenderModelCard GetModelCard(string modelCardId) => - _store.GetModelById(modelCardId) as SenderModelCard - ?? throw new InvalidOperationException("No publish model card was found."); - - private void InitializeConverterSettings(IServiceScope scope, SenderModelCard modelCard) => - scope - .ServiceProvider.GetRequiredService>() + private void InitializeConverterSettings(IServiceProvider serviceProvider, SenderModelCard modelCard) => + serviceProvider + .GetRequiredService>() .Initialize( _conversionSettingsFactory.Create( originMode: _toSpeckleSettingsManagerNavisworks.GetOriginMode(modelCard), @@ -159,7 +101,7 @@ public class NavisworksSendBinding : ISendBinding ) ); - private async Task> GetNavisworksModelItems( + private async Task> GetNavisworksModelItems( SenderModelCard modelCard, IProgress onOperationProgressed ) diff --git a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/DependencyInjection/NavisworksConnectorServiceRegistration.cs b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/DependencyInjection/NavisworksConnectorServiceRegistration.cs index f0e8aeda2..5e6114537 100644 --- a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/DependencyInjection/NavisworksConnectorServiceRegistration.cs +++ b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/DependencyInjection/NavisworksConnectorServiceRegistration.cs @@ -68,6 +68,7 @@ public static class NavisworksConnectorServiceRegistration // register filters serviceCollection.AddScoped(); serviceCollection.AddScoped(); + serviceCollection.AddScoped(); serviceCollection.AddScoped(); } } diff --git a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Operations/Send/Filters/NavisworksSavedSetsFilter.cs b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Operations/Send/Filters/NavisworksSavedSetsFilter.cs index abc5011ca..58911cb7c 100644 --- a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Operations/Send/Filters/NavisworksSavedSetsFilter.cs +++ b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Operations/Send/Filters/NavisworksSavedSetsFilter.cs @@ -2,7 +2,6 @@ using Speckle.Connectors.DUI.Exceptions; using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Connectors.DUI.Utils; -using Speckle.Converter.Navisworks.Constants; namespace Speckle.Connector.Navisworks.Operations.Send.Filters; @@ -85,12 +84,14 @@ public class NavisworksSavedSetsFilter : DiscriminatedObject, ISendFilterSelect { List savedSetRecords = []; - CollectSavedSets(NavisworksApp.ActiveDocument.SelectionSets.RootItem, savedSetRecords); + var root = NavisworksApp.ActiveDocument.SelectionSets.RootItem; + + CollectSavedSets(root, savedSetRecords); Items = savedSetRecords .Select(setRecord => { - string hierarchicalName = BuildHierarchicalName(setRecord); + string hierarchicalName = SavedItemHelpers.BuildHierarchicalName(setRecord, root); return new SendFilterSelectItem(setRecord.Guid.ToString(), hierarchicalName); }) .ToList(); @@ -103,7 +104,7 @@ public class NavisworksSavedSetsFilter : DiscriminatedObject, ISendFilterSelect return; } - foreach (NAV.SavedItem item in ((NAV.FolderItem)parentItem).Children) + foreach (NAV.SavedItem item in ((NAV.GroupItem)parentItem).Children) { if (item.IsGroup) { @@ -115,18 +116,4 @@ public class NavisworksSavedSetsFilter : DiscriminatedObject, ISendFilterSelect } } } - - private static string BuildHierarchicalName(NAV.SavedItem item) - { - var pathParts = new List { item.DisplayName }; - - var current = item.Parent; - while (current != null && current != NavisworksApp.ActiveDocument.SelectionSets.RootItem) - { - pathParts.Insert(0, current.DisplayName); - current = current.Parent; - } - - return string.Join(PathConstants.SET_SEPARATOR, pathParts); - } } diff --git a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Operations/Send/Filters/NavisworksSavedViewsFilter.cs b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Operations/Send/Filters/NavisworksSavedViewsFilter.cs new file mode 100644 index 000000000..3d494d35d --- /dev/null +++ b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Operations/Send/Filters/NavisworksSavedViewsFilter.cs @@ -0,0 +1,173 @@ +using Speckle.Connector.Navisworks.Services; +using Speckle.Connectors.DUI.Exceptions; +using Speckle.Connectors.DUI.Models.Card.SendFilter; +using Speckle.Connectors.DUI.Utils; + +namespace Speckle.Connector.Navisworks.Operations.Send.Filters; + +public class NavisworksSavedViewsFilter : DiscriminatedObject, ISendFilterSelect +{ + private readonly IElementSelectionService _selectionService; + + public NavisworksSavedViewsFilter(IElementSelectionService selectionService) + { + _selectionService = selectionService; + + Items = []; + SelectedItems = []; + + GetSavedViews(); + } + + public string Id { get; set; } = "navisworksSavedViews"; + + public string Name { get; set; } = "Saved Views"; + + public string Type { get; set; } = "Select"; + + public string? Summary { get; set; } + + public bool IsDefault { get; set; } + + public List SelectedObjectIds { get; set; } = []; + + public Dictionary? IdMap { get; set; } + + public bool IsMultiSelectable { get; set; } + + public List SelectedItems { get; set; } + + public List Items { get; set; } + + public List RefreshObjectIds() + { + List objectIds = []; + + if (SelectedItems.Count == 0) + { + return objectIds; + } + + var savedViews = NavisworksApp.ActiveDocument.SavedViewpoints; + + foreach (var savedViewItem in SelectedItems.Select(item => ResolveSavedView(item.Id))) + { + // Get the visible elements in the saved view. + objectIds.AddRange(ResolvedSavedViewObjects(savedViewItem)); + } + + return objectIds; + } + + private static NAV.SavedViewpoint ResolveSavedView(string savedViewReference) + { + if (Guid.TryParse(savedViewReference, out var guid)) + { + // Even though we may have already got a match, that could be to a generic Guid from earlier versions of Navisworks + if (savedViewReference != Guid.Empty.ToString()) + { + return (NAV.SavedViewpoint)NavisworksApp.ActiveDocument.SavedViewpoints.ResolveGuid(guid); + } + } + + var savedRef = new NAV.SavedItemReference("LcOpSavedViewsElement", savedViewReference); + + var resolvedReference = NavisworksApp.ActiveDocument.ResolveReference(savedRef) as NAV.SavedViewpoint; + + return resolvedReference + ?? throw new SpeckleSendFilterException($"Saved view with reference {savedViewReference} not found."); + } + + private IEnumerable ResolvedSavedViewObjects(NAV.SavedViewpoint savedView) + { + var objectIds = new List(); + + // THIS IS COMMENTED OUT AS IT IS LEGACY DEFENSIVE BEHAVIOUR - DISCUSSION REQUIRED + // if (!savedView.ContainsVisibilityOverrides) + // { + // // We check this again as the view settings may have changed in the saved card. + // // If the saved view does not contain visibility overrides, this is effectively everything in the model. + // // This will need to be the documented behaviour. + // throw new SpeckleSendFilterException( + // "Saved view does not contain visibility overrides. This would effectively publish everything in the model." + // ); + // } + + NavisworksApp.ActiveDocument.SavedViewpoints.CurrentSavedViewpoint = savedView; + var models = NavisworksApp.ActiveDocument.Models; + NavisworksApp.ActiveDocument.CurrentSelection.Clear(); + + foreach (var model in models) + { + var rootItem = model.RootItem; + + if (!_selectionService.IsVisible(rootItem)) + { + // If the root item is hidden, we skip it and its descendants. + continue; + } + + objectIds.AddRange( + rootItem.Descendants.Where(_selectionService.IsVisible).Select(_selectionService.GetModelItemPath).ToList() + ); + } + + return objectIds; + } + + /// + /// Since it is called from constructor, it is re-called whenever UI calls SendBinding.GetSendFilters() on SendFilter dialog. + /// Do not change the behavior/scope of this class on send binding unless make sure the behavior is same. Otherwise, we might not be able to update list of saved sets. + /// + private void GetSavedViews() + { + List savedViewRecords = []; + + var root = NavisworksApp.ActiveDocument.SavedViewpoints.RootItem; + + CollectSavedViews(root, savedViewRecords); + + Items = savedViewRecords + .Select(viewRecord => + { + var reference = NavisworksApp.ActiveDocument.SavedViewpoints.CreateReference(viewRecord); + + // If the guid is effectively empty, we can use the saved view's name as a fallback + var selectItemId = + viewRecord.Guid.ToString() == Guid.Empty.ToString() ? reference.SavedItemId : viewRecord.Guid.ToString(); + string hierarchicalName = SavedItemHelpers.BuildHierarchicalName(viewRecord, root); + + return new SendFilterSelectItem(selectItemId, hierarchicalName); + }) + .ToList(); + } + + private static void CollectSavedViews(NAV.SavedItem parentItem, List collectedSets) + { + if (!parentItem.IsGroup) + { + return; + } + + foreach (NAV.SavedItem item in ((NAV.GroupItem)parentItem).Children) + { + switch (item.IsGroup) + { + // THIS IS COMMENTED OUT AS IT IS LEGACY DEFENSIVE BEHAVIOUR - DISCUSSION REQUIRED + // case false when item is NAV.SavedViewpoint { ContainsVisibilityOverrides: false }: + // // If the saved view does not contain visibility overrides, this is effectively everything in the model. + // // This will need to be the documented behaviour. + // break; + case false: + collectedSets.Add((NAV.SavedViewpoint)item); + break; + default: // handles item.IsGroup == true + if (((NAV.GroupItem)item).Children.Count > 0) // Don't add empty groups + { + CollectSavedViews(item, collectedSets); + } + break; + } + } + } +} diff --git a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Operations/Send/Filters/SavedItemHelpers.cs b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Operations/Send/Filters/SavedItemHelpers.cs new file mode 100644 index 000000000..f04696f41 --- /dev/null +++ b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Operations/Send/Filters/SavedItemHelpers.cs @@ -0,0 +1,20 @@ +using Speckle.Converter.Navisworks.Constants; + +namespace Speckle.Connector.Navisworks.Operations.Send.Filters; + +public static class SavedItemHelpers +{ + internal static string BuildHierarchicalName(NAV.SavedItem item, NAV.FolderItem? root) + { + var pathParts = new List { item.DisplayName }; + + var current = item.Parent; + while (current != null && current != root) + { + pathParts.Insert(0, current.DisplayName); + current = current.Parent; + } + + return string.Join(PathConstants.SET_SEPARATOR, pathParts); + } +} diff --git a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Speckle.Connectors.NavisworksShared.projitems b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Speckle.Connectors.NavisworksShared.projitems index 0937aeec6..53aa9d3dd 100644 --- a/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Speckle.Connectors.NavisworksShared.projitems +++ b/Connectors/Navisworks/Speckle.Connectors.NavisworksShared/Speckle.Connectors.NavisworksShared.projitems @@ -20,6 +20,8 @@ + + diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared.Cef/CefSharpPanel.xaml.cs b/Connectors/Revit/Speckle.Connectors.RevitShared.Cef/CefSharpPanel.xaml.cs index b521f32e6..9de42e77b 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared.Cef/CefSharpPanel.xaml.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared.Cef/CefSharpPanel.xaml.cs @@ -15,7 +15,18 @@ public partial class CefSharpPanel : Page, Autodesk.Revit.UI.IDockablePaneProvid public void ExecuteScript(string script) { - Browser.Dispatcher.Invoke(() => Browser.ExecuteScriptAsync(script), DispatcherPriority.Background); + Browser.Dispatcher.Invoke( + () => + { + //avoid exceptions by checking if IBrowser is there + if (!Browser.IsBrowserInitialized || Browser.GetBrowser() is null) + { + return; + } + Browser.ExecuteScriptAsync(script); + }, + DispatcherPriority.Background + ); } public void SendProgress(string script) => ExecuteScript(script); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitReceiveBinding.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitReceiveBinding.cs index e9507eef9..edae45173 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitReceiveBinding.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitReceiveBinding.cs @@ -1,123 +1,59 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Speckle.Connectors.Common.Builders; using Speckle.Connectors.Common.Cancellation; -using Speckle.Connectors.Common.Operations; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; -using Speckle.Connectors.DUI.Logging; -using Speckle.Connectors.DUI.Models; -using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.Revit.Plugin; using Speckle.Converters.Common; -using Speckle.Converters.RevitShared.Helpers; using Speckle.Converters.RevitShared.Settings; -using Speckle.Sdk; namespace Speckle.Connectors.Revit.Bindings; -internal sealed class RevitReceiveBinding : IReceiveBinding +internal sealed class RevitReceiveBinding( + ICancellationManager cancellationManager, + IBrowserBridge parent, + ILogger logger, + IRevitConversionSettingsFactory revitConversionSettingsFactory, + IReceiveOperationManagerFactory receiveOperationManagerFactory +) : IReceiveBinding { public string Name => "receiveBinding"; - public IBrowserBridge Parent { get; } + public IBrowserBridge Parent { get; } = parent; + private IReceiveBindingUICommands Commands { get; } = new ReceiveBindingUICommands(parent); - private readonly IOperationProgressManager _operationProgressManager; - private readonly ILogger _logger; - private readonly ICancellationManager _cancellationManager; - private readonly DocumentModelStore _store; - private readonly IServiceProvider _serviceProvider; - private readonly IRevitConversionSettingsFactory _revitConversionSettingsFactory; - private readonly ISpeckleApplication _speckleApplication; - private readonly RevitToHostCacheSingleton _revitToHostCacheSingleton; - private ReceiveBindingUICommands Commands { get; } - - public RevitReceiveBinding( - DocumentModelStore store, - ICancellationManager cancellationManager, - IBrowserBridge parent, - IServiceProvider serviceProvider, - IOperationProgressManager operationProgressManager, - ILogger logger, - IRevitConversionSettingsFactory revitConversionSettingsFactory, - ISpeckleApplication speckleApplication, - RevitToHostCacheSingleton revitToHostCacheSingleton - ) - { - Parent = parent; - _store = store; - _serviceProvider = serviceProvider; - _operationProgressManager = operationProgressManager; - _logger = logger; - _revitConversionSettingsFactory = revitConversionSettingsFactory; - _speckleApplication = speckleApplication; - _cancellationManager = cancellationManager; - _revitToHostCacheSingleton = revitToHostCacheSingleton; - - Commands = new ReceiveBindingUICommands(parent); - } - - public void CancelReceive(string modelCardId) => _cancellationManager.CancelOperation(modelCardId); + public void CancelReceive(string modelCardId) => cancellationManager.CancelOperation(modelCardId); public async Task Receive(string modelCardId) { - try - { - // Get receiver card - if (_store.GetModelById(modelCardId) is not ReceiverModelCard modelCard) + using var manager = receiveOperationManagerFactory.Create(); + await manager.Process( + Commands, + modelCardId, + (sp) => { - // Handle as GLOBAL ERROR at BrowserBridge - throw new InvalidOperationException("No download model card was found."); + sp.GetRequiredService>() + .Initialize( + revitConversionSettingsFactory.Create( + DetailLevelType.Coarse, // TODO figure out + null, + false, + true, + false + ) + ); + }, + async (_, processor) => + { + try + { + return await processor(); + } + catch (SpeckleRevitTaskException ex) + { + await SpeckleRevitTaskException.ProcessException(modelCardId, ex, logger, Commands); + return null; + } } - - using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId); - - using var scope = _serviceProvider.CreateScope(); - scope - .ServiceProvider.GetRequiredService>() - .Initialize( - _revitConversionSettingsFactory.Create( - DetailLevelType.Coarse, // TODO figure out - null, - false, - true, - false - ) - ); - // Receive host objects - HostObjectBuilderResult conversionResults = await scope - .ServiceProvider.GetRequiredService() - .Execute( - modelCard.GetReceiveInfo(_speckleApplication.Slug), - _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationItem.Token), - cancellationItem.Token - ); - - modelCard.BakedObjectIds = conversionResults.BakedObjectIds.ToList(); - await Commands.SetModelReceiveResult( - modelCardId, - conversionResults.BakedObjectIds, - conversionResults.ConversionResults - ); - } - catch (OperationCanceledException) - { - // SWALLOW -> UI handles it immediately, so we do not need to handle anything for now! - // Idea for later -> when cancel called, create promise from UI to solve it later with this catch block. - // So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled - } - catch (SpeckleRevitTaskException ex) - { - await SpeckleRevitTaskException.ProcessException(modelCardId, ex, _logger, 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); - } - finally - { - // otherwise the id of the operation persists on the cancellation manager and triggers 'Operations cancelled because of document swap!' message to UI. - _cancellationManager.CancelOperation(modelCardId); - } + ); } } diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs index ee0e08c8b..3d7ab2af7 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitSendBinding.cs @@ -1,15 +1,11 @@ using Autodesk.Revit.DB; using Autodesk.Revit.DB.ExtensibleStorage; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; 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; -using Speckle.Connectors.DUI.Logging; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.DUI.Models.Card.SendFilter; @@ -32,17 +28,14 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding private readonly RevitContext _revitContext; private readonly DocumentModelStore _store; private readonly ICancellationManager _cancellationManager; - private readonly IServiceProvider _serviceProvider; private readonly ISendConversionCache _sendConversionCache; - private readonly IOperationProgressManager _operationProgressManager; private readonly ToSpeckleSettingsManager _toSpeckleSettingsManager; - private readonly ILogger _logger; private readonly ElementUnpacker _elementUnpacker; private readonly IRevitConversionSettingsFactory _revitConversionSettingsFactory; - private readonly ISpeckleApplication _speckleApplication; private readonly ITopLevelExceptionHandler _topLevelExceptionHandler; private readonly LinkedModelHandler _linkedModelHandler; private readonly IThreadContext _threadContext; + private readonly ISendOperationManagerFactory _sendOperationManagerFactory; /// /// 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: @@ -58,18 +51,15 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding DocumentModelStore store, ICancellationManager cancellationManager, IBrowserBridge bridge, - IServiceProvider serviceProvider, ISendConversionCache sendConversionCache, - IOperationProgressManager operationProgressManager, ToSpeckleSettingsManager toSpeckleSettingsManager, - ILogger logger, ElementUnpacker elementUnpacker, IRevitConversionSettingsFactory revitConversionSettingsFactory, - ISpeckleApplication speckleApplication, ITopLevelExceptionHandler topLevelExceptionHandler, LinkedModelHandler linkedModelHandler, IThreadContext threadContext, - IRevitTask revitTask + IRevitTask revitTask, + ISendOperationManagerFactory sendOperationManagerFactory ) : base("sendBinding", bridge) { @@ -77,17 +67,14 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding _revitContext = revitContext; _store = store; _cancellationManager = cancellationManager; - _serviceProvider = serviceProvider; _sendConversionCache = sendConversionCache; - _operationProgressManager = operationProgressManager; _toSpeckleSettingsManager = toSpeckleSettingsManager; - _logger = logger; _elementUnpacker = elementUnpacker; _revitConversionSettingsFactory = revitConversionSettingsFactory; - _speckleApplication = speckleApplication; _topLevelExceptionHandler = topLevelExceptionHandler; _linkedModelHandler = linkedModelHandler; _threadContext = threadContext; + _sendOperationManagerFactory = sendOperationManagerFactory; Commands = new SendBindingUICommands(bridge); // TODO expiry events @@ -123,69 +110,26 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding public async Task Send(string modelCardId) { - // Note: removed top level handling thing as it was confusing me - try - { - if (_store.GetModelById(modelCardId) is not SenderModelCard modelCard) + using var manager = _sendOperationManagerFactory.Create(); + + await manager.Process( + Commands, + modelCardId, + (sp, card) => { - // Handle as GLOBAL ERROR at BrowserBridge - throw new InvalidOperationException("No publish model card was found."); - } - - using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId); - - using var scope = _serviceProvider.CreateScope(); - scope - .ServiceProvider.GetRequiredService>() - .Initialize( - _revitConversionSettingsFactory.Create( - _toSpeckleSettingsManager.GetDetailLevelSetting(modelCard), - _toSpeckleSettingsManager.GetReferencePointSetting(modelCard), - _toSpeckleSettingsManager.GetSendParameterNullOrEmptyStringsSetting(modelCard), - _toSpeckleSettingsManager.GetLinkedModelsSetting(modelCard), - _toSpeckleSettingsManager.GetSendRebarsAsVolumetric(modelCard) - ) - ); - - var elementsByTransform = await RefreshElementsIdsOnSender(modelCard.NotNull()); - - if (elementsByTransform.Count == 0) - { - // Handle as CARD ERROR in this function - throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!"); - } - - var sendResult = await scope - .ServiceProvider.GetRequiredService>() - .Execute( - elementsByTransform, - modelCard.GetSendInfo(_speckleApplication.ApplicationAndVersion), - _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationItem.Token), - cancellationItem.Token - ); - - await Commands.SetModelSendResult(modelCardId, sendResult.VersionId, sendResult.ConversionResults); - } - catch (OperationCanceledException) - { - // SWALLOW -> UI handles it immediately, so we do not need to handle anything for now! - // Idea for later -> when cancel called, create promise from UI to solve it later with this catch block. - // So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled - } - catch (SpeckleRevitTaskException ex) - { - await SpeckleRevitTaskException.ProcessException(modelCardId, ex, _logger, 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); - } - finally - { - // otherwise the id of the operation persists on the cancellation manager and triggers 'Operations cancelled because of document swap!' message to UI. - _cancellationManager.CancelOperation(modelCardId); - } + sp.GetRequiredService>() + .Initialize( + _revitConversionSettingsFactory.Create( + _toSpeckleSettingsManager.GetDetailLevelSetting(card), + _toSpeckleSettingsManager.GetReferencePointSetting(card), + _toSpeckleSettingsManager.GetSendParameterNullOrEmptyStringsSetting(card), + _toSpeckleSettingsManager.GetLinkedModelsSetting(card), + _toSpeckleSettingsManager.GetSendRebarsAsVolumetric(card) + ) + ); + }, + async x => await RefreshElementsIdsOnSender(x.NotNull()) + ); } private async Task> RefreshElementsIdsOnSender(SenderModelCard modelCard) diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs index b2238c1cf..43c1b1f69 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Receive/RevitHostObjectBuilder.cs @@ -40,7 +40,8 @@ public sealed class RevitHostObjectBuilder( ITypedConverter< (Base atomicObject, IReadOnlyCollection matrix), DirectShape - > localToGlobalDirectShapeConverter + > localToGlobalDirectShapeConverter, + IReceiveConversionHandler conversionHandler ) : IHostObjectBuilder, IDisposable { public Task Build( @@ -234,11 +235,9 @@ public sealed class RevitHostObjectBuilder( foreach (LocalToGlobalMap localToGlobalMap in localToGlobalMaps) { - cancellationToken.ThrowIfCancellationRequested(); - try + var ex = conversionHandler.TryConvert(() => { - using var activity = activityFactory.Start("BakeObject"); - + cancellationToken.ThrowIfCancellationRequested(); // actual conversion happens here! var result = converter.Convert(localToGlobalMap.AtomicObject); onOperationProgressed.Report(new("Converting", (double)++count / localToGlobalMaps.Count)); @@ -269,11 +268,10 @@ public sealed class RevitHostObjectBuilder( { throw new ConversionException($"Failed to cast {result.GetType()} to direct shape definition wrapper."); } - } - catch (Exception ex) when (!ex.IsFatal()) + }); + if (ex is not null) { conversionResults.Add(new(Status.ERROR, localToGlobalMap.AtomicObject, null, null, ex)); - logger.LogError(ex, $"Failed to convert object of type {localToGlobalMap.AtomicObject.speckle_type}"); } } return (new(bakedObjectIds, conversionResults), postBakePaintTargets); diff --git a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/SpeckleRevitTaskException.cs b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/SpeckleRevitTaskException.cs index ecdc769f8..2a3b1703a 100644 --- a/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/SpeckleRevitTaskException.cs +++ b/Connectors/Revit/Speckle.Connectors.RevitShared/Plugin/SpeckleRevitTaskException.cs @@ -14,7 +14,7 @@ public class SpeckleRevitTaskException(Exception exception) : SpeckleException(" string modelCardId, SpeckleRevitTaskException ex, ILogger logger, - BasicConnectorBindingCommands commands + IReceiveBindingUICommands commands ) where T : IBinding { diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Dev/DeconstructSpeckleParam.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Dev/DeconstructSpeckleParam.cs index 21fc6dfcf..4b21b71a1 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Dev/DeconstructSpeckleParam.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Dev/DeconstructSpeckleParam.cs @@ -66,7 +66,13 @@ public class DeconstructSpeckleParam : GH_Component, IGH_VariableParameterCompon outputParams = new(); foreach (var key in propGoo.Value.Keys) { - outputParams.Add(CreateOutputParamByKeyValue(key, propGoo.Value[key].Value, GH_ParamAccess.item)); + ISpecklePropertyGoo value = propGoo.Value[key]; + object? outputValue = value is SpecklePropertyGoo prop + ? prop.Value + : value is SpecklePropertyGroupGoo propGroup + ? propGroup + : value; + outputParams.Add(CreateOutputParamByKeyValue(key, outputValue, GH_ParamAccess.item)); } break; default: diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/IGH_StructureExtensions.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/IGH_StructureExtensions.cs new file mode 100644 index 000000000..72bb1fbd4 --- /dev/null +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/IGH_StructureExtensions.cs @@ -0,0 +1,11 @@ +using Grasshopper.Kernel.Data; + +namespace Speckle.Connectors.GrasshopperShared.Components; + +public static class IGH_StructureExtensions +{ + public static bool HasInputCountGreaterThan(this IGH_Structure data, int maximumCount, bool skipNulls = false) + { + return data.AllData(skipNulls).Skip(maximumCount).Any(); + } +} diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Objects/CreateSpeckleProperties.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Objects/CreateSpeckleProperties.cs index 3f66268f0..32619dd18 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Objects/CreateSpeckleProperties.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Objects/CreateSpeckleProperties.cs @@ -40,7 +40,7 @@ public class CreateSpeckleProperties : VariableParameterComponentBase protected override void SolveInstance(IGH_DataAccess da) { - var properties = new Dictionary(); + var properties = new Dictionary(); // Validate for duplicate names var paramNames = Params.Input.Select(p => p.NickName).ToList(); @@ -71,13 +71,18 @@ public class CreateSpeckleProperties : VariableParameterComponentBase da.SetData(0, groupGoo); } - private SpecklePropertyGoo? ExtractPropertyValue(IGH_DataAccess da, int index, string paramName) + private ISpecklePropertyGoo? ExtractPropertyValue(IGH_DataAccess da, int index, string paramName) { object? value = null; da.GetData(index, ref value); - var propertyGoo = new SpecklePropertyGoo(); + // check for a group input first + if (value is SpecklePropertyGroupGoo group) + { + return group; + } + var propertyGoo = new SpecklePropertyGoo(); if (value == null) { return propertyGoo; // Return empty property @@ -87,7 +92,7 @@ public class CreateSpeckleProperties : VariableParameterComponentBase { AddRuntimeMessage( GH_RuntimeMessageLevel.Error, - $"Parameter '{paramName}' contains invalid data type. Only strings, numbers, and booleans are supported." + $"Parameter '{paramName}' contains invalid data type. Only strings, numbers, booleans, and other Speckle properties are supported." ); return null; } diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Objects/GetObjectProperties.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Objects/GetObjectProperties.cs index 70289483e..0e880281f 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Objects/GetObjectProperties.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Objects/GetObjectProperties.cs @@ -62,20 +62,36 @@ public class GetObjectProperties : GH_Component, IGH_VariableParameterComponent SpeckleObjectWrapperGoo objectWrapperGoo = new(); da.GetData(0, ref objectWrapperGoo); + // flatten object properties, if any + SpecklePropertyGroupGoo properties = objectWrapperGoo.Value.Properties; + if (properties.Value.Count == 0) + { + return; + } + + Dictionary flattenedProps = properties.Flatten(); + for (int i = 0; i < paths.Count; i++) { var name = paths[i]; - SpecklePropertyGoo objectProperty = FindProperty(objectWrapperGoo.Value.Properties, name); - da.SetData(i, objectProperty.Value); + if (FindProperty(flattenedProps, name) is SpecklePropertyGoo prop) + { + da.SetData(i, prop.Value); + } + else + { + da.SetData(i, null); + } } } } - private SpecklePropertyGoo FindProperty(SpecklePropertyGroupGoo root, string unifiedPath) + // attempts to find a property by concatenated key, or returns null if not + private SpecklePropertyGoo? FindProperty(Dictionary props, string unifiedPath) { - if (!root.Value.TryGetValue(unifiedPath, out SpecklePropertyGoo currentGoo)) + if (!props.TryGetValue(unifiedPath, out SpecklePropertyGoo currentGoo)) { - return new() { Path = unifiedPath, Value = "" }; + return null; } return currentGoo; diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Objects/PropertyGroupPathsSelector.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Objects/PropertyGroupPathsSelector.cs index 7d8e0c57a..6230b6c1d 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Objects/PropertyGroupPathsSelector.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Objects/PropertyGroupPathsSelector.cs @@ -29,7 +29,7 @@ public class PropertyGroupPathsSelector : ValueSet var objectPropertyGroups = VolatileData .AllData(true) .OfType() - .Select(goo => goo.Value.Properties.Value) + .Select(goo => goo.Value.Properties) .ToList(); #if RHINO8_OR_GREATER @@ -39,7 +39,7 @@ public class PropertyGroupPathsSelector : ValueSet var modelObjects = VolatileData .AllData(true) .OfType() - .Select(mo => new SpeckleObjectWrapperGoo(mo).Value.Properties.Value) + .Select(mo => new SpeckleObjectWrapperGoo(mo).Value.Properties) .ToList(); objectPropertyGroups.AddRange(modelObjects); } @@ -55,13 +55,18 @@ public class PropertyGroupPathsSelector : ValueSet m_data.AppendRange(paths.Select(s => new GH_String(s))); } - private static List GetPropertyPaths(List> objectPropertyGroups) + private static List GetPropertyPaths(List objectPropertyGroups) { var result = new HashSet(); - foreach (var dict in objectPropertyGroups) + foreach (SpecklePropertyGroupGoo propGroup in objectPropertyGroups) { + // flatten the props + Dictionary flattenedProps = propGroup.Flatten(); + result.AddRange( - dict.Keys.Where(k => !(k.EndsWith(".name") || k.EndsWith(".units") || k.EndsWith(".internalDefinitionName"))) + flattenedProps.Keys.Where(k => + !(k.EndsWith(".name") || k.EndsWith(".units") || k.EndsWith(".internalDefinitionName")) + ) ); } return result.ToList(); diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Operations/Receive/ReceiveAsyncComponent.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Operations/Receive/ReceiveAsyncComponent.cs index d4d713148..504378f4d 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Operations/Receive/ReceiveAsyncComponent.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Operations/Receive/ReceiveAsyncComponent.cs @@ -68,6 +68,16 @@ public class ReceiveAsyncComponent : GH_AsyncComponent protected override void SolveInstance(IGH_DataAccess da) { + MultipleResources = Params.Input[0].VolatileData.HasInputCountGreaterThan(1); + if (MultipleResources) + { + AddRuntimeMessage( + GH_RuntimeMessageLevel.Error, + "Only one model can be loaded at a time. To load to multiple models, please use different load components." + ); + return; + } + da.DisableGapLogic(); // We need to call this always in here to be able to react and set events :/ ParseInput(da); @@ -101,6 +111,8 @@ public class ReceiveAsyncComponent : GH_AsyncComponent } } + public bool MultipleResources { get; set; } + public override void AppendAdditionalMenuItems(ToolStripDropDown menu) { base.AppendAdditionalMenuItems(menu); @@ -561,14 +573,21 @@ public class ReceiveAsyncComponentAttributes : GH_ComponentAttributes return GH_ObjectResponse.Handled; } - if (((ReceiveAsyncComponent)Owner).AutoReceive) + // NOTE: why do we kill auto receive when clicking on the button? + // It's enabled via the context menu, I expect it to be disabled from the same place + // if (((ReceiveAsyncComponent)Owner).AutoReceive) + // { + // ((ReceiveAsyncComponent)Owner).AutoReceive = false; + // Owner.OnDisplayExpired(true); + // return GH_ObjectResponse.Handled; + // } + + // TODO: check if owner has null account/client, and call the reset thing SYNC + if ((Owner as ReceiveAsyncComponent)?.MultipleResources == true) { - ((ReceiveAsyncComponent)Owner).AutoReceive = false; - Owner.OnDisplayExpired(true); return GH_ObjectResponse.Handled; } - // TODO: check if owner has null account/client, and call the reset thing SYNC ((ReceiveAsyncComponent)Owner).CurrentComponentState = ComponentState.Ready; Owner.ExpireSolution(true); return GH_ObjectResponse.Handled; diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Operations/Receive/ReceiveComponent.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Operations/Receive/ReceiveComponent.cs index bf47ccfdf..9f197c89b 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Operations/Receive/ReceiveComponent.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Operations/Receive/ReceiveComponent.cs @@ -101,6 +101,15 @@ public class ReceiveComponent : SpeckleTaskCapableComponent? LastFetchedProjects { get; set; } - private ResourceCollection? LastFetchedModels { get; set; } - public GhContextMenuButton ProjectContextMenuButton { get; set; } public GhContextMenuButton ModelContextMenuButton { get; set; } - private ToolStripDropDown? ProjectDropDown { get; set; } - private ToolStripDropDown? ModelDropDown { get; set; } - public SendAsyncComponent() : base( "Publish", @@ -59,8 +52,8 @@ public class SendAsyncComponent : GH_AsyncComponent public IClient ApiClient { get; set; } public HostApp.SpeckleUrlModelResource? UrlModelResource { get; set; } public SpeckleCollectionWrapperGoo? RootCollectionWrapper { get; set; } - public SpeckleUrlModelResource? OutputParam { get; set; } + public bool HasMultipleInputs { get; set; } protected override void RegisterInputParams(GH_InputParamManager pManager) { @@ -136,6 +129,31 @@ public class SendAsyncComponent : GH_AsyncComponent protected override void SolveInstance(IGH_DataAccess da) { + var multipleResources = Params.Input[0].VolatileData.HasInputCountGreaterThan(1); + var multipleCollections = Params.Input[1].VolatileData.HasInputCountGreaterThan(1); + + HasMultipleInputs = multipleCollections || multipleResources; + + if (HasMultipleInputs) + { + var mCollErrText = + "Only one single collection supported. Please group your input collections into one single one before sending."; + var mLinksErrText = + "Only one single model can be published to from this node. To send to multiple models, please use different publish components."; + + if (multipleCollections) + { + AddRuntimeMessage(GH_RuntimeMessageLevel.Error, mCollErrText); + } + + if (multipleResources) + { + AddRuntimeMessage(GH_RuntimeMessageLevel.Error, mLinksErrText); + } + + return; + } + using var scope = PriorityLoader.CreateScopeForActiveDocument(); var accountService = scope.ServiceProvider.GetRequiredService(); @@ -342,7 +360,7 @@ public class SendComponentWorker : WorkerInstance { var sendComponent = (SendAsyncComponent)Parent; - if (sendComponent.JustPastedIn) + if (sendComponent.JustPastedIn || sendComponent.HasMultipleInputs) { done(); return; @@ -519,6 +537,11 @@ public class SendAsyncComponentAttributes : GH_ComponentAttributes { if (((RectangleF)ButtonBounds).Contains(e.CanvasLocation)) { + // Ignore button presses on a component with invalid inputs to prevent multiple sends + if ((Owner as SendAsyncComponent)?.HasMultipleInputs == true) + { + return GH_ObjectResponse.Handled; + } if (((SendAsyncComponent)Owner).AutoSend) { ((SendAsyncComponent)Owner).AutoSend = false; diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Operations/Send/SendComponent.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Operations/Send/SendComponent.cs index dfffb49e2..beaacca77 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Operations/Send/SendComponent.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Operations/Send/SendComponent.cs @@ -129,6 +129,31 @@ public class SendComponent : SpeckleTaskCapableComponent innerE.Message)) ); + da.AbortComponentSolution(); } catch (Exception e) when (!e.IsFatal()) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.Message); + da.AbortComponentSolution(); } } diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Operations/Wizard/SpeckleOperationWizard.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Operations/Wizard/SpeckleOperationWizard.cs index 907f0f321..d61fbb948 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Operations/Wizard/SpeckleOperationWizard.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Components/Operations/Wizard/SpeckleOperationWizard.cs @@ -197,7 +197,7 @@ public class SpeckleOperationWizard { return; } - IClient client = _clientFactory.Create(SelectedAccount); + using IClient client = _clientFactory.Create(SelectedAccount); var workspace = client.Workspace.Get(workspaceId).Result; SelectedWorkspace = workspace; WorkspaceMenuHandler.RedrawMenuButton(SelectedWorkspace); @@ -209,7 +209,7 @@ public class SpeckleOperationWizard { return; } - IClient client = _clientFactory.Create(SelectedAccount); + using IClient client = _clientFactory.Create(SelectedAccount); var project = client.Project.Get(projectId).Result; SelectedProject = project; ProjectMenuHandler.RedrawMenuButton(SelectedProject); @@ -222,7 +222,7 @@ public class SpeckleOperationWizard return; } - IClient client = _clientFactory.Create(SelectedAccount); + using IClient client = _clientFactory.Create(SelectedAccount); var model = client.Model.Get(modelId, SelectedProject.id).Result; SelectedModel = model; ModelMenuHandler.RedrawMenuButton(SelectedModel); @@ -235,7 +235,7 @@ public class SpeckleOperationWizard return; } - IClient client = _clientFactory.Create(SelectedAccount); + using IClient client = _clientFactory.Create(SelectedAccount); var version = client.Version.Get(versionId, SelectedProject.id).Result; SelectedVersion = version; VersionMenuHandler?.RedrawMenuButton(SelectedVersion); @@ -251,7 +251,7 @@ public class SpeckleOperationWizard return new ResourceCollection(); } - IClient client = _clientFactory.Create(SelectedAccount); + using IClient client = _clientFactory.Create(SelectedAccount); var workspaces = await client.ActiveUser.GetWorkspaces(10, null, new UserWorkspacesFilter(searchText)); WorkspaceMenuHandler.Workspaces = workspaces; return workspaces; @@ -267,7 +267,7 @@ public class SpeckleOperationWizard return new ResourceCollection(); } - IClient client = _clientFactory.Create(SelectedAccount); + using IClient client = _clientFactory.Create(SelectedAccount); var workspaces = client.ActiveUser.GetWorkspaces(10, null, new UserWorkspacesFilter(searchText)).Result; WorkspaceMenuHandler.Workspaces = workspaces; return workspaces; @@ -283,7 +283,7 @@ public class SpeckleOperationWizard return new ResourceCollection(); } - IClient client = _clientFactory.Create(SelectedAccount); + using IClient client = _clientFactory.Create(SelectedAccount); var workspaceId = SelectedWorkspace?.id ?? null; var projects = await client.ActiveUser.GetProjectsWithPermissions( 10, @@ -309,7 +309,7 @@ public class SpeckleOperationWizard return new ResourceCollection(); } - IClient client = _clientFactory.Create(SelectedAccount); + using IClient client = _clientFactory.Create(SelectedAccount); var workspaceId = SelectedWorkspace?.id ?? null; var projects = client .ActiveUser.GetProjectsWithPermissions( @@ -337,7 +337,7 @@ public class SpeckleOperationWizard return new ResourceCollection(); } - IClient client = _clientFactory.Create(SelectedAccount); + using IClient client = _clientFactory.Create(SelectedAccount); var projectWithModels = await client .Project.GetWithModels(SelectedProject.id, 10, modelsFilter: new ProjectModelsFilter(search: searchText)) .ConfigureAwait(true); @@ -373,7 +373,7 @@ public class SpeckleOperationWizard return new ResourceCollection(); } - IClient client = _clientFactory.Create(SelectedAccount); + using IClient client = _clientFactory.Create(SelectedAccount); var newVersionsResult = await client .Model.GetWithVersions(SelectedModel.id, SelectedProject.id, versionCount) .ConfigureAwait(true); @@ -395,7 +395,7 @@ public class SpeckleOperationWizard return new ResourceCollection(); } - IClient client = _clientFactory.Create(SelectedAccount); + using IClient client = _clientFactory.Create(SelectedAccount); var newVersionsResult = client.Model.GetWithVersions(SelectedModel.id, SelectedProject.id, versionCount).Result; if (VersionMenuHandler != null) { @@ -411,7 +411,7 @@ public class SpeckleOperationWizard { return; } - IClient client = _clientFactory.Create(SelectedAccount); + using IClient client = _clientFactory.Create(SelectedAccount); var activeWorkspace = client.ActiveUser.GetActiveWorkspace().Result; Workspace? selectedWorkspace = SelectedWorkspace diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/HostApp/Helpers.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/HostApp/Helpers.cs index 361811474..0914ec555 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/HostApp/Helpers.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/HostApp/Helpers.cs @@ -124,6 +124,8 @@ public static class GrasshopperHelpers return el.ToNurbsCurve(); case Sphere sp: return sp.ToBrep(); + case Box box: + return box.ToBrep(); } throw new SpeckleException("Failed to cast IGH_GeometricGoo to geometry base"); diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Operations/Send/GrasshopperSendOperation.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Operations/Send/GrasshopperSendOperation.cs index 270b2139f..67046e58d 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Operations/Send/GrasshopperSendOperation.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Operations/Send/GrasshopperSendOperation.cs @@ -110,6 +110,7 @@ public class GrasshopperRootObjectBuilder() : IRootObjectBuilder wrappers, string appId) { Dictionary props = new(); + wrappers.First().Properties.CastTo>(ref props); return new() diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/ISpeckleGoo.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/ISpeckleGoo.cs deleted file mode 100644 index ddf9d6d94..000000000 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/ISpeckleGoo.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Speckle.Connectors.GrasshopperShared.Parameters; - -internal interface ISpeckleGoo { } diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/Interfaces.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/Interfaces.cs new file mode 100644 index 000000000..33786673a --- /dev/null +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/Interfaces.cs @@ -0,0 +1,8 @@ +namespace Speckle.Connectors.GrasshopperShared.Parameters; + +[System.Diagnostics.CodeAnalysis.SuppressMessage( + "Design", + "CA1040:Avoid empty interfaces", + Justification = "Needed to identify acceptable values of properties without multiple inheritance" +)] +public interface ISpecklePropertyGoo { } diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleCollectionWrapper.ModelObjects.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleCollectionWrapper.ModelObjects.cs index a7c597ed5..7d85873ef 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleCollectionWrapper.ModelObjects.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleCollectionWrapper.ModelObjects.cs @@ -7,7 +7,7 @@ using Speckle.Sdk.Models.Collections; namespace Speckle.Connectors.GrasshopperShared.Parameters; -public partial class SpeckleCollectionWrapperGoo : GH_Goo, ISpeckleGoo //, IGH_PreviewData // can be made previewable later +public partial class SpeckleCollectionWrapperGoo : GH_Goo //, IGH_PreviewData // can be made previewable later { private bool CastToModelLayer(ref T target) { diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleCollectionWrapper.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleCollectionWrapper.cs index 6b3a9fde1..3d07722d8 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleCollectionWrapper.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleCollectionWrapper.cs @@ -222,7 +222,7 @@ public class SpeckleCollectionWrapper : SpeckleWrapper } } -public partial class SpeckleCollectionWrapperGoo : GH_Goo, ISpeckleGoo //, IGH_PreviewData // can be made previewable later +public partial class SpeckleCollectionWrapperGoo : GH_Goo //, IGH_PreviewData // can be made previewable later { public override IGH_Goo Duplicate() => new SpeckleCollectionWrapperGoo(Value.DeepCopy()); diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleMaterialWrapper.ModelObjects.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleMaterialWrapper.ModelObjects.cs index 411e1c43a..d283fa820 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleMaterialWrapper.ModelObjects.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleMaterialWrapper.ModelObjects.cs @@ -6,6 +6,7 @@ using Rhino; using Rhino.DocObjects; using Rhino.Render; using Speckle.Sdk; +using SpeckleRenderMaterial = Speckle.Objects.Other.RenderMaterial; namespace Speckle.Connectors.GrasshopperShared.Parameters; @@ -13,7 +14,7 @@ namespace Speckle.Connectors.GrasshopperShared.Parameters; /// The Speckle Property Group Goo is a flat dictionary of (speckle property path, speckle property). /// The speckle property path is the concatenated string of all original flattened keys with the property delimiter /// -public partial class SpeckleMaterialWrapperGoo : GH_Goo, ISpeckleGoo +public partial class SpeckleMaterialWrapperGoo : GH_Goo { private bool CastFromModelRenderMaterial(object source) { @@ -90,5 +91,40 @@ public partial class SpeckleMaterialWrapperGoo : GH_Goo, return false; } + + private SpeckleRenderMaterial ToSpeckleRenderMaterial(Rhino.Render.RenderMaterial mat) + { + Rhino.DocObjects.PhysicallyBasedMaterial pbRenderMaterial = mat.ConvertToPhysicallyBased( + RenderTexture.TextureGeneration.Allow + ); + + // get opacity + // POC: pbr will return opacity = 0 for these because they are not pbr materials, they are transparent materials with IOR. Currently hardcoding 0.2 value in lieu of proper type support in rhino. + double opacity = (mat.SmellsLikeGem || mat.SmellsLikeGlass) ? 0.2 : pbRenderMaterial.Opacity; + + string renderMaterialName = mat.Name ?? "default"; // default rhino material has no name + Color diffuse = pbRenderMaterial.BaseColor.AsSystemColor(); + Color emissive = mat.TypeName.Equals("Emission") + ? pbRenderMaterial.Material.EmissionColor + : pbRenderMaterial.Emission.AsSystemColor(); // pbRenderMaterial.emission gives wrong color for emission materials, and material.emissioncolor gives the wrong value for most others *shrug* + + SpeckleRenderMaterial speckleRenderMaterial = + new() + { + name = renderMaterialName, + opacity = opacity, + metalness = pbRenderMaterial.Metallic, + roughness = pbRenderMaterial.Roughness, + diffuse = diffuse.ToArgb(), + emissive = emissive.ToArgb(), + applicationId = mat.Id.ToString(), + ["typeName"] = mat.TypeName, + ["ior"] = pbRenderMaterial.Material.IndexOfRefraction, + ["shine"] = pbRenderMaterial.Material.Shine, + }; + + return speckleRenderMaterial; + } } + #endif diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleMaterialWrapper.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleMaterialWrapper.cs index 4626395f1..ed6be947f 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleMaterialWrapper.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleMaterialWrapper.cs @@ -2,7 +2,6 @@ using Grasshopper.Kernel; using Grasshopper.Kernel.Types; using Rhino; using Rhino.DocObjects; -using Rhino.Render; using Speckle.Connectors.GrasshopperShared.Components; using Speckle.Connectors.GrasshopperShared.HostApp; using Speckle.Connectors.GrasshopperShared.Properties; @@ -61,7 +60,7 @@ public class SpeckleMaterialWrapper : SpeckleWrapper } } -public partial class SpeckleMaterialWrapperGoo : GH_Goo, ISpeckleGoo +public partial class SpeckleMaterialWrapperGoo : GH_Goo { public override IGH_Goo Duplicate() => throw new NotImplementedException(); @@ -161,40 +160,6 @@ public partial class SpeckleMaterialWrapperGoo : GH_Goo, return speckleRenderMaterial; } - private SpeckleRenderMaterial ToSpeckleRenderMaterial(Rhino.Render.RenderMaterial mat) - { - Rhino.DocObjects.PhysicallyBasedMaterial pbRenderMaterial = mat.ConvertToPhysicallyBased( - RenderTexture.TextureGeneration.Allow - ); - - // get opacity - // POC: pbr will return opacity = 0 for these because they are not pbr materials, they are transparent materials with IOR. Currently hardcoding 0.2 value in lieu of proper type support in rhino. - double opacity = (mat.SmellsLikeGem || mat.SmellsLikeGlass) ? 0.2 : pbRenderMaterial.Opacity; - - string renderMaterialName = mat.Name ?? "default"; // default rhino material has no name - Color diffuse = pbRenderMaterial.BaseColor.AsSystemColor(); - Color emissive = mat.TypeName.Equals("Emission") - ? pbRenderMaterial.Material.EmissionColor - : pbRenderMaterial.Emission.AsSystemColor(); // pbRenderMaterial.emission gives wrong color for emission materials, and material.emissioncolor gives the wrong value for most others *shrug* - - SpeckleRenderMaterial speckleRenderMaterial = - new() - { - name = renderMaterialName, - opacity = opacity, - metalness = pbRenderMaterial.Metallic, - roughness = pbRenderMaterial.Roughness, - diffuse = diffuse.ToArgb(), - emissive = emissive.ToArgb(), - applicationId = mat.Id.ToString(), - ["typeName"] = mat.TypeName, - ["ior"] = pbRenderMaterial.Material.IndexOfRefraction, - ["shine"] = pbRenderMaterial.Material.Shine, - }; - - return speckleRenderMaterial; - } - private SpeckleRenderMaterial ToSpeckleRenderMaterial(Material mat) { SpeckleRenderMaterial speckleRenderMaterial = diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleObjectWrapper.ModelObjects.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleObjectWrapper.ModelObjects.cs index d8df49929..4f5898841 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleObjectWrapper.ModelObjects.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleObjectWrapper.ModelObjects.cs @@ -11,7 +11,7 @@ using Grasshopper.Rhinoceros.Render; namespace Speckle.Connectors.GrasshopperShared.Parameters; -public partial class SpeckleObjectWrapperGoo : GH_Goo, IGH_PreviewData, ISpeckleGoo +public partial class SpeckleObjectWrapperGoo : GH_Goo, IGH_PreviewData { public SpeckleObjectWrapperGoo(ModelObject mo) { @@ -114,10 +114,8 @@ public partial class SpeckleObjectWrapperGoo : GH_Goo, IGH } } - foreach (var kvp in Value.Properties.Value) - { - atts.SetUserString(kvp.Key, kvp.Value.Value?.ToString() ?? ""); - } + // add props + Value.Properties.AssignToObjectAttributes(atts); target = (T)(object)atts; return true; @@ -165,7 +163,6 @@ public partial class SpeckleObjectWrapperGoo : GH_Goo, IGH propertyGroup.CastFrom(modelObject.UserText); // get the object layer - SpeckleCollectionWrapperGoo collWrapperGoo = new(); SpeckleCollectionWrapper? collWrapper = collWrapperGoo.CastFrom(modelObject.Layer) ? collWrapperGoo.Value @@ -175,9 +172,9 @@ public partial class SpeckleObjectWrapperGoo : GH_Goo, IGH modelConverted.applicationId = modelObject.Id?.ToString(); modelConverted[Constants.NAME_PROP] = modelObject.Name.ToString(); Dictionary propertyDict = new(); - foreach (var entry in propertyGroup.Value) + foreach (var entry in modelObject.UserText) { - propertyDict.Add(entry.Key, entry.Value.Value); + propertyDict.Add(entry.Key, entry.Value); } modelConverted[Constants.PROPERTIES_PROP] = propertyDict; diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleObjectWrapper.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleObjectWrapper.cs index 8ebb17736..3bed3b033 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleObjectWrapper.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleObjectWrapper.cs @@ -172,10 +172,8 @@ public class SpeckleObjectWrapper : SpeckleWrapper } } - foreach (var kvp in Properties.Value) - { - att.SetUserString(kvp.Key, kvp.Value.Value?.ToString() ?? ""); - } + // add props + Properties.AssignToObjectAttributes(att); // add to doc Guid guid = doc.Objects.Add(GeometryBase, att); @@ -202,10 +200,12 @@ public class SpeckleObjectWrapper : SpeckleWrapper return false; } + /* if (!Properties.Equals(objWrapper.Properties)) { return false; } + */ return true; } @@ -226,7 +226,7 @@ public class SpeckleObjectWrapper : SpeckleWrapper }; } -public partial class SpeckleObjectWrapperGoo : GH_Goo, IGH_PreviewData, ISpeckleGoo +public partial class SpeckleObjectWrapperGoo : GH_Goo, IGH_PreviewData { public override IGH_Goo Duplicate() { diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpecklePropertyGoo.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpecklePropertyGoo.cs index ca4c1ff97..b811272c4 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpecklePropertyGoo.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpecklePropertyGoo.cs @@ -3,7 +3,7 @@ using Grasshopper.Kernel.Types; namespace Speckle.Connectors.GrasshopperShared.Parameters; -public class SpecklePropertyGoo : GH_Goo, ISpeckleGoo +public class SpecklePropertyGoo : GH_Goo, ISpecklePropertyGoo { public override IGH_Goo Duplicate() => throw new NotImplementedException(); diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpecklePropertyGroupGoo.ModelObjects.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpecklePropertyGroupGoo.ModelObjects.cs index 5bfbde313..c015d04ea 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpecklePropertyGroupGoo.ModelObjects.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpecklePropertyGroupGoo.ModelObjects.cs @@ -9,10 +9,10 @@ using Rhino.DocObjects; namespace Speckle.Connectors.GrasshopperShared.Parameters; /// -/// The Speckle Property Group Goo is a flat dictionary of (speckle property path, speckle property). -/// The speckle property path is the concatenated string of all original flattened keys with the property delimiter +/// The Speckle Property Group Goo is a nested dictionary of (key, speckle property or property group). +/// The method will use the property delimiter on the keys to flatten the property group into properties. /// -public partial class SpecklePropertyGroupGoo : GH_Goo>, ISpeckleGoo +public partial class SpecklePropertyGroupGoo : GH_Goo>, ISpecklePropertyGoo { private bool CastFromModelObject(object source) { @@ -22,7 +22,7 @@ public partial class SpecklePropertyGroupGoo : GH_Goo dictionary = new(); + Dictionary dictionary = new(); foreach (KeyValuePair entry in userText) { string key = entry.Key; @@ -45,14 +45,10 @@ public partial class SpecklePropertyGroupGoo : GH_Goo -/// The Speckle Property Group Goo is a flat dictionary of (speckle property path, speckle property). -/// The speckle property path is the concatenated string of all original flattened keys with the property delimiter +/// The Speckle Property Group Goo is a dictionary of (key, speckle property or property group). +/// Flattened property group keys are the concatenated strings of all nested keys with the property delimiter /// -public partial class SpecklePropertyGroupGoo : GH_Goo>, ISpeckleGoo +public partial class SpecklePropertyGroupGoo : GH_Goo>, ISpecklePropertyGoo { public override IGH_Goo Duplicate() => throw new NotImplementedException(); @@ -25,7 +26,7 @@ public partial class SpecklePropertyGroupGoo : GH_Goo value) + public SpecklePropertyGroupGoo(Dictionary value) { Value = value; } @@ -44,14 +45,7 @@ public partial class SpecklePropertyGroupGoo : GH_Goo properties: - Dictionary flattenedProperties = new(); - FlattenDictionary(properties, flattenedProperties, ""); - Dictionary speckleProperties = new(); - foreach (var kvp in flattenedProperties) - { - speckleProperties.Add(kvp.Key, new() { Value = kvp.Value }); - } - Value = speckleProperties; + Value = WrapDictionary(properties); return true; } @@ -68,11 +62,7 @@ public partial class SpecklePropertyGroupGoo : GH_Goo)) { - Dictionary dictionary = new(); - foreach (var entry in Value) - { - dictionary.Add(entry.Key, entry.Value.Value); - } + Dictionary dictionary = Unwrap(); target = (T)(object)dictionary; return true; } @@ -85,53 +75,104 @@ public partial class SpecklePropertyGroupGoo : GH_Goo(ref T _) => false; #endif - // Flattens a dictionary that may contain more dictionaries of the same type - private void FlattenDictionary( - Dictionary dict, - Dictionary flattenedDict, + /// + /// Adds this property group to the input object attributes + /// + /// + public void AssignToObjectAttributes(ObjectAttributes atts) + { + Dictionary flattenedProps = Flatten(); + foreach (var kvp in flattenedProps) + { + atts.SetUserString(kvp.Key, kvp.Value.Value?.ToString() ?? ""); + } + } + + /// + /// Flattens the value into a dictionary with concatenated keys + /// + /// + public Dictionary Flatten() + { + Dictionary flattenedProps = new(); + FlattenWorker(Value, flattenedProps); + return flattenedProps; + } + + private void FlattenWorker( + Dictionary props, + Dictionary flattenedProps, string keyPrefix = "" ) { - foreach (var kvp in dict) + foreach (var kvp in props) { string newKey = string.IsNullOrEmpty(keyPrefix) ? kvp.Key : $"{keyPrefix}{Constants.PROPERTY_PATH_DELIMITER}{kvp.Key}"; - if (kvp.Value is Dictionary childDict) + switch (kvp.Value) { - FlattenDictionary(childDict, flattenedDict, newKey); - } - else - { - flattenedDict.Add(newKey, kvp.Value ?? ""); + case SpecklePropertyGroupGoo childProps: + FlattenWorker(childProps.Value, flattenedProps, newKey); + break; + case SpecklePropertyGoo prop: + flattenedProps.Add(newKey, prop); + break; } } } - public override bool Equals(object obj) + private Dictionary WrapDictionary(Dictionary dict) { - if (obj is not SpecklePropertyGroupGoo propertyGroupGoo || Value.Count != propertyGroupGoo.Value.Count) - { - return false; - } + Dictionary wrappedDict = new(); - foreach (var entry in Value) + foreach (var kvp in dict) { - if (propertyGroupGoo.Value.TryGetValue(entry.Key, out SpecklePropertyGoo compareProp)) + ISpecklePropertyGoo? val; + if (kvp.Value is Dictionary childDict) { - if (entry.Value.Value != compareProp.Value) - { - return false; - } + SpecklePropertyGroupGoo childPropertyGroup = new(); + childPropertyGroup.CastFrom(childDict); + val = childPropertyGroup; } else { - return false; + SpecklePropertyGoo entry = new(); + entry.CastFrom(kvp.Value); + val = entry; } + + wrappedDict.Add(kvp.Key, val); } - return true; + return wrappedDict; + } + + /// + /// Unwraps the value into a Dictionary of equivalent structure + /// + /// + public Dictionary Unwrap() + { + Dictionary dict = UnwrapWorker(Value); + return dict; + } + + private Dictionary UnwrapWorker(Dictionary properties) + { + Dictionary dict = new(); + foreach (var kvp in properties) + { + object? val = kvp.Value is SpecklePropertyGroupGoo propertyGroup + ? UnwrapWorker(propertyGroup.Value) + : kvp.Value is SpecklePropertyGoo property + ? property.Value + : null; + dict.Add(kvp.Key, val); + } + + return dict; } public override int GetHashCode() => base.GetHashCode(); diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleVariableParam.cs b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleVariableParam.cs index 04a58c28b..8e3f4717d 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleVariableParam.cs +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Parameters/SpeckleVariableParam.cs @@ -112,6 +112,12 @@ public class SpeckleVariableParam : Param_GenericObject // Tell the parent component its layout needs to be recalculated Attributes.Parent?.ExpireLayout(); + + // Expire solution when name changes to refresh downstream components + if (AlwaysInheritNames) + { + ExpireSolution(true); + } } finally { @@ -167,6 +173,9 @@ public class SpeckleVariableParam : Param_GenericObject if (AlwaysInheritNames && !_isUpdatingName) // Double-check in case it changed { TryInheritName(); + + // downstream components to be refreshed when source names change + OnPingDocument()?.ScheduleSolution(5, _ => ExpireSolution(true)); } }); } diff --git a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Speckle.Connectors.GrasshopperShared.projitems b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Speckle.Connectors.GrasshopperShared.projitems index 6ab2b4b05..cf2453112 100644 --- a/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Speckle.Connectors.GrasshopperShared.projitems +++ b/Connectors/Rhino/Speckle.Connectors.GrasshopperShared/Speckle.Connectors.GrasshopperShared.projitems @@ -16,6 +16,7 @@ + @@ -53,6 +54,7 @@ + @@ -61,7 +63,6 @@ - diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoReceiveBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoReceiveBinding.cs index bbb1d5145..66aed2cea 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoReceiveBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoReceiveBinding.cs @@ -1,111 +1,53 @@ using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Rhino; -using Speckle.Connectors.Common.Builders; using Speckle.Connectors.Common.Cancellation; -using Speckle.Connectors.Common.Operations; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; -using Speckle.Connectors.DUI.Logging; -using Speckle.Connectors.DUI.Models; -using Speckle.Connectors.DUI.Models.Card; using Speckle.Converters.Common; using Speckle.Converters.Rhino; -using Speckle.Sdk; namespace Speckle.Connectors.Rhino.Bindings; -public class RhinoReceiveBinding : IReceiveBinding +public class RhinoReceiveBinding( + ICancellationManager cancellationManager, + IBrowserBridge parent, + IRhinoConversionSettingsFactory rhinoConversionSettingsFactory, + IReceiveOperationManagerFactory receiveOperationManagerFactory +) : IReceiveBinding { public string Name => "receiveBinding"; - public IBrowserBridge Parent { get; } + public IBrowserBridge Parent { get; } = parent; - private readonly ICancellationManager _cancellationManager; - private readonly DocumentModelStore _store; - private readonly IServiceProvider _serviceProvider; - private readonly IOperationProgressManager _operationProgressManager; - private readonly ILogger _logger; - private readonly IRhinoConversionSettingsFactory _rhinoConversionSettingsFactory; - private readonly ISpeckleApplication _speckleApplication; - private ReceiveBindingUICommands Commands { get; } + private ReceiveBindingUICommands Commands { get; } = new(parent); - public RhinoReceiveBinding( - DocumentModelStore store, - ICancellationManager cancellationManager, - IBrowserBridge parent, - IOperationProgressManager operationProgressManager, - ILogger logger, - IRhinoConversionSettingsFactory rhinoConversionSettingsFactory, - IServiceProvider serviceProvider, - ISpeckleApplication speckleApplication - ) - { - Parent = parent; - _store = store; - _operationProgressManager = operationProgressManager; - _logger = logger; - _rhinoConversionSettingsFactory = rhinoConversionSettingsFactory; - _serviceProvider = serviceProvider; - _speckleApplication = speckleApplication; - _cancellationManager = cancellationManager; - Commands = new ReceiveBindingUICommands(parent); - } - - public void CancelReceive(string modelCardId) => _cancellationManager.CancelOperation(modelCardId); + public void CancelReceive(string modelCardId) => cancellationManager.CancelOperation(modelCardId); public async Task Receive(string modelCardId) { - using var scope = _serviceProvider.CreateScope(); - scope - .ServiceProvider.GetRequiredService>() - .Initialize(_rhinoConversionSettingsFactory.Create(RhinoDoc.ActiveDoc)); - - uint undoRecord = 0; - try - { - // Get receiver card - if (_store.GetModelById(modelCardId) is not ReceiverModelCard modelCard) + using var manager = receiveOperationManagerFactory.Create(); + await manager.Process( + Commands, + modelCardId, + (sp) => { - // Handle as GLOBAL ERROR at BrowserBridge - throw new InvalidOperationException("No download model card was found."); + sp.GetRequiredService>() + .Initialize(rhinoConversionSettingsFactory.Create(RhinoDoc.ActiveDoc)); + }, + async (modelName, processor) => + { + uint undoRecord = 0; + try + { + undoRecord = RhinoDoc.ActiveDoc.BeginUndoRecord($"Receive Speckle model {modelName}"); + return await processor(); + } + finally + { + RhinoDoc.ActiveDoc.EndUndoRecord(undoRecord); + } } - - using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId); - - undoRecord = RhinoDoc.ActiveDoc.BeginUndoRecord($"Receive Speckle model {modelCard.ModelName}"); - // Receive host objects - HostObjectBuilderResult conversionResults = await scope - .ServiceProvider.GetRequiredService() - .Execute( - modelCard.GetReceiveInfo(_speckleApplication.Slug), - _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationItem.Token), - cancellationItem.Token - ); - - modelCard.BakedObjectIds = conversionResults.BakedObjectIds.ToList(); - await Commands.SetModelReceiveResult( - modelCardId, - conversionResults.BakedObjectIds, - conversionResults.ConversionResults - ); - } - catch (OperationCanceledException) - { - // SWALLOW -> UI handles it immediately, so we do not need to handle anything for now! - // Idea for later -> when cancel called, create promise from UI to solve it later with this catch block. - // So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled - return; - } - 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); - } - finally - { - RhinoDoc.ActiveDoc.EndUndoRecord(undoRecord); - } + ); } - public void CancelSend(string modelCardId) => _cancellationManager.CancelOperation(modelCardId); + public void CancelSend(string modelCardId) => cancellationManager.CancelOperation(modelCardId); } diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs index dc0eb91a7..cd5c332f3 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Bindings/RhinoSendBinding.cs @@ -7,11 +7,8 @@ using Rhino.DocObjects; using Rhino.DocObjects.Tables; using Speckle.Connectors.Common.Caching; using Speckle.Connectors.Common.Cancellation; -using Speckle.Connectors.Common.Operations; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; -using Speckle.Connectors.DUI.Exceptions; -using Speckle.Connectors.DUI.Logging; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.DUI.Models.Card.SendFilter; @@ -19,9 +16,7 @@ using Speckle.Connectors.DUI.Settings; using Speckle.Connectors.Rhino.Operations.Send.Filters; using Speckle.Converters.Common; using Speckle.Converters.Rhino; -using Speckle.Sdk; using Speckle.Sdk.Common; -using Speckle.Sdk.Logging; namespace Speckle.Connectors.Rhino.Bindings; @@ -32,16 +27,13 @@ public sealed class RhinoSendBinding : ISendBinding public IBrowserBridge Parent { get; } private readonly DocumentModelStore _store; - private readonly IServiceProvider _serviceProvider; private readonly ICancellationManager _cancellationManager; private readonly ISendConversionCache _sendConversionCache; - private readonly IOperationProgressManager _operationProgressManager; private readonly ILogger _logger; private readonly IRhinoConversionSettingsFactory _rhinoConversionSettingsFactory; - private readonly ISpeckleApplication _speckleApplication; - private readonly ISdkActivityFactory _activityFactory; private readonly ITopLevelExceptionHandler _topLevelExceptionHandler; private readonly IAppIdleManager _idleManager; + private readonly ISendOperationManagerFactory _sendOperationManagerFactory; /// /// Used internally to aggregate the changed objects' id. Objects in this list will be reconverted. @@ -65,30 +57,24 @@ public sealed class RhinoSendBinding : ISendBinding DocumentModelStore store, IAppIdleManager idleManager, IBrowserBridge parent, - IServiceProvider serviceProvider, ICancellationManager cancellationManager, ISendConversionCache sendConversionCache, - IOperationProgressManager operationProgressManager, ILogger logger, IRhinoConversionSettingsFactory rhinoConversionSettingsFactory, - ISpeckleApplication speckleApplication, - ISdkActivityFactory activityFactory, - ITopLevelExceptionHandler topLevelExceptionHandler + ITopLevelExceptionHandler topLevelExceptionHandler, + ISendOperationManagerFactory sendOperationManagerFactory ) { _store = store; _idleManager = idleManager; - _serviceProvider = serviceProvider; _cancellationManager = cancellationManager; _sendConversionCache = sendConversionCache; - _operationProgressManager = operationProgressManager; _logger = logger; _rhinoConversionSettingsFactory = rhinoConversionSettingsFactory; - _speckleApplication = speckleApplication; Parent = parent; _topLevelExceptionHandler = topLevelExceptionHandler; + _sendOperationManagerFactory = sendOperationManagerFactory; Commands = new SendBindingUICommands(parent); // POC: Commands are tightly coupled with their bindings, at least for now, saves us injecting a factory. - _activityFactory = activityFactory; PreviousUnitSystem = RhinoDoc.ActiveDoc.ModelUnitSystem; SubscribeToRhinoEvents(); } @@ -168,7 +154,21 @@ public sealed class RhinoSendBinding : ISendBinding if (args is RhinoDoc.RenderMaterialAssignmentChangedEventArgs changedEventArgs) { - ChangedObjectIds[changedEventArgs.ObjectId.ToString()] = 1; + // Update ChangedObjectIdsInGroupsOrLayers (without triggering objects' expiration) + // 1. If Material was changed directly on the object: + if (changedEventArgs.ObjectId != Guid.Empty) + { + ChangedObjectIdsInGroupsOrLayers[changedEventArgs.ObjectId.ToString()] = 1; + } + // 2. If parent Layer material has changed: + else if (changedEventArgs.LayerId != Guid.Empty) + { + var layer = RhinoDoc.ActiveDoc.Layers.FindId(changedEventArgs.LayerId); + foreach (Guid objectId in GetChildObjectIdsFromLayerAndSubLayers(layer)) + { + ChangedObjectIdsInGroupsOrLayers[objectId.ToString()] = 1; + } + } _idleManager.SubscribeToIdle(nameof(RunExpirationChecks), RunExpirationChecks); } }); @@ -206,17 +206,10 @@ public sealed class RhinoSendBinding : ISendBinding } var layer = RhinoDoc.ActiveDoc.Layers[args.LayerIndex]; - - var allLayers = args.Document.Layers.Where(l => /* NOTE: layer path may actually be null in some cases (rhino's fault, not ours) */ - l.FullPath != null && l.FullPath.Contains(layer.Name) - ); // not e imperfect, but layer.GetChildren(true) is valid only in v8 and above; this filter will include the original layer. - foreach (var childLayer in allLayers) + // Record IDs of all sub-objects affected by the LayerTable event (without triggering each objects' expiration) + foreach (Guid objectId in GetChildObjectIdsFromLayerAndSubLayers(layer)) { - var sublayerObjs = RhinoDoc.ActiveDoc.Objects.FindByLayer(childLayer) ?? []; - foreach (var obj in sublayerObjs) - { - ChangedObjectIdsInGroupsOrLayers[obj.Id.ToString()] = 1; - } + ChangedObjectIdsInGroupsOrLayers[objectId.ToString()] = 1; } _idleManager.SubscribeToIdle(nameof(RunExpirationChecks), RunExpirationChecks); await Commands.RefreshSendFilters(); @@ -284,57 +277,25 @@ public sealed class RhinoSendBinding : ISendBinding public async Task Send(string modelCardId) { - using var activity = _activityFactory.Start(); - using var scope = _serviceProvider.CreateScope(); - scope - .ServiceProvider.GetRequiredService>() - .Initialize(_rhinoConversionSettingsFactory.Create(RhinoDoc.ActiveDoc)); - try - { - if (_store.GetModelById(modelCardId) is not SenderModelCard modelCard) + using var manager = _sendOperationManagerFactory.Create(); + + await manager.Process( + Commands, + modelCardId, + (sp, _) => + sp.GetRequiredService>() + .Initialize(_rhinoConversionSettingsFactory.Create(RhinoDoc.ActiveDoc)), + card => { - // Handle as GLOBAL ERROR at BrowserBridge - throw new InvalidOperationException("No publish model card was found."); - } - - using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId); - - List rhinoObjects = modelCard - .SendFilter.NotNull() - .RefreshObjectIds() - .Select(id => RhinoDoc.ActiveDoc.Objects.FindId(new Guid(id))) - .Where(obj => obj != null) - .ToList(); - - if (rhinoObjects.Count == 0) - { - // Handle as CARD ERROR in this function - throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!"); - } - - var sendResult = await scope - .ServiceProvider.GetRequiredService>() - .Execute( - rhinoObjects, - modelCard.GetSendInfo(_speckleApplication.ApplicationAndVersion), - _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationItem.Token), - cancellationItem.Token + return Task.FromResult>( + card.SendFilter.NotNull() + .RefreshObjectIds() + .Select(id => RhinoDoc.ActiveDoc.Objects.FindId(new Guid(id))) + .Where(obj => obj != null) + .ToList() ); - - await Commands.SetModelSendResult(modelCardId, sendResult.VersionId, sendResult.ConversionResults); - } - catch (OperationCanceledException) - { - // SWALLOW -> UI handles it immediately, so we do not need to handle anything for now! - // Idea for later -> when cancel called, create promise from UI to solve it later with this catch block. - // So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled - return; - } - 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); - } + } + ); } public void CancelSend(string modelCardId) => _cancellationManager.CancelOperation(modelCardId); @@ -407,4 +368,20 @@ public sealed class RhinoSendBinding : ISendBinding var senderModelCardIds = _store.GetSenders().Select(s => s.ModelCardId.NotNull()); await Commands.SetModelsExpired(senderModelCardIds); } + + private IEnumerable GetChildObjectIdsFromLayerAndSubLayers(Layer layer) + { + var allLayers = RhinoDoc.ActiveDoc.Layers.Where(l => /* NOTE: layer path may actually be null in some cases (rhino's fault, not ours) */ + l.FullPath != null && l.FullPath.Contains(layer.Name) + ); // not e imperfect, but layer.GetChildren(true) is valid only in v8 and above; this filter will include the original layer. + + foreach (var childLayer in allLayers) + { + var sublayerObjs = RhinoDoc.ActiveDoc.Objects.FindByLayer(childLayer) ?? []; + foreach (var obj in sublayerObjs) + { + yield return obj.Id; + } + } + } } diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Extensions/AttributeExtensions.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Extensions/AttributeExtensions.cs index c3d6bdb15..6d0274d6b 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Extensions/AttributeExtensions.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Extensions/AttributeExtensions.cs @@ -19,8 +19,8 @@ public static class SpeckleAttributeExtensions ObjectAttributes atts = new() { Name = name }; Dictionary userStrings = new(); Dictionary properties = @base is DataObject dataObj - ? dataObj.properties - : @base["properties"] as Dictionary ?? new(); + ? dataObj.properties ?? [] + : @base["properties"] as Dictionary ?? []; FlattenDictionaryToUserStrings(properties, userStrings, ""); foreach (var kvp in userStrings) { @@ -40,7 +40,7 @@ public static class SpeckleAttributeExtensions private static void FlattenDictionaryToUserStrings( Dictionary dict, Dictionary flattenedDict, - string keyPrefix = "" + string keyPrefix ) { foreach (var kvp in dict) diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoGroupBaker.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoGroupBaker.cs index 3ed1852f0..bf719ccb2 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoGroupBaker.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoGroupBaker.cs @@ -35,8 +35,10 @@ public class RhinoGroupBaker { try { - var appIds = groupProxy.objects.SelectMany(oldObjId => applicationIdMap[oldObjId]).Select(id => new Guid(id)); var groupName = (groupProxy.name ?? "No Name Group") + $" ({baseLayerName})"; + var appIds = groupProxy + .objects.SelectMany(oldObjId => LookupApplicationIds(groupName, oldObjId, applicationIdMap)) + .Select(id => new Guid(id)); _converterSettings.Current.Document.Groups.Add(groupName, appIds); } catch (Exception ex) when (!ex.IsFatal()) @@ -46,6 +48,20 @@ public class RhinoGroupBaker } } + private IEnumerable LookupApplicationIds( + string name, + string oldObjId, + Dictionary> applicationIdMap + ) + { + if (applicationIdMap.TryGetValue(oldObjId, out IReadOnlyCollection value)) + { + return value; + } + _logger.LogWarning("Group {group} references an application Id {appId} that cannot be mapped", name, oldObjId); + return []; + } + public void PurgeGroups(string baseLayerName) { for (int i = _converterSettings.Current.Document.Groups.Count; i >= 0; i--) diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoLayerBaker.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoLayerBaker.cs index 2daf7b2f2..c6bea23c3 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoLayerBaker.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoLayerBaker.cs @@ -3,6 +3,7 @@ using Rhino.DocObjects; using Speckle.Connectors.Common.Operations.Receive; using Speckle.Sdk; using Speckle.Sdk.Common; +using Speckle.Sdk.Common.Exceptions; using Speckle.Sdk.Models.Collections; using Layer = Rhino.DocObjects.Layer; @@ -55,13 +56,13 @@ public class RhinoLayerBaker : TraversalContextUnpacker foreach (var path in paths) { var names = path.Select(o => string.IsNullOrWhiteSpace(o.name) ? "unnamed" : o.name); - var key = string.Join(",", names!); + var key = string.Join(",", names); uniquePaths[key] = path; } foreach (var uniquePath in uniquePaths) { - var layerIndex = CreateLayerFromPath(uniquePath.Value, baseLayerName); + CreateLayerFromPath(uniquePath.Value, baseLayerName); } } catch (Exception ex) when (!ex.IsFatal()) @@ -90,7 +91,7 @@ public class RhinoLayerBaker : TraversalContextUnpacker return existingLayerIndex; } - throw new SpeckleException($"Did not find a layer in the cache with the name {layerFullName}"); + throw new ConversionException($"Did not find a layer in the cache with the name '{layerFullName}'"); } /// @@ -159,7 +160,7 @@ public class RhinoLayerBaker : TraversalContextUnpacker int index = currentDocument.Layers.Add(newLayer); if (index == -1) { - throw new SpeckleException($"Could not create layer {currentLayerName}."); + throw new SpeckleException($"Could not create layer '{currentLayerName}'."); } _hostLayerCache.Add(currentLayerName, index); previousLayer = currentDocument.Layers.FindIndex(index); // note we need to get the correct id out, hence why we're double calling this diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoMaterialUnpacker.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoMaterialUnpacker.cs index f3a49464b..14559a698 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoMaterialUnpacker.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoMaterialUnpacker.cs @@ -89,8 +89,11 @@ public class RhinoMaterialUnpacker } else if (material is not null) { - RenderMaterial convertedRender = ConvertMaterialToRenderMaterial(material); - myMaterial = ConvertRenderMaterialToSpeckle(convertedRender); + RenderMaterial? convertedRender = ConvertMaterialToRenderMaterial(material); + if (convertedRender is not null) + { + myMaterial = ConvertRenderMaterialToSpeckle(convertedRender); + } } if (myMaterial is null) @@ -174,7 +177,7 @@ public class RhinoMaterialUnpacker } // converts a rhino material to a rhino render material - private RenderMaterial ConvertMaterialToRenderMaterial(Material material) + private RenderMaterial? ConvertMaterialToRenderMaterial(Material material) { // get physically based render material Material pbMaterial = material; diff --git a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs index 7439fd489..82e96d9f1 100644 --- a/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs +++ b/Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Receive/RhinoHostObjectBuilder.cs @@ -11,8 +11,8 @@ using Speckle.Connectors.Rhino.Extensions; using Speckle.Connectors.Rhino.HostApp; using Speckle.Converters.Common; using Speckle.Converters.Rhino; -using Speckle.Sdk; using Speckle.Sdk.Common; +using Speckle.Sdk.Common.Exceptions; using Speckle.Sdk.Logging; using Speckle.Sdk.Models; using Speckle.Sdk.Models.Collections; @@ -35,6 +35,7 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder private readonly RootObjectUnpacker _rootObjectUnpacker; private readonly ISdkActivityFactory _activityFactory; private readonly IThreadContext _threadContext; + private readonly IReceiveConversionHandler _conversionHandler; public RhinoHostObjectBuilder( IRootToHostConverter converter, @@ -46,7 +47,8 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder RhinoColorBaker colorBaker, RhinoGroupBaker groupBaker, ISdkActivityFactory activityFactory, - IThreadContext threadContext + IThreadContext threadContext, + IReceiveConversionHandler conversionHandler ) { _converter = converter; @@ -59,6 +61,7 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder _groupBaker = groupBaker; _activityFactory = activityFactory; _threadContext = threadContext; + _conversionHandler = conversionHandler; } #pragma warning disable CA1506 @@ -142,79 +145,73 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder { foreach (var (path, obj) in atomicObjectsWithoutInstanceComponentsWithPath) { - using (var convertActivity = _activityFactory.Start("Converting object")) + onOperationProgressed.Report( + new("Converting objects", (double)++count / atomicObjectsWithoutInstanceComponentsForConverter.Count) + ); + var ex = _conversionHandler.TryConvert(() => { - onOperationProgressed.Report( - new("Converting objects", (double)++count / atomicObjectsWithoutInstanceComponentsForConverter.Count) - ); + // 0: get pre-created layer from cache in layer baker + int layerIndex = _layerBaker.GetLayerIndex(path, baseLayerName); cancellationToken.ThrowIfCancellationRequested(); - try + + // 1: create object attributes for baking + ObjectAttributes atts = obj.GetAttributes(); + atts.LayerIndex = layerIndex; + + // 2: convert + var result = _converter.Convert(obj); + + // 3: bake + var conversionIds = new List(); + if (result is GeometryBase geometryBase) { - // 0: get pre-created layer from cache in layer baker - int layerIndex = _layerBaker.GetLayerIndex(path, baseLayerName); - - // 1: create object attributes for baking - ObjectAttributes atts = obj.GetAttributes(); - atts.LayerIndex = layerIndex; - - // 2: convert - var result = _converter.Convert(obj); - - // 3: bake - var conversionIds = new List(); - if (result is GeometryBase geometryBase) + var guid = BakeObject(geometryBase, obj, null, atts); + conversionIds.Add(guid.ToString()); + } + else if (result is List geometryBases) // one to many raw encoding case + { + // NOTE: I'm unhappy about this case (dim). It's needed as the raw encoder approach can hypothetically return + // multiple "geometry bases" - but this is not a fallback conversion. + // EXTRA NOTE: Oguzhan says i shouldn't be unhappy about this - it's a legitimate case + // EXTRA EXTRA NOTE: TY Ogu, i am no longer than unhappy about it. It's legit "mess". + foreach (var gb in geometryBases) { - var guid = BakeObject(geometryBase, obj, null, atts); + var guid = BakeObject(gb, obj, null, atts); conversionIds.Add(guid.ToString()); } - else if (result is List geometryBases) // one to many raw encoding case - { - // NOTE: I'm unhappy about this case (dim). It's needed as the raw encoder approach can hypothetically return - // multiple "geometry bases" - but this is not a fallback conversion. - // EXTRA NOTE: Oguzhan says i shouldn't be unhappy about this - it's a legitimate case - // EXTRA EXTRA NOTE: TY Ogu, i am no longer than unhappy about it. It's legit "mess". - foreach (var gb in geometryBases) - { - var guid = BakeObject(gb, obj, null, atts); - conversionIds.Add(guid.ToString()); - } - } - else if (result is List<(GeometryBase, Base)> fallbackConversionResult) // one to many fallback conversion - { - var guids = BakeObjectsAsFallbackGroup(fallbackConversionResult, obj, atts, baseLayerName); - conversionIds.AddRange(guids.Select(id => id.ToString())); - } - - if (conversionIds.Count == 0) - { - // TODO: add this condition to report object - same as in autocad - throw new SpeckleException("Object did not convert to any native geometry"); - } - - // 4: log - var id = conversionIds[0]; // this is group id if it is a one to many conversion, otherwise id of object itself - conversionResults.Add(new(Status.SUCCESS, obj, id, result.GetType().ToString())); - if (conversionIds.Count == 1) - { - bakedObjectIds.Add(id); - } - else - { - // first item always a group id if it is a one-to-many, - // we do not want to deal with later groups and its sub elements. It causes a huge issue on performance. - bakedObjectIds.AddRange(conversionIds.Skip(1)); - } - - // 5: populate app id map - applicationIdMap[obj.applicationId ?? obj.id.NotNull()] = conversionIds; - convertActivity?.SetStatus(SdkActivityStatusCode.Ok); } - catch (Exception ex) when (!ex.IsFatal()) + else if (result is List<(GeometryBase, Base)> fallbackConversionResult) // one to many fallback conversion { - conversionResults.Add(new(Status.ERROR, obj, null, null, ex)); - convertActivity?.SetStatus(SdkActivityStatusCode.Error); - convertActivity?.RecordException(ex); + var guids = BakeObjectsAsFallbackGroup(fallbackConversionResult, obj, atts, baseLayerName); + conversionIds.AddRange(guids.Select(id => id.ToString())); } + + if (conversionIds.Count == 0) + { + // TODO: add this condition to report object - same as in autocad + throw new ConversionException("Object did not convert to any native geometry"); + } + + // 4: log + var id = conversionIds[0]; // this is group id if it is a one to many conversion, otherwise id of object itself + conversionResults.Add(new(Status.SUCCESS, obj, id, result.GetType().ToString())); + if (conversionIds.Count == 1) + { + bakedObjectIds.Add(id); + } + else + { + // first item always a group id if it is a one-to-many, + // we do not want to deal with later groups and its sub elements. It causes a huge issue on performance. + bakedObjectIds.AddRange(conversionIds.Skip(1)); + } + + // 5: populate app id map + applicationIdMap[obj.applicationId ?? obj.id.NotNull()] = conversionIds; + }); + if (ex is not null) + { + conversionResults.Add(new(Status.ERROR, obj, null, null, ex)); } } } diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs index d709cd329..3a4be05d8 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Bindings/TeklaSendBinding.cs @@ -3,11 +3,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Speckle.Connectors.Common.Caching; using Speckle.Connectors.Common.Cancellation; -using Speckle.Connectors.Common.Operations; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; -using Speckle.Connectors.DUI.Exceptions; -using Speckle.Connectors.DUI.Logging; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.DUI.Models.Card.SendFilter; @@ -15,9 +12,7 @@ using Speckle.Connectors.DUI.Settings; using Speckle.Connectors.TeklaShared.Operations.Send.Settings; using Speckle.Converters.Common; using Speckle.Converters.TeklaShared; -using Speckle.Sdk; using Speckle.Sdk.Common; -using Speckle.Sdk.Logging; using Tekla.Structures; using Tekla.Structures.Model; using Task = System.Threading.Tasks.Task; @@ -31,18 +26,15 @@ public sealed class TeklaSendBinding : ISendBinding public IBrowserBridge Parent { get; } private readonly DocumentModelStore _store; - private readonly IServiceProvider _serviceProvider; private readonly List _sendFilters; private readonly ICancellationManager _cancellationManager; private readonly ISendConversionCache _sendConversionCache; - private readonly IOperationProgressManager _operationProgressManager; private readonly ILogger _logger; private readonly ITeklaConversionSettingsFactory _teklaConversionSettingsFactory; - private readonly ISpeckleApplication _speckleApplication; - private readonly ISdkActivityFactory _activityFactory; private readonly Model _model; private readonly ToSpeckleSettingsManager _toSpeckleSettingsManager; private readonly Events _events; + private readonly ISendOperationManagerFactory _sendOperationManagerFactory; private ConcurrentDictionary ChangedObjectIds { get; set; } = new(); @@ -50,30 +42,24 @@ public sealed class TeklaSendBinding : ISendBinding DocumentModelStore store, IBrowserBridge parent, IEnumerable sendFilters, - IServiceProvider serviceProvider, ICancellationManager cancellationManager, ISendConversionCache sendConversionCache, - IOperationProgressManager operationProgressManager, ILogger logger, ITeklaConversionSettingsFactory teklaConversionSettingsFactory, - ISpeckleApplication speckleApplication, - ISdkActivityFactory activityFactory, - ToSpeckleSettingsManager toSpeckleSettingsManager + ToSpeckleSettingsManager toSpeckleSettingsManager, + ISendOperationManagerFactory sendOperationManagerFactory ) { _store = store; - _serviceProvider = serviceProvider; _sendFilters = sendFilters.ToList(); _cancellationManager = cancellationManager; _sendConversionCache = sendConversionCache; - _operationProgressManager = operationProgressManager; _logger = logger; _teklaConversionSettingsFactory = teklaConversionSettingsFactory; - _speckleApplication = speckleApplication; Parent = parent; Commands = new SendBindingUICommands(parent); - _activityFactory = activityFactory; _toSpeckleSettingsManager = toSpeckleSettingsManager; + _sendOperationManagerFactory = sendOperationManagerFactory; _model = new Model(); _events = new Events(); @@ -111,55 +97,22 @@ public sealed class TeklaSendBinding : ISendBinding public async Task Send(string modelCardId) { - using var activity = _activityFactory.Start(); - - try - { - if (_store.GetModelById(modelCardId) is not SenderModelCard modelCard) - { - throw new InvalidOperationException("No publish model card was found."); - } - using var scope = _serviceProvider.CreateScope(); - scope - .ServiceProvider.GetRequiredService>() - .Initialize( - _teklaConversionSettingsFactory.Create(_model, _toSpeckleSettingsManager.GetSendRebarsAsSolid(modelCard)) - ); - - using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId); - - List teklaObjects = modelCard - .SendFilter.NotNull() - .RefreshObjectIds() - .Select(id => _model.SelectModelObject(new Identifier(new Guid(id)))) - .Where(obj => obj != null) - .ToList(); - - if (teklaObjects.Count == 0) - { - throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!"); - } - - var sendResult = await scope - .ServiceProvider.GetRequiredService>() - .Execute( - teklaObjects, - modelCard.GetSendInfo(_speckleApplication.ApplicationAndVersion), - _operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationItem.Token), - cancellationItem.Token - ); - - await Commands.SetModelSendResult(modelCardId, sendResult.VersionId, sendResult.ConversionResults); - } - catch (OperationCanceledException) - { - return; - } - catch (Exception ex) when (!ex.IsFatal()) - { - _logger.LogModelCardHandledError(ex); - await Commands.SetModelError(modelCardId, ex); - } + using var manager = _sendOperationManagerFactory.Create(); + await manager.Process( + Commands, + modelCardId, + (sp, card) => + sp.GetRequiredService>() + .Initialize( + _teklaConversionSettingsFactory.Create(_model, _toSpeckleSettingsManager.GetSendRebarsAsSolid(card)) + ), + card => + card.SendFilter.NotNull() + .RefreshObjectIds() + .Select(id => _model.SelectModelObject(new Identifier(new Guid(id)))) + .Where(obj => obj != null) + .ToList() + ); } public void CancelSend(string modelCardId) => _cancellationManager.CancelOperation(modelCardId); diff --git a/Connectors/Tekla/Speckle.Connector.TeklaShared/Resources/speckle.svg b/Connectors/Tekla/Speckle.Connector.TeklaShared/Resources/speckle.svg index 64500d6f7..ffaf2e113 100644 --- a/Connectors/Tekla/Speckle.Connector.TeklaShared/Resources/speckle.svg +++ b/Connectors/Tekla/Speckle.Connector.TeklaShared/Resources/speckle.svg @@ -1,6 +1,6 @@ - - - - + + + + diff --git a/Converters/Civil3d/Speckle.Converters.Civil3dShared/Civil3dRootToSpeckleConverter.cs b/Converters/Civil3d/Speckle.Converters.Civil3dShared/Civil3dRootToSpeckleConverter.cs index 15e2172a2..980e0daab 100644 --- a/Converters/Civil3d/Speckle.Converters.Civil3dShared/Civil3dRootToSpeckleConverter.cs +++ b/Converters/Civil3d/Speckle.Converters.Civil3dShared/Civil3dRootToSpeckleConverter.cs @@ -58,16 +58,16 @@ public class Civil3dRootToSpeckleConverter : IRootToSpeckleConverter { var result = objectConverter.Convert(target); - // NOTE: we can not test acad objects props, so commented out. - // // we need to capture properties on autocad entities - // if (target is ADB.Entity autocadEntity) - // { - // var properties = _propertiesExtractor.GetProperties(autocadEntity); - // if (properties.Count > 0) - // { - // result["properties"] = properties; - // } - // } + // This is needed to retrieve property sets on solids + // Civil entity properties are retrieved in the CivilEntityToSpeckleTopLevelConverter + if (target is not CDB.Entity && target is ADB.Entity autocadEntity) + { + var properties = _propertiesExtractor.GetProperties(autocadEntity); + if (properties.Count > 0) + { + result["properties"] = properties; + } + } tr.Commit(); return result; diff --git a/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/ClassPropertiesExtractor.cs b/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/ClassPropertiesExtractor.cs index f4212c028..eaf05662e 100644 --- a/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/ClassPropertiesExtractor.cs +++ b/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/ClassPropertiesExtractor.cs @@ -43,7 +43,7 @@ public class ClassPropertiesExtractor /// /// /// - public Dictionary GetClassProperties(CDB.Entity entity) + public Dictionary GetClassProperties(ADB.Entity entity) { switch (entity) { diff --git a/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/ExtensionDictionaryExtractor.cs b/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/ExtensionDictionaryExtractor.cs index 024fba91f..eb4968984 100644 --- a/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/ExtensionDictionaryExtractor.cs +++ b/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/ExtensionDictionaryExtractor.cs @@ -19,7 +19,7 @@ public class ExtensionDictionaryExtractor /// /// /// - public Dictionary? GetExtensionDictionary(CDB.Entity entity) + public Dictionary? GetExtensionDictionary(ADB.Entity entity) { if (entity is null || entity.ExtensionDictionary == ADB.ObjectId.Null) { diff --git a/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/PartDataExtractor.cs b/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/PartDataExtractor.cs index b8d73608b..59748d01f 100644 --- a/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/PartDataExtractor.cs +++ b/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/PartDataExtractor.cs @@ -14,7 +14,7 @@ public class PartDataExtractor /// /// /// - public Dictionary? GetPartData(CDB.Entity entity) + public Dictionary? GetPartData(ADB.Entity entity) { return entity switch { diff --git a/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/PropertiesExtractor.cs b/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/PropertiesExtractor.cs index 82ad1fbad..f98a2b5c1 100644 --- a/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/PropertiesExtractor.cs +++ b/Converters/Civil3d/Speckle.Converters.Civil3dShared/ToSpeckle/Properties/PropertiesExtractor.cs @@ -23,7 +23,7 @@ public class PropertiesExtractor _extensionDictionaryExtractor = extensionDictionaryExtractor; } - public Dictionary GetProperties(CDB.Entity entity) + public Dictionary GetProperties(ADB.Entity entity) { // first get all class properties, which will be at the root level of props dictionary Dictionary properties = _classPropertiesExtractor.GetClassProperties(entity); diff --git a/DUI3/Speckle.Connectors.DUI.Tests/ReceiveOperationManagerTests.cs b/DUI3/Speckle.Connectors.DUI.Tests/ReceiveOperationManagerTests.cs new file mode 100644 index 000000000..81394cf0e --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI.Tests/ReceiveOperationManagerTests.cs @@ -0,0 +1,204 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; +using Speckle.Connectors.Common.Builders; +using Speckle.Connectors.Common.Cancellation; +using Speckle.Connectors.Common.Conversion; +using Speckle.Connectors.Common.Operations; +using Speckle.Connectors.DUI.Bindings; +using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Models; +using Speckle.Connectors.DUI.Models.Card; +using Speckle.Sdk; +using Speckle.Testing; + +namespace Speckle.Connectors.DUI.Tests; + +[TestFixture] +public class ReceiveOperationManagerTests : MoqTest +{ + private Mock _serviceScopeMock; + private Mock _cancellationManagerMock; + private Mock _storeMock; + private Mock _speckleAppMock; + private Mock _progressManagerMock; + private Mock> _loggerMock; + private ReceiveOperationManager _manager; + + [SetUp] + public void SetUp() + { + _serviceScopeMock = Create(); + _cancellationManagerMock = Create(); + _storeMock = Create(); + _speckleAppMock = Create(); + _progressManagerMock = Create(); + _loggerMock = Create>(MockBehavior.Loose); + _manager = new ReceiveOperationManager( + _serviceScopeMock.Object, + _cancellationManagerMock.Object, + _storeMock.Object, + _speckleAppMock.Object, + _progressManagerMock.Object, + _loggerMock.Object + ); + _serviceScopeMock.Setup(x => x.Dispose()); + } + + [TearDown] + public void TearDown() + { + _manager.Dispose(); + } + + [Test] + public void Process_ShouldThrow_WhenModelCardNotFound() + { + _storeMock.Setup(x => x.GetModelById("id1")).Returns((ModelCard?)null); + var commands = Create(); + Assert.ThrowsAsync( + async () => + await _manager.Process( + commands.Object, + "id1", + _ => { }, + (s, f) => Task.FromResult(null) + ) + ); + } + + [Test] + public async Task Process_ShouldHandleOperationCanceledException() + { + var modelCard = new ReceiverModelCard { ModelCardId = "id2", ModelName = "Test" }; + _storeMock.Setup(x => x.GetModelById("id2")).Returns(modelCard); + var cancellationItem = Create(); + cancellationItem.Setup(x => x.Token).Returns(CancellationToken.None); + cancellationItem.Setup(x => x.Dispose()); + + _cancellationManagerMock.Setup(x => x.GetCancellationItem("id2")).Returns(cancellationItem.Object); + _cancellationManagerMock.Setup(x => x.CancelOperation("id2")); + + var receiveOp = Create(); + var serviceProvider = Create(); + serviceProvider.Setup(x => x.GetService(typeof(IReceiveOperation))).Returns(receiveOp.Object); + _serviceScopeMock.Setup(x => x.ServiceProvider).Returns(serviceProvider.Object); + + var exception = new OperationCanceledException(); + + var commands = Create(); + commands.Setup(x => x.Bridge).Returns(Create().Object); + + var progressHandler = Create>(); + _progressManagerMock + .Setup(x => + x.CreateOperationProgressEventHandler(It.IsAny(), "id2", It.IsAny()) + ) + .Returns(progressHandler.Object); + + var processor = new Func>, Task>( + (s, f) => throw exception + ); + await _manager.Process(commands.Object, "id2", _ => { }, processor); + _cancellationManagerMock.Verify(x => x.CancelOperation("id2"), Times.Once); + } + + [Test] + public async Task Process_ShouldHandleGeneralException_AndSetModelError() + { + var modelCard = new ReceiverModelCard { ModelCardId = "id3", ModelName = "Test" }; + _storeMock.Setup(x => x.GetModelById("id3")).Returns(modelCard); + + var cancellationItem = Create(); + cancellationItem.Setup(x => x.Token).Returns(CancellationToken.None); + cancellationItem.Setup(x => x.Dispose()); + + _cancellationManagerMock.Setup(x => x.GetCancellationItem("id3")).Returns(cancellationItem.Object); + _cancellationManagerMock.Setup(x => x.CancelOperation("id3")); + + var commands = Create(); + var exception = new InvalidOperationException("fail"); + commands.Setup(x => x.SetModelError("id3", exception)).Returns(Task.CompletedTask); + var bridge = Create(); + commands.Setup(x => x.Bridge).Returns(bridge.Object); + + var progressHandler = Create>(); + _progressManagerMock + .Setup(x => x.CreateOperationProgressEventHandler(bridge.Object, "id3", It.IsAny())) + .Returns(progressHandler.Object); + + var receiveOp = Create(); + var serviceProvider = Create(); + serviceProvider.Setup(x => x.GetService(typeof(IReceiveOperation))).Returns(receiveOp.Object); + _serviceScopeMock.Setup(x => x.ServiceProvider).Returns(serviceProvider.Object); + + var processor = new Func>, Task>( + (s, f) => throw exception + ); + await _manager.Process(commands.Object, "id3", _ => { }, processor); + + commands.Verify(x => x.SetModelError("id3", It.IsAny()), Times.Once); + _cancellationManagerMock.Verify(x => x.CancelOperation("id3"), Times.Once); + } + + [Test] + public async Task Process_ShouldSetModelReceiveResult_OnSuccess() + { + var modelCard = new ReceiverModelCard + { + ModelCardId = "id4", + ModelName = "Test", + AccountId = "AccountId", + ServerUrl = "http://localhost", + ProjectId = "ProjectId", + ProjectName = "ProjectName", + ModelId = "ModelId", + SelectedVersionId = "SelectedVersionId", + }; + _storeMock.Setup(x => x.GetModelById("id4")).Returns(modelCard); + var cancellationItem = Create(); + cancellationItem.Setup(x => x.Token).Returns(CancellationToken.None); + cancellationItem.Setup(x => x.Dispose()); + + _cancellationManagerMock.Setup(x => x.CancelOperation("id4")); + _cancellationManagerMock.Setup(x => x.GetCancellationItem("id4")).Returns(cancellationItem.Object); + + var commands = Create(); + commands.Setup(x => x.Bridge).Returns(Create().Object); + commands + .Setup(x => + x.SetModelReceiveResult("id4", It.IsAny>(), It.IsAny>()) + ) + .Returns(Task.CompletedTask); + + var progressHandler = Create>(); + _progressManagerMock + .Setup(x => + x.CreateOperationProgressEventHandler(It.IsAny(), "id4", It.IsAny()) + ) + .Returns(progressHandler.Object); + + var receiveOp = Create(); + var bakedIds = new List { "obj1", "obj2" }; + var hostResult = new HostObjectBuilderResult(bakedIds, []); + var serviceProvider = Create(); + serviceProvider.Setup(x => x.GetService(typeof(IReceiveOperation))).Returns(receiveOp.Object); + _serviceScopeMock.Setup(x => x.ServiceProvider).Returns(serviceProvider.Object); + receiveOp + .Setup(x => x.Execute(It.IsAny(), progressHandler.Object, CancellationToken.None)) + .ReturnsAsync(hostResult); + _speckleAppMock.Setup(x => x.Slug).Returns("slug"); + + var processor = new Func>, Task>( + async (s, f) => await f() + ); + await _manager.Process(commands.Object, "id4", _ => { }, processor); + + commands.Verify( + x => x.SetModelReceiveResult("id4", bakedIds, It.IsAny>()), + Times.Once + ); + _cancellationManagerMock.Verify(x => x.CancelOperation("id4"), Times.Once); + } +} diff --git a/DUI3/Speckle.Connectors.DUI.Tests/SendOperationManagerTests.cs b/DUI3/Speckle.Connectors.DUI.Tests/SendOperationManagerTests.cs new file mode 100644 index 000000000..a98e62e3c --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI.Tests/SendOperationManagerTests.cs @@ -0,0 +1,116 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; +using Speckle.Connectors.Common.Cancellation; +using Speckle.Connectors.Common.Conversion; +using Speckle.Connectors.Common.Operations; +using Speckle.Connectors.DUI.Bindings; +using Speckle.Connectors.DUI.Bridge; +using Speckle.Connectors.DUI.Models; +using Speckle.Connectors.DUI.Models.Card; +using Speckle.Connectors.DUI.Utils; +using Speckle.Sdk; +using Speckle.Sdk.Logging; +using Speckle.Sdk.Models; +using Speckle.Sdk.Serialisation; +using Speckle.Testing; + +namespace Speckle.Connectors.DUI.Tests; + +public class SendOperationManagerTests : MoqTest +{ + [Test] + public async Task TestHappyProcess() + { + // Arrange + var serviceScopeMock = Create(); + var serviceProviderMock = Create(); + serviceScopeMock.Setup(x => x.ServiceProvider).Returns(serviceProviderMock.Object); + serviceScopeMock.Setup(x => x.Dispose()); + + var operationProgressManager = Create(); + var progressHandler = Create>(); + var modelCard = new SenderModelCard + { + ModelCardId = "model1", + AccountId = "acc", + ServerUrl = "http://localhost", + ProjectId = "proj", + ModelId = "mod" + }; + var bridge = Create(); + + operationProgressManager + .Setup(x => + x.CreateOperationProgressEventHandler(bridge.Object, modelCard.ModelCardId, It.IsAny()) + ) + .Returns(progressHandler.Object); + + var store = new TestDocumentModelStore( + Create>(MockBehavior.Loose).Object, + Create(MockBehavior.Loose).Object + ); + + store.AddModel(modelCard); + + var cancellationManager = Create(); + var cancellationItem = Create(); + cancellationItem.Setup(x => x.Token).Returns(CancellationToken.None); + cancellationItem.Setup(x => x.Dispose()); + cancellationManager.Setup(x => x.GetCancellationItem(modelCard.ModelCardId)).Returns(cancellationItem.Object); + + var speckleApplication = Create(); + speckleApplication.SetupGet(x => x.ApplicationAndVersion).Returns("TestApp 1.0"); + + var activityFactory = Create(); + var activity = Create(); + activityFactory.Setup(x => x.Start(null, It.IsAny())).Returns(activity.Object); + activity.Setup(x => x.Dispose()); + + var logger = Create>(MockBehavior.Loose); + + var sendResults = new List(); + var versionId = "v1"; + var objects = new List { "obj1", "obj2" }; + + var sendOperationMock = Create>(); + sendOperationMock + .Setup(x => x.Execute(objects, It.IsAny(), progressHandler.Object, It.IsAny())) + .ReturnsAsync( + new SendOperationResult("rootObjId", versionId, new Dictionary(), sendResults) + ); + + serviceProviderMock.Setup(x => x.GetService(typeof(ISendOperation))).Returns(sendOperationMock.Object); + + var commandsMock = Create(); + commandsMock.Setup(x => x.Bridge).Returns(bridge.Object); + commandsMock + .Setup(x => x.SetModelSendResult(modelCard.ModelCardId, versionId, sendResults)) + .Returns(Task.CompletedTask); + + using var manager = new SendOperationManager( + serviceScopeMock.Object, + operationProgressManager.Object, + store, + cancellationManager.Object, + speckleApplication.Object, + activityFactory.Object, + logger.Object + ); + + // Act + await manager.Process(commandsMock.Object, "model1", (sp, card) => { }, card => objects); + } + + // Helper for in-memory DocumentModelStore + private sealed class TestDocumentModelStore : DocumentModelStore + { + public TestDocumentModelStore(ILogger logger, IJsonSerializer serializer) + : base(logger, serializer) { } + + protected override void HostAppSaveState(string modelCardState) { } + + protected override void LoadState() => throw new NotImplementedException(); + } +} diff --git a/DUI3/Speckle.Connectors.DUI.WebView/Speckle.Connectors.DUI.WebView.csproj b/DUI3/Speckle.Connectors.DUI.WebView/Speckle.Connectors.DUI.WebView.csproj index 6c6aa310d..3f1045a28 100644 --- a/DUI3/Speckle.Connectors.DUI.WebView/Speckle.Connectors.DUI.WebView.csproj +++ b/DUI3/Speckle.Connectors.DUI.WebView/Speckle.Connectors.DUI.WebView.csproj @@ -1,7 +1,7 @@ - net48;net6.0-windows;net8.0-windows + net48;net8.0-windows x64 diff --git a/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json b/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json index cfd515df6..8ef8ed802 100644 --- a/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json +++ b/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json @@ -340,306 +340,6 @@ "contentHash": "mYjR5i5zaNxkR2VXi2Ills3XG3VZ4z3wLSQBn7GldAudtxI8yS09M6w4ltFNcBmgLlnYHYiIbsWEilIGUbi0Nw==" } }, - "net6.0-windows7.0": { - "Microsoft.NETFramework.ReferenceAssemblies": { - "type": "Direct", - "requested": "[1.0.3, )", - "resolved": "1.0.3", - "contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==", - "dependencies": { - "Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3" - } - }, - "Microsoft.SourceLink.GitHub": { - "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "8.0.0", - "Microsoft.SourceLink.Common": "8.0.0" - } - }, - "Microsoft.Web.WebView2": { - "type": "Direct", - "requested": "[1.0.1938.49, )", - "resolved": "1.0.1938.49", - "contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw==" - }, - "PolySharp": { - "type": "Direct", - "requested": "[1.14.1, )", - "resolved": "1.14.1", - "contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ==" - }, - "Speckle.InterfaceGenerator": { - "type": "Direct", - "requested": "[0.9.6, )", - "resolved": "0.9.6", - "contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w==" - }, - "GraphQL.Client": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "8yPNBbuVBpTptivyAlak4GZvbwbUcjeQTL4vN1HKHRuOykZ4r7l5fcLS6vpyPyLn0x8FsL31xbOIKyxbmR9rbA==", - "dependencies": { - "GraphQL.Client.Abstractions": "6.0.0", - "GraphQL.Client.Abstractions.Websocket": "6.0.0", - "System.Reactive": "5.0.0" - } - }, - "GraphQL.Client.Abstractions": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "h7uzWFORHZ+CCjwr/ThAyXMr0DPpzEANDa4Uo54wqCQ+j7qUKwqYTgOrb1W40sqbvNaZm9v/X7It31SUw0maHA==", - "dependencies": { - "GraphQL.Primitives": "6.0.0" - } - }, - "GraphQL.Client.Abstractions.Websocket": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "Nr9bPf8gIOvLuXpqEpqr9z9jslYFJOvd0feHth3/kPqeR3uMbjF5pjiwh4jxyMcxHdr8Pb6QiXkV3hsSyt0v7A==", - "dependencies": { - "GraphQL.Client.Abstractions": "6.0.0" - } - }, - "GraphQL.Primitives": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "yg72rrYDapfsIUrul7aF6wwNnTJBOFvuA9VdDTQpPa8AlAriHbufeXYLBcodKjfUdkCnaiggX1U/nEP08Zb5GA==" - }, - "Microsoft.Bcl.AsyncInterfaces": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==" - }, - "Microsoft.Build.Tasks.Git": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ==" - }, - "Microsoft.CSharp": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA==" - }, - "Microsoft.Data.Sqlite": { - "type": "Transitive", - "resolved": "7.0.5", - "contentHash": "KGxbPeWsQMnmQy43DSBxAFtHz3l2JX8EWBSGUCvT3CuZ8KsuzbkqMIJMDOxWtG8eZSoCDI04aiVQjWuuV8HmSw==", - "dependencies": { - "Microsoft.Data.Sqlite.Core": "7.0.5", - "SQLitePCLRaw.bundle_e_sqlite3": "2.1.4" - } - }, - "Microsoft.Data.Sqlite.Core": { - "type": "Transitive", - "resolved": "7.0.5", - "contentHash": "FTerRmQPqHrCrnoUzhBu+E+1DNGwyrAMLqHkAqOOOu5pGfyMOj8qQUBxI/gDtWtG11p49UxSfWmBzRNlwZqfUg==", - "dependencies": { - "SQLitePCLRaw.core": "2.1.4" - } - }, - "Microsoft.Extensions.Configuration": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "nOP8R1mVb/6mZtm2qgAJXn/LFm/2kMjHDAg/QJLFG6CuWYJtaD3p1BwQhufBVvRzL9ceJ/xF0SQ0qsI2GkDQAA==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "2.2.0" - } - }, - "Microsoft.Extensions.Configuration.Abstractions": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "65MrmXCziWaQFrI0UHkQbesrX5wTwf9XPjY5yFm/VkgJKFJ5gqvXRoXjIZcf2wLi5ZlwGz/oMYfyURVCWbM5iw==", - "dependencies": { - "Microsoft.Extensions.Primitives": "2.2.0" - } - }, - "Microsoft.Extensions.Configuration.Binder": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "vJ9xvOZCnUAIHcGC3SU35r3HKmHTVIeHzo6u/qzlHAqD8m6xv92MLin4oJntTvkpKxVX3vI1GFFkIQtU3AdlsQ==", - "dependencies": { - "Microsoft.Extensions.Configuration": "2.2.0" - } - }, - "Microsoft.Extensions.DependencyInjection.Abstractions": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw==" - }, - "Microsoft.Extensions.Options": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "UpZLNLBpIZ0GTebShui7xXYh6DmBHjWM8NxGxZbdQh/bPZ5e6YswqI+bru6BnEL5eWiOdodsXtEz3FROcgi/qg==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", - "Microsoft.Extensions.Primitives": "2.2.0", - "System.ComponentModel.Annotations": "4.5.0" - } - }, - "Microsoft.Extensions.Primitives": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "azyQtqbm4fSaDzZHD/J+V6oWMFaf2tWP4WEGIYePLCMw3+b2RQdj9ybgbQyjCshcitQKQ4lEDOZjmSlTTrHxUg==", - "dependencies": { - "System.Memory": "4.5.1", - "System.Runtime.CompilerServices.Unsafe": "4.5.1" - } - }, - "Microsoft.NETFramework.ReferenceAssemblies.net461": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA==" - }, - "Microsoft.SourceLink.Common": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" - }, - "Speckle.Newtonsoft.Json": { - "type": "Transitive", - "resolved": "13.0.2", - "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" - }, - "SQLitePCLRaw.bundle_e_sqlite3": { - "type": "Transitive", - "resolved": "2.1.4", - "contentHash": "EWI1olKDjFEBMJu0+3wuxwziIAdWDVMYLhuZ3Qs84rrz+DHwD00RzWPZCa+bLnHCf3oJwuFZIRsHT5p236QXww==", - "dependencies": { - "SQLitePCLRaw.lib.e_sqlite3": "2.1.4", - "SQLitePCLRaw.provider.e_sqlite3": "2.1.4" - } - }, - "SQLitePCLRaw.core": { - "type": "Transitive", - "resolved": "2.1.4", - "contentHash": "inBjvSHo9UDKneGNzfUfDjK08JzlcIhn1+SP5Y3m6cgXpCxXKCJDy6Mka7LpgSV+UZmKSnC8rTwB0SQ0xKu5pA==", - "dependencies": { - "System.Memory": "4.5.3" - } - }, - "SQLitePCLRaw.lib.e_sqlite3": { - "type": "Transitive", - "resolved": "2.1.4", - "contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg==" - }, - "SQLitePCLRaw.provider.e_sqlite3": { - "type": "Transitive", - "resolved": "2.1.4", - "contentHash": "CSlb5dUp1FMIkez9Iv5EXzpeq7rHryVNqwJMWnpq87j9zWZexaEMdisDktMsnnrzKM6ahNrsTkjqNodTBPBxtQ==", - "dependencies": { - "SQLitePCLRaw.core": "2.1.4" - } - }, - "System.ComponentModel.Annotations": { - "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==" - }, - "System.Memory": { - "type": "Transitive", - "resolved": "4.5.3", - "contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==" - }, - "System.Reactive": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==" - }, - "System.Runtime.CompilerServices.Unsafe": { - "type": "Transitive", - "resolved": "4.5.1", - "contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw==" - }, - "speckle.connectors.common": { - "type": "Project", - "dependencies": { - "Microsoft.Extensions.DependencyInjection": "[2.2.0, )", - "Speckle.Connectors.Logging": "[1.0.0, )", - "Speckle.Objects": "[3.4.2, )", - "Speckle.Sdk": "[3.4.2, )", - "Speckle.Sdk.Dependencies": "[3.4.2, )" - } - }, - "speckle.connectors.dui": { - "type": "Project", - "dependencies": { - "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )", - "Speckle.Connectors.Common": "[1.0.0, )" - } - }, - "speckle.connectors.logging": { - "type": "Project" - }, - "Microsoft.Extensions.DependencyInjection": { - "type": "CentralTransitive", - "requested": "[2.2.0, )", - "resolved": "2.2.0", - "contentHash": "MZtBIwfDFork5vfjpJdG5g8wuJFt7d/y3LOSVVtDK/76wlbtz6cjltfKHqLx2TKVqTj5/c41t77m1+h20zqtPA==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0" - } - }, - "Microsoft.Extensions.Logging": { - "type": "CentralTransitive", - "requested": "[2.2.0, )", - "resolved": "2.2.0", - "contentHash": "Nxqhadc9FCmFHzU+fz3oc8sFlE6IadViYg8dfUdGzJZ2JUxnCsRghBhhOWdM4B2zSZqEc+0BjliBh/oNdRZuig==", - "dependencies": { - "Microsoft.Extensions.Configuration.Binder": "2.2.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", - "Microsoft.Extensions.Logging.Abstractions": "2.2.0", - "Microsoft.Extensions.Options": "2.2.0" - } - }, - "Microsoft.Extensions.Logging.Abstractions": { - "type": "CentralTransitive", - "requested": "[2.2.0, )", - "resolved": "2.2.0", - "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" - }, - "Speckle.DoubleNumerics": { - "type": "CentralTransitive", - "requested": "[4.1.0, )", - "resolved": "4.1.0", - "contentHash": "20DtS+FsDRsOD9+AU3TwNFZ0qrKo5f6f7B5ZR9wStsIHHHC9k7DpjbCvuNtmnSjx54MD+TJC7wV2f5iyGVPj1A==" - }, - "Speckle.Objects": { - "type": "CentralTransitive", - "requested": "[3.4.2, )", - "resolved": "3.4.2", - "contentHash": "2TcYsGm+vG5mpZj+fiwPJv/4wXtstrWb9FasxsQN2JdUNDKvg1/rVFE9Pby1tPWN+4J0X0QaXutGj0yNwLRe7w==", - "dependencies": { - "Speckle.Sdk": "3.4.2" - } - }, - "Speckle.Sdk": { - "type": "CentralTransitive", - "requested": "[3.4.2, )", - "resolved": "3.4.2", - "contentHash": "SOjUacHaCt+w19DhSgwQijhcwYZZSgmRVBOLk/O1Lwlq66cHVy3pzyBbsNR8zM+rVAtXrpahf60TjBg2EsD5Zg==", - "dependencies": { - "GraphQL.Client": "6.0.0", - "Microsoft.Bcl.AsyncInterfaces": "5.0.0", - "Microsoft.CSharp": "4.7.0", - "Microsoft.Data.Sqlite": "7.0.5", - "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", - "Microsoft.Extensions.Logging": "2.2.0", - "Speckle.DoubleNumerics": "4.1.0", - "Speckle.Newtonsoft.Json": "13.0.2", - "Speckle.Sdk.Dependencies": "3.4.2" - } - }, - "Speckle.Sdk.Dependencies": { - "type": "CentralTransitive", - "requested": "[3.4.2, )", - "resolved": "3.4.2", - "contentHash": "mYjR5i5zaNxkR2VXi2Ills3XG3VZ4z3wLSQBn7GldAudtxI8yS09M6w4ltFNcBmgLlnYHYiIbsWEilIGUbi0Nw==" - } - }, "net8.0-windows7.0": { "Microsoft.NETFramework.ReferenceAssemblies": { "type": "Direct", diff --git a/DUI3/Speckle.Connectors.DUI/Bindings/IBasicConnectorBinding.cs b/DUI3/Speckle.Connectors.DUI/Bindings/IBasicConnectorBinding.cs index 78e711d65..71b34770d 100644 --- a/DUI3/Speckle.Connectors.DUI/Bindings/IBasicConnectorBinding.cs +++ b/DUI3/Speckle.Connectors.DUI/Bindings/IBasicConnectorBinding.cs @@ -47,7 +47,7 @@ public class BasicConnectorBindingCommands private const string SET_MODEL_ERROR_UI_COMMAND_NAME = "setModelError"; public const string SET_GLOBAL_NOTIFICATION = "setGlobalNotification"; - protected IBrowserBridge Bridge { get; } + public IBrowserBridge Bridge { get; } public BasicConnectorBindingCommands(IBrowserBridge bridge) { diff --git a/DUI3/Speckle.Connectors.DUI/Bindings/ISendBindingUICommands.cs b/DUI3/Speckle.Connectors.DUI/Bindings/ISendBindingUICommands.cs index 13848f1a7..0fb6ddc10 100644 --- a/DUI3/Speckle.Connectors.DUI/Bindings/ISendBindingUICommands.cs +++ b/DUI3/Speckle.Connectors.DUI/Bindings/ISendBindingUICommands.cs @@ -1,10 +1,20 @@ +using Speckle.Connectors.Common.Conversion; +using Speckle.Connectors.DUI.Bridge; + namespace Speckle.Connectors.DUI.Bindings; public interface ISendBindingUICommands { - public void RefreshSendFilters(string frontEndName); + Task RefreshSendFilters(); - public void SetModelsExpired(string frontEndName, IEnumerable expiredModelIds); + Task SetModelsExpired(IEnumerable expiredModelIds); + Task SetModelError(string modelCardId, Exception exception); - public void SetModelCreatedVersionId(string frontEndName, string modelCardId, string versionId); + Task SetModelSendResult( + string modelCardId, + string versionId, + IEnumerable sendConversionResults + ); + + IBrowserBridge Bridge { get; } } diff --git a/DUI3/Speckle.Connectors.DUI/Bindings/ReceiveBindingUICommands.cs b/DUI3/Speckle.Connectors.DUI/Bindings/ReceiveBindingUICommands.cs index 2cabe20dd..c4be84630 100644 --- a/DUI3/Speckle.Connectors.DUI/Bindings/ReceiveBindingUICommands.cs +++ b/DUI3/Speckle.Connectors.DUI/Bindings/ReceiveBindingUICommands.cs @@ -3,7 +3,20 @@ using Speckle.Connectors.DUI.Bridge; namespace Speckle.Connectors.DUI.Bindings; -public sealed class ReceiveBindingUICommands : BasicConnectorBindingCommands +public interface IReceiveBindingUICommands +{ + Task SetModelError(string modelCardId, Exception exception); + + Task SetModelReceiveResult( + string modelCardId, + IEnumerable bakedObjectIds, + IEnumerable conversionResults + ); + + IBrowserBridge Bridge { get; } +} + +public sealed class ReceiveBindingUICommands : BasicConnectorBindingCommands, IReceiveBindingUICommands { // POC: put here events once we needed for receive specific private const string SET_MODEL_RECEIVE_RESULT_UI_COMMAND_NAME = "setModelReceiveResult"; diff --git a/DUI3/Speckle.Connectors.DUI/Bindings/ReceiveOperationManager.cs b/DUI3/Speckle.Connectors.DUI/Bindings/ReceiveOperationManager.cs new file mode 100644 index 000000000..a1d225348 --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Bindings/ReceiveOperationManager.cs @@ -0,0 +1,87 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Speckle.Connectors.Common.Builders; +using Speckle.Connectors.Common.Cancellation; +using Speckle.Connectors.Common.Operations; +using Speckle.Connectors.DUI.Logging; +using Speckle.Connectors.DUI.Models; +using Speckle.Connectors.DUI.Models.Card; +using Speckle.InterfaceGenerator; +using Speckle.Sdk; + +namespace Speckle.Connectors.DUI.Bindings; + +public partial interface IReceiveOperationManager : IDisposable; + +[GenerateAutoInterface] +public sealed class ReceiveOperationManager( + IServiceScope serviceScope, + ICancellationManager cancellationManager, + IDocumentModelStore store, + ISpeckleApplication speckleApplication, + IOperationProgressManager operationProgressManager, + ILogger logger +) : IReceiveOperationManager +{ + public async Task Process( + IReceiveBindingUICommands commands, + string modelCardId, + Action initializeScope, + Func>, Task> processor + ) + { + // Get receiver card + if (store.GetModelById(modelCardId) is not ReceiverModelCard modelCard) + { + // Handle as GLOBAL ERROR at BrowserBridge + throw new InvalidOperationException("No download model card was found."); + } + try + { + using var cancellationItem = cancellationManager.GetCancellationItem(modelCardId); + + initializeScope(serviceScope.ServiceProvider); + var progress = operationProgressManager.CreateOperationProgressEventHandler( + commands.Bridge, + modelCardId, + cancellationItem.Token + ); + var ro = serviceScope.ServiceProvider.GetRequiredService(); + var conversionResults = await processor( + modelCard.ModelName, + () => ro.Execute(modelCard.GetReceiveInfo(speckleApplication.Slug), progress, cancellationItem.Token) + ); + + if (conversionResults is null) + { + return; + } + + modelCard.BakedObjectIds = conversionResults.BakedObjectIds.ToList(); + await commands.SetModelReceiveResult( + modelCardId, + conversionResults.BakedObjectIds, + conversionResults.ConversionResults + ); + } + catch (OperationCanceledException) + { + // SWALLOW -> UI handles it immediately, so we do not need to handle anything for now! + // Idea for later -> when cancel called, create promise from UI to solve it later with this catch block. + // So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled + } + 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); + } + finally + { + // otherwise the id of the operation persists on the cancellation manager and triggers 'Operations cancelled because of document swap!' message to UI. + cancellationManager.CancelOperation(modelCardId); + } + } + + [AutoInterfaceIgnore] + public void Dispose() => serviceScope.Dispose(); +} diff --git a/DUI3/Speckle.Connectors.DUI/Bindings/ReceiveOperationManagerFactory.cs b/DUI3/Speckle.Connectors.DUI/Bindings/ReceiveOperationManagerFactory.cs new file mode 100644 index 000000000..26bfc1b1d --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Bindings/ReceiveOperationManagerFactory.cs @@ -0,0 +1,31 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Speckle.Connectors.Common.Cancellation; +using Speckle.Connectors.DUI.Models; +using Speckle.InterfaceGenerator; +using Speckle.Sdk; + +namespace Speckle.Connectors.DUI.Bindings; + +[GenerateAutoInterface] +public class ReceiveOperationManagerFactory( + IServiceProvider serviceProvider, + IOperationProgressManager operationProgressManager, + DocumentModelStore store, + ICancellationManager cancellationManager, + ISpeckleApplication speckleApplication, + ILoggerFactory loggerFactory +) : IReceiveOperationManagerFactory +{ + public IReceiveOperationManager Create() => + new ReceiveOperationManager( +#pragma warning disable CA2000 + serviceProvider.CreateScope(), +#pragma warning restore CA2000 + cancellationManager, + store, + speckleApplication, + operationProgressManager, + loggerFactory.CreateLogger() + ); +} diff --git a/DUI3/Speckle.Connectors.DUI/Bindings/SendBindingUICommands.cs b/DUI3/Speckle.Connectors.DUI/Bindings/SendBindingUICommands.cs index 45e3ff23f..eeafee7b3 100644 --- a/DUI3/Speckle.Connectors.DUI/Bindings/SendBindingUICommands.cs +++ b/DUI3/Speckle.Connectors.DUI/Bindings/SendBindingUICommands.cs @@ -4,7 +4,9 @@ using Speckle.Connectors.DUI.Bridge; namespace Speckle.Connectors.DUI.Bindings; // POC: Send Commands share all commands from BasicBindings + some, this pattern should be revised -public class SendBindingUICommands(IBrowserBridge bridge) : BasicConnectorBindingCommands(bridge) +public class SendBindingUICommands(IBrowserBridge bridge) + : BasicConnectorBindingCommands(bridge), + ISendBindingUICommands { private const string REFRESH_SEND_FILTERS_UI_COMMAND_NAME = "refreshSendFilters"; private const string SET_MODELS_EXPIRED_UI_COMMAND_NAME = "setModelsExpired"; diff --git a/DUI3/Speckle.Connectors.DUI/Bindings/SendOperationManager.cs b/DUI3/Speckle.Connectors.DUI/Bindings/SendOperationManager.cs new file mode 100644 index 000000000..a53d68ed0 --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Bindings/SendOperationManager.cs @@ -0,0 +1,106 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Speckle.Connectors.Common.Cancellation; +using Speckle.Connectors.Common.Operations; +using Speckle.Connectors.DUI.Exceptions; +using Speckle.Connectors.DUI.Logging; +using Speckle.Connectors.DUI.Models; +using Speckle.Connectors.DUI.Models.Card; +using Speckle.InterfaceGenerator; +using Speckle.Sdk; +using Speckle.Sdk.Logging; + +namespace Speckle.Connectors.DUI.Bindings; + +public partial interface ISendOperationManager : IDisposable; + +[GenerateAutoInterface] +public sealed class SendOperationManager( + IServiceScope serviceScope, + IOperationProgressManager operationProgressManager, + DocumentModelStore store, + ICancellationManager cancellationManager, + ISpeckleApplication speckleApplication, + ISdkActivityFactory activityFactory, + ILogger logger +) : ISendOperationManager +{ + public async Task Process( + ISendBindingUICommands commands, + string modelCardId, + Action initializeScope, + Func> gatherObjects + ) + { + await Process(commands, modelCardId, initializeScope, (card, _) => Task.FromResult(gatherObjects(card))); + } + + public async Task Process( + ISendBindingUICommands commands, + string modelCardId, + Action initializeScope, + Func>> gatherObjects + ) + { + await Process(commands, modelCardId, initializeScope, async (card, _) => await gatherObjects(card)); + } + + public async Task Process( + ISendBindingUICommands commands, + string modelCardId, + Action initializeScope, + Func, Task>> gatherObjects + ) + { + using var activity = activityFactory.Start(); + try + { + if (store.GetModelById(modelCardId) is not SenderModelCard modelCard) + { + // Handle as GLOBAL ERROR at BrowserBridge + throw new InvalidOperationException("No publish model card was found."); + } + + using var cancellationItem = cancellationManager.GetCancellationItem(modelCardId); + + initializeScope(serviceScope.ServiceProvider, modelCard); + + var progress = operationProgressManager.CreateOperationProgressEventHandler( + commands.Bridge, + modelCardId, + cancellationItem.Token + ); + + var objects = await gatherObjects(modelCard, progress); + + if (objects.Count == 0) + { + // Handle as CARD ERROR in this function + throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!"); + } + + var sendInfo = modelCard.GetSendInfo(speckleApplication.ApplicationAndVersion); + + var sendResult = await serviceScope + .ServiceProvider.GetRequiredService>() + .Execute(objects, sendInfo, progress, cancellationItem.Token); + + await commands.SetModelSendResult(modelCardId, sendResult.VersionId, sendResult.ConversionResults); + } + catch (OperationCanceledException) + { + // SWALLOW -> UI handles it immediately, so we do not need to handle anything for now! + // Idea for later -> when cancel called, create promise from UI to solve it later with this catch block. + // So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled + return; + } + 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); + } + } + + [AutoInterfaceIgnore] + public void Dispose() => serviceScope.Dispose(); +} diff --git a/DUI3/Speckle.Connectors.DUI/Bindings/SendOperationManagerFactory.cs b/DUI3/Speckle.Connectors.DUI/Bindings/SendOperationManagerFactory.cs new file mode 100644 index 000000000..082a66575 --- /dev/null +++ b/DUI3/Speckle.Connectors.DUI/Bindings/SendOperationManagerFactory.cs @@ -0,0 +1,34 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Speckle.Connectors.Common.Cancellation; +using Speckle.Connectors.DUI.Models; +using Speckle.InterfaceGenerator; +using Speckle.Sdk; +using Speckle.Sdk.Logging; + +namespace Speckle.Connectors.DUI.Bindings; + +[GenerateAutoInterface] +public class SendOperationManagerFactory( + IServiceProvider serviceProvider, + IOperationProgressManager operationProgressManager, + DocumentModelStore store, + ICancellationManager cancellationManager, + ISpeckleApplication speckleApplication, + ISdkActivityFactory activityFactory, + ILoggerFactory loggerFactory +) : ISendOperationManagerFactory +{ + public ISendOperationManager Create() => + new SendOperationManager( +#pragma warning disable CA2000 + serviceProvider.CreateScope(), +#pragma warning restore CA2000 + operationProgressManager, + store, + cancellationManager, + speckleApplication, + activityFactory, + loggerFactory.CreateLogger() + ); +} diff --git a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs index 15c90b734..201bcda9a 100644 --- a/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs +++ b/DUI3/Speckle.Connectors.DUI/ContainerRegistration.cs @@ -20,6 +20,7 @@ public static class ContainerRegistration // context always newed up on host app's main/ui thread serviceCollection.AddSingleton(new TThreadContext()); serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(sp => sp.GetService()); serviceCollection.AddTransient(); // POC: Each binding should have it's own bridge instance @@ -40,10 +41,13 @@ public static class ContainerRegistration { try { - serviceProvider - .GetRequiredService() - .CreateLogger("UnobservedTaskException") - .LogError(args.Exception, "Unobserved task exception"); + foreach (var exception in args.Exception.InnerExceptions) + { + if (TestAndLogStacktrace(serviceProvider, exception)) + { + args.SetObserved(); + } + } } #pragma warning disable CA1031 catch (Exception e) @@ -53,10 +57,25 @@ public static class ContainerRegistration Console.WriteLine(args.Exception); Console.WriteLine(e); } - finally - { - args.SetObserved(); - } }; } + + private static bool TestAndLogStacktrace(IServiceProvider serviceProvider, Exception exception) + { + var stackTrace = exception.ToString(); + if (stackTrace.IndexOf("Speckle", StringComparison.InvariantCultureIgnoreCase) <= 0) + { + serviceProvider + .GetRequiredService() + .CreateLogger("UnobservedTaskException") + .LogInformation(exception, "Non-Speckle unobserved task exception"); + return false; + } + + serviceProvider + .GetRequiredService() + .CreateLogger("UnobservedTaskException") + .LogError(exception, "Unobserved task exception"); + return true; + } } diff --git a/DUI3/Speckle.Connectors.DUI/Logging/BindingErrorLogging.cs b/DUI3/Speckle.Connectors.DUI/Logging/BindingErrorLogging.cs index f8405d76b..b7a976828 100644 --- a/DUI3/Speckle.Connectors.DUI/Logging/BindingErrorLogging.cs +++ b/DUI3/Speckle.Connectors.DUI/Logging/BindingErrorLogging.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.Logging; -using Speckle.Connectors.DUI.Bindings; using Speckle.Sdk; namespace Speckle.Connectors.DUI.Logging; @@ -13,7 +12,6 @@ namespace Speckle.Connectors.DUI.Logging; public static class HandledModelCardErrors { public static void LogModelCardHandledError(this ILogger logger, Exception ex) - where T : IBinding { LogLevel level = ex switch { diff --git a/DUI3/Speckle.Connectors.DUI/Models/DocumentModelStore.cs b/DUI3/Speckle.Connectors.DUI/Models/DocumentModelStore.cs index bdb0e2b3f..53d821d6d 100644 --- a/DUI3/Speckle.Connectors.DUI/Models/DocumentModelStore.cs +++ b/DUI3/Speckle.Connectors.DUI/Models/DocumentModelStore.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using Microsoft.Extensions.Logging; using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.DUI.Utils; +using Speckle.InterfaceGenerator; using Speckle.Sdk; using Speckle.Sdk.Common; @@ -10,7 +11,9 @@ namespace Speckle.Connectors.DUI.Models; /// /// Encapsulates the state Speckle needs to persist in the host app's document. /// +[GenerateAutoInterface] public abstract class DocumentModelStore(ILogger logger, IJsonSerializer serializer) + : IDocumentModelStore { private readonly List _models = new(); diff --git a/DUI3/Speckle.Connectors.DUI/Speckle.Connectors.DUI.csproj b/DUI3/Speckle.Connectors.DUI/Speckle.Connectors.DUI.csproj index 5be4104fe..0d08e6b96 100644 --- a/DUI3/Speckle.Connectors.DUI/Speckle.Connectors.DUI.csproj +++ b/DUI3/Speckle.Connectors.DUI/Speckle.Connectors.DUI.csproj @@ -1,7 +1,7 @@  - net48;net6.0;net8.0 + net48;net8.0 Debug;Release;Local diff --git a/DUI3/Speckle.Connectors.DUI/packages.lock.json b/DUI3/Speckle.Connectors.DUI/packages.lock.json index 8d176a623..535a03ef3 100644 --- a/DUI3/Speckle.Connectors.DUI/packages.lock.json +++ b/DUI3/Speckle.Connectors.DUI/packages.lock.json @@ -327,293 +327,6 @@ "contentHash": "mYjR5i5zaNxkR2VXi2Ills3XG3VZ4z3wLSQBn7GldAudtxI8yS09M6w4ltFNcBmgLlnYHYiIbsWEilIGUbi0Nw==" } }, - "net6.0": { - "Microsoft.Extensions.Logging.Abstractions": { - "type": "Direct", - "requested": "[2.2.0, )", - "resolved": "2.2.0", - "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" - }, - "Microsoft.NETFramework.ReferenceAssemblies": { - "type": "Direct", - "requested": "[1.0.3, )", - "resolved": "1.0.3", - "contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==", - "dependencies": { - "Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3" - } - }, - "Microsoft.SourceLink.GitHub": { - "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "8.0.0", - "Microsoft.SourceLink.Common": "8.0.0" - } - }, - "PolySharp": { - "type": "Direct", - "requested": "[1.14.1, )", - "resolved": "1.14.1", - "contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ==" - }, - "Speckle.InterfaceGenerator": { - "type": "Direct", - "requested": "[0.9.6, )", - "resolved": "0.9.6", - "contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w==" - }, - "GraphQL.Client": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "8yPNBbuVBpTptivyAlak4GZvbwbUcjeQTL4vN1HKHRuOykZ4r7l5fcLS6vpyPyLn0x8FsL31xbOIKyxbmR9rbA==", - "dependencies": { - "GraphQL.Client.Abstractions": "6.0.0", - "GraphQL.Client.Abstractions.Websocket": "6.0.0", - "System.Reactive": "5.0.0" - } - }, - "GraphQL.Client.Abstractions": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "h7uzWFORHZ+CCjwr/ThAyXMr0DPpzEANDa4Uo54wqCQ+j7qUKwqYTgOrb1W40sqbvNaZm9v/X7It31SUw0maHA==", - "dependencies": { - "GraphQL.Primitives": "6.0.0" - } - }, - "GraphQL.Client.Abstractions.Websocket": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "Nr9bPf8gIOvLuXpqEpqr9z9jslYFJOvd0feHth3/kPqeR3uMbjF5pjiwh4jxyMcxHdr8Pb6QiXkV3hsSyt0v7A==", - "dependencies": { - "GraphQL.Client.Abstractions": "6.0.0" - } - }, - "GraphQL.Primitives": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "yg72rrYDapfsIUrul7aF6wwNnTJBOFvuA9VdDTQpPa8AlAriHbufeXYLBcodKjfUdkCnaiggX1U/nEP08Zb5GA==" - }, - "Microsoft.Bcl.AsyncInterfaces": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==" - }, - "Microsoft.Build.Tasks.Git": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ==" - }, - "Microsoft.CSharp": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA==" - }, - "Microsoft.Data.Sqlite": { - "type": "Transitive", - "resolved": "7.0.5", - "contentHash": "KGxbPeWsQMnmQy43DSBxAFtHz3l2JX8EWBSGUCvT3CuZ8KsuzbkqMIJMDOxWtG8eZSoCDI04aiVQjWuuV8HmSw==", - "dependencies": { - "Microsoft.Data.Sqlite.Core": "7.0.5", - "SQLitePCLRaw.bundle_e_sqlite3": "2.1.4" - } - }, - "Microsoft.Data.Sqlite.Core": { - "type": "Transitive", - "resolved": "7.0.5", - "contentHash": "FTerRmQPqHrCrnoUzhBu+E+1DNGwyrAMLqHkAqOOOu5pGfyMOj8qQUBxI/gDtWtG11p49UxSfWmBzRNlwZqfUg==", - "dependencies": { - "SQLitePCLRaw.core": "2.1.4" - } - }, - "Microsoft.Extensions.Configuration": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "nOP8R1mVb/6mZtm2qgAJXn/LFm/2kMjHDAg/QJLFG6CuWYJtaD3p1BwQhufBVvRzL9ceJ/xF0SQ0qsI2GkDQAA==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "2.2.0" - } - }, - "Microsoft.Extensions.Configuration.Abstractions": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "65MrmXCziWaQFrI0UHkQbesrX5wTwf9XPjY5yFm/VkgJKFJ5gqvXRoXjIZcf2wLi5ZlwGz/oMYfyURVCWbM5iw==", - "dependencies": { - "Microsoft.Extensions.Primitives": "2.2.0" - } - }, - "Microsoft.Extensions.Configuration.Binder": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "vJ9xvOZCnUAIHcGC3SU35r3HKmHTVIeHzo6u/qzlHAqD8m6xv92MLin4oJntTvkpKxVX3vI1GFFkIQtU3AdlsQ==", - "dependencies": { - "Microsoft.Extensions.Configuration": "2.2.0" - } - }, - "Microsoft.Extensions.DependencyInjection.Abstractions": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw==" - }, - "Microsoft.Extensions.Options": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "UpZLNLBpIZ0GTebShui7xXYh6DmBHjWM8NxGxZbdQh/bPZ5e6YswqI+bru6BnEL5eWiOdodsXtEz3FROcgi/qg==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", - "Microsoft.Extensions.Primitives": "2.2.0", - "System.ComponentModel.Annotations": "4.5.0" - } - }, - "Microsoft.Extensions.Primitives": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "azyQtqbm4fSaDzZHD/J+V6oWMFaf2tWP4WEGIYePLCMw3+b2RQdj9ybgbQyjCshcitQKQ4lEDOZjmSlTTrHxUg==", - "dependencies": { - "System.Memory": "4.5.1", - "System.Runtime.CompilerServices.Unsafe": "4.5.1" - } - }, - "Microsoft.NETFramework.ReferenceAssemblies.net461": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA==" - }, - "Microsoft.SourceLink.Common": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" - }, - "Speckle.Newtonsoft.Json": { - "type": "Transitive", - "resolved": "13.0.2", - "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" - }, - "SQLitePCLRaw.bundle_e_sqlite3": { - "type": "Transitive", - "resolved": "2.1.4", - "contentHash": "EWI1olKDjFEBMJu0+3wuxwziIAdWDVMYLhuZ3Qs84rrz+DHwD00RzWPZCa+bLnHCf3oJwuFZIRsHT5p236QXww==", - "dependencies": { - "SQLitePCLRaw.lib.e_sqlite3": "2.1.4", - "SQLitePCLRaw.provider.e_sqlite3": "2.1.4" - } - }, - "SQLitePCLRaw.core": { - "type": "Transitive", - "resolved": "2.1.4", - "contentHash": "inBjvSHo9UDKneGNzfUfDjK08JzlcIhn1+SP5Y3m6cgXpCxXKCJDy6Mka7LpgSV+UZmKSnC8rTwB0SQ0xKu5pA==", - "dependencies": { - "System.Memory": "4.5.3" - } - }, - "SQLitePCLRaw.lib.e_sqlite3": { - "type": "Transitive", - "resolved": "2.1.4", - "contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg==" - }, - "SQLitePCLRaw.provider.e_sqlite3": { - "type": "Transitive", - "resolved": "2.1.4", - "contentHash": "CSlb5dUp1FMIkez9Iv5EXzpeq7rHryVNqwJMWnpq87j9zWZexaEMdisDktMsnnrzKM6ahNrsTkjqNodTBPBxtQ==", - "dependencies": { - "SQLitePCLRaw.core": "2.1.4" - } - }, - "System.ComponentModel.Annotations": { - "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==" - }, - "System.Memory": { - "type": "Transitive", - "resolved": "4.5.3", - "contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==" - }, - "System.Reactive": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==" - }, - "System.Runtime.CompilerServices.Unsafe": { - "type": "Transitive", - "resolved": "4.5.1", - "contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw==" - }, - "speckle.connectors.common": { - "type": "Project", - "dependencies": { - "Microsoft.Extensions.DependencyInjection": "[2.2.0, )", - "Speckle.Connectors.Logging": "[1.0.0, )", - "Speckle.Objects": "[3.4.2, )", - "Speckle.Sdk": "[3.4.2, )", - "Speckle.Sdk.Dependencies": "[3.4.2, )" - } - }, - "speckle.connectors.logging": { - "type": "Project" - }, - "Microsoft.Extensions.DependencyInjection": { - "type": "CentralTransitive", - "requested": "[2.2.0, )", - "resolved": "2.2.0", - "contentHash": "MZtBIwfDFork5vfjpJdG5g8wuJFt7d/y3LOSVVtDK/76wlbtz6cjltfKHqLx2TKVqTj5/c41t77m1+h20zqtPA==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0" - } - }, - "Microsoft.Extensions.Logging": { - "type": "CentralTransitive", - "requested": "[2.2.0, )", - "resolved": "2.2.0", - "contentHash": "Nxqhadc9FCmFHzU+fz3oc8sFlE6IadViYg8dfUdGzJZ2JUxnCsRghBhhOWdM4B2zSZqEc+0BjliBh/oNdRZuig==", - "dependencies": { - "Microsoft.Extensions.Configuration.Binder": "2.2.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", - "Microsoft.Extensions.Logging.Abstractions": "2.2.0", - "Microsoft.Extensions.Options": "2.2.0" - } - }, - "Speckle.DoubleNumerics": { - "type": "CentralTransitive", - "requested": "[4.1.0, )", - "resolved": "4.1.0", - "contentHash": "20DtS+FsDRsOD9+AU3TwNFZ0qrKo5f6f7B5ZR9wStsIHHHC9k7DpjbCvuNtmnSjx54MD+TJC7wV2f5iyGVPj1A==" - }, - "Speckle.Objects": { - "type": "CentralTransitive", - "requested": "[3.4.2, )", - "resolved": "3.4.2", - "contentHash": "2TcYsGm+vG5mpZj+fiwPJv/4wXtstrWb9FasxsQN2JdUNDKvg1/rVFE9Pby1tPWN+4J0X0QaXutGj0yNwLRe7w==", - "dependencies": { - "Speckle.Sdk": "3.4.2" - } - }, - "Speckle.Sdk": { - "type": "CentralTransitive", - "requested": "[3.4.2, )", - "resolved": "3.4.2", - "contentHash": "SOjUacHaCt+w19DhSgwQijhcwYZZSgmRVBOLk/O1Lwlq66cHVy3pzyBbsNR8zM+rVAtXrpahf60TjBg2EsD5Zg==", - "dependencies": { - "GraphQL.Client": "6.0.0", - "Microsoft.Bcl.AsyncInterfaces": "5.0.0", - "Microsoft.CSharp": "4.7.0", - "Microsoft.Data.Sqlite": "7.0.5", - "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", - "Microsoft.Extensions.Logging": "2.2.0", - "Speckle.DoubleNumerics": "4.1.0", - "Speckle.Newtonsoft.Json": "13.0.2", - "Speckle.Sdk.Dependencies": "3.4.2" - } - }, - "Speckle.Sdk.Dependencies": { - "type": "CentralTransitive", - "requested": "[3.4.2, )", - "resolved": "3.4.2", - "contentHash": "mYjR5i5zaNxkR2VXi2Ills3XG3VZ4z3wLSQBn7GldAudtxI8yS09M6w4ltFNcBmgLlnYHYiIbsWEilIGUbi0Nw==" - } - }, "net8.0": { "Microsoft.Extensions.Logging.Abstractions": { "type": "Direct", diff --git a/Importers/Ifc/Speckle.Importers.Ifc.Tester2/IfcTester.cs b/Importers/Ifc/Speckle.Importers.Ifc.Tester2/IfcTester.cs index ce4cb9e51..e1c9a75c1 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc.Tester2/IfcTester.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc.Tester2/IfcTester.cs @@ -1,6 +1,7 @@ using Ara3D.Utils; using Speckle.Sdk.Api; using Speckle.Sdk.Credentials; +using Speckle.Sdk.Models.Extensions; namespace Speckle.Importers.Ifc.Tester2; @@ -16,7 +17,10 @@ public sealed class IfcTester(IClientFactory clientFactory, Importer importer, I { // Settings, Change these to suit! // private readonly ICollection _filePath = [new(@"C:\Users\Jedd\Desktop\GRAPHISOFT_Archicad_Sample_Project-S-Office_v1.0_AC25.ifc")] - private readonly IEnumerable _filePaths = Directory.EnumerateFiles(@"C:\Users\Jedd\Desktop\", "*.ifc"); + private readonly IEnumerable _filePaths = Directory.EnumerateFiles( + @"C:\Users\Jedd\Desktop\big files", + "*.ifc" + ); private readonly Uri _serverUrl = new("https://app.speckle.systems"); private const string PROJECT_ID = "f3a42bdf24"; @@ -28,7 +32,16 @@ public sealed class IfcTester(IClientFactory clientFactory, Importer importer, I foreach (var path in _filePaths) { - await ImportFile(speckleClient, path, cancellationToken); + try + { + await ImportFile(speckleClient, path, cancellationToken); + } +#pragma warning disable CA1031 + catch (Exception ex) +#pragma warning restore CA1031 + { + Console.WriteLine(ex.ToFormattedString()); + } } } diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Converters/GraphConverter.cs b/Importers/Ifc/Speckle.Importers.Ifc/Converters/GraphConverter.cs index d0b1a7dce..5bf855076 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/Converters/GraphConverter.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/Converters/GraphConverter.cs @@ -12,11 +12,17 @@ public sealed class GraphConverter(INodeConverter nodeConverter, IRenderMaterial { public Base Convert(IfcModel model, IfcGraph graph) { - Base rootCollection = nodeConverter.Convert(model, graph.GetIfcProject()); + try + { + Base rootCollection = nodeConverter.Convert(model, graph.GetIfcProject()); - //Grabing materials from ProxyManager - rootCollection["renderMaterialProxies"] = proxyManager.RenderMaterialProxies.Values.ToList(); - - return rootCollection; + //Grabing materials from ProxyManager + rootCollection["renderMaterialProxies"] = proxyManager.RenderMaterialProxies.Values.ToList(); + return rootCollection; + } + finally + { + proxyManager.Clear(); + } } } diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Importer.cs b/Importers/Ifc/Speckle.Importers.Ifc/Importer.cs index 3a9a59de2..93977d132 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/Importer.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/Importer.cs @@ -38,13 +38,16 @@ public sealed class Importer( CancellationToken cancellationToken ) { + var filePath = new FilePath(args.FilePath); var stopwatch = Stopwatch.StartNew(); - var ifcModel = ifcFactory.Open(args.FilePath); + Console.WriteLine($"Starting processing file : {filePath.GetFileName()}"); + + var ifcModel = ifcFactory.Open(filePath); var ms = stopwatch.ElapsedMilliseconds; Console.WriteLine($"Opened with WebIFC: {ms} ms"); - var graph = IfcGraph.Load(new FilePath(args.FilePath)); + var graph = IfcGraph.Load(filePath); var ms2 = stopwatch.ElapsedMilliseconds; Console.WriteLine($"Loaded with StepParser: {ms2 - ms} ms"); @@ -90,7 +93,15 @@ public sealed class Importer( ); ms = ms2; ms2 = stopwatch.ElapsedMilliseconds; - Console.WriteLine($"Committed to Speckle: {ms2 - ms} ms"); + + Console.WriteLine($"Committed to Speckle: {ms2 - ms} ms - {GetUrl(speckleVersion, modelId)}"); + Console.WriteLine(); + return speckleVersion; } + + private static string GetUrl(Version version, string modelId) + { + return version.previewUrl.ToString().Replace("preview", "projects").Replace("commits/", $"models/{modelId}@"); + } } diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Services/RenderMaterialProxyManager.cs b/Importers/Ifc/Speckle.Importers.Ifc/Services/RenderMaterialProxyManager.cs index 643401f43..0f5d6b81e 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/Services/RenderMaterialProxyManager.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/Services/RenderMaterialProxyManager.cs @@ -10,6 +10,8 @@ public sealed class RenderMaterialProxyManager : IRenderMaterialProxyManager { public Dictionary RenderMaterialProxies { get; } = new(); + public void Clear() => RenderMaterialProxies.Clear(); + public void AddMeshMapping(RenderMaterial renderMaterial, Mesh mesh) { string materialId = renderMaterial.applicationId.NotNull(); diff --git a/Local.sln b/Local.sln index 00fc21719..4d6f7797c 100644 --- a/Local.sln +++ b/Local.sln @@ -303,11 +303,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Performance", "Sdk\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Testing", "Sdk\Speckle.Testing\Speckle.Testing.csproj", "{02E79865-6261-CDE0-77EA-3DD2E01DACBD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Objects", "..\speckle-sharp-sdk\src\Speckle.Objects\Speckle.Objects.csproj", "{FBD58ABD-9704-C232-7CF3-D96EC5CFCBE6}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "..\speckle-sharp-sdk\src\Speckle.Objects\Speckle.Objects", "..\speckle-sharp-sdk\src\Speckle.Objects\Speckle.Objects.csproj", "{FBD58ABD-9704-C232-7CF3-D96EC5CFCBE6}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Sdk", "..\speckle-sharp-sdk\src\Speckle.Sdk\Speckle.Sdk.csproj", "{0201A282-BEFA-8897-C535-03EBAC94870B}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "..\speckle-sharp-sdk\src\Speckle.Sdk\Speckle.Sdk", "..\speckle-sharp-sdk\src\Speckle.Sdk\Speckle.Sdk.csproj", "{0201A282-BEFA-8897-C535-03EBAC94870B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Sdk.Dependencies", "..\speckle-sharp-sdk\src\Speckle.Sdk.Dependencies\Speckle.Sdk.Dependencies.csproj", "{0677CA87-027F-D526-4463-3517F75B76EC}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "..\speckle-sharp-sdk\src\Speckle.Sdk.Dependencies\Speckle.Sdk.Dependencies", "..\speckle-sharp-sdk\src\Speckle.Sdk.Dependencies\Speckle.Sdk.Dependencies.csproj", "{0677CA87-027F-D526-4463-3517F75B76EC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/Local.slnx b/Local.slnx index 88c6bf7fe..949ebc9c6 100644 --- a/Local.slnx +++ b/Local.slnx @@ -196,7 +196,7 @@ - - - + + + \ No newline at end of file diff --git a/Sdk/Speckle.Common.MeshTriangulation/Speckle.Common.MeshTriangulation.csproj b/Sdk/Speckle.Common.MeshTriangulation/Speckle.Common.MeshTriangulation.csproj index b154f54f0..643d80fc9 100644 --- a/Sdk/Speckle.Common.MeshTriangulation/Speckle.Common.MeshTriangulation.csproj +++ b/Sdk/Speckle.Common.MeshTriangulation/Speckle.Common.MeshTriangulation.csproj @@ -1,7 +1,7 @@  - net48;net6.0;net8.0 + net48;net8.0 Debug;Release;Local diff --git a/Sdk/Speckle.Common.MeshTriangulation/packages.lock.json b/Sdk/Speckle.Common.MeshTriangulation/packages.lock.json index b4abae136..f69104c46 100644 --- a/Sdk/Speckle.Common.MeshTriangulation/packages.lock.json +++ b/Sdk/Speckle.Common.MeshTriangulation/packages.lock.json @@ -61,66 +61,6 @@ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" } }, - "net6.0": { - "LibTessDotNet": { - "type": "Direct", - "requested": "[1.1.15, )", - "resolved": "1.1.15", - "contentHash": "KuA7N3Nv/lIeawJdQBQJR6oqWD9KETHLbWzBqapwFs+Tby+R5I4crkKujKMm5bXcSuFZ8LNtflFQVadsWCbBjg==" - }, - "Microsoft.NETFramework.ReferenceAssemblies": { - "type": "Direct", - "requested": "[1.0.3, )", - "resolved": "1.0.3", - "contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==", - "dependencies": { - "Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3" - } - }, - "Microsoft.SourceLink.GitHub": { - "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "8.0.0", - "Microsoft.SourceLink.Common": "8.0.0" - } - }, - "PolySharp": { - "type": "Direct", - "requested": "[1.14.1, )", - "resolved": "1.14.1", - "contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ==" - }, - "Speckle.DoubleNumerics": { - "type": "Direct", - "requested": "[4.1.0, )", - "resolved": "4.1.0", - "contentHash": "20DtS+FsDRsOD9+AU3TwNFZ0qrKo5f6f7B5ZR9wStsIHHHC9k7DpjbCvuNtmnSjx54MD+TJC7wV2f5iyGVPj1A==" - }, - "Speckle.InterfaceGenerator": { - "type": "Direct", - "requested": "[0.9.6, )", - "resolved": "0.9.6", - "contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w==" - }, - "Microsoft.Build.Tasks.Git": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ==" - }, - "Microsoft.NETFramework.ReferenceAssemblies.net461": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA==" - }, - "Microsoft.SourceLink.Common": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" - } - }, "net8.0": { "LibTessDotNet": { "type": "Direct", diff --git a/Sdk/Speckle.Connectors.Common.Tests/Operations/ReceiveConversionHandlerTests.cs b/Sdk/Speckle.Connectors.Common.Tests/Operations/ReceiveConversionHandlerTests.cs new file mode 100644 index 000000000..e90a151f3 --- /dev/null +++ b/Sdk/Speckle.Connectors.Common.Tests/Operations/ReceiveConversionHandlerTests.cs @@ -0,0 +1,73 @@ +using FluentAssertions; +using Moq; +using NUnit.Framework; +using Speckle.Connectors.Common.Operations; +using Speckle.Sdk.Common.Exceptions; +using Speckle.Sdk.Logging; + +namespace Speckle.Connectors.Common.Tests.Operations; + +public class ReceiveConversionHandlerTests +{ + [Test] + public void TryConvert_ReturnsNullOnSuccess() + { + var activityFactory = new Mock(); + var activity = new Mock(); + activityFactory.Setup(f => f.Start(It.IsAny(), It.IsAny())).Returns(activity.Object); + var handler = new ReceiveConversionHandler(activityFactory.Object); + + Exception? result = handler.TryConvert( + () => { /* success */ + } + ); + + result.Should().BeNull(); + activity.Verify(a => a.SetStatus(SdkActivityStatusCode.Ok), Times.Once); + } + + [Test] + public void TryConvert_ReturnsConversionException() + { + var activityFactory = new Mock(); + var activity = new Mock(); + activityFactory.Setup(f => f.Start(It.IsAny(), It.IsAny())).Returns(activity.Object); + var handler = new ReceiveConversionHandler(activityFactory.Object); + var ex = new ConversionException("fail"); + + Exception? result = handler.TryConvert(() => throw ex); + + result.Should().Be(ex); + activity.Verify(a => a.SetStatus(SdkActivityStatusCode.Error), Times.Once); + } + + [Test] + public void TryConvert_ThrowsOperationCanceledException() + { + var activityFactory = new Mock(); + var activity = new Mock(); + activityFactory.Setup(f => f.Start(It.IsAny(), It.IsAny())).Returns(activity.Object); + var handler = new ReceiveConversionHandler(activityFactory.Object); + + Assert.Throws(() => handler.TryConvert(() => throw new OperationCanceledException())); + activity.Verify(a => a.SetStatus(SdkActivityStatusCode.Error), Times.Once); + } + + [Test] + public void TryConvert_ReturnsNonFatalException() + { + var activityFactory = new Mock(); + var activity = new Mock(); + activityFactory.Setup(f => f.Start(It.IsAny(), It.IsAny())).Returns(activity.Object); + var handler = new ReceiveConversionHandler(activityFactory.Object); +#pragma warning disable CA2201 + var ex = new Exception("non-fatal"); +#pragma warning restore CA2201 + + Exception? result = handler.TryConvert(() => throw ex); + + result.Should().Be(ex); + activity.Verify(a => a.SetStatus(SdkActivityStatusCode.Error), Times.Once); + activity.Verify(a => a.RecordException(ex), Times.Once); + } +} diff --git a/Sdk/Speckle.Connectors.Common.Tests/Operations/SendProgressTests.cs b/Sdk/Speckle.Connectors.Common.Tests/Operations/SendProgressTests.cs index 3ad5a310b..5c10f566e 100644 --- a/Sdk/Speckle.Connectors.Common.Tests/Operations/SendProgressTests.cs +++ b/Sdk/Speckle.Connectors.Common.Tests/Operations/SendProgressTests.cs @@ -35,6 +35,8 @@ public class SendProgressTests : MoqTest case ProgressEvent.FindingChildren: sendProgressState.SetupSet(x => x.Total = args.Count); break; + case ProgressEvent.UploadingObjects: + break; } displayManager.Setup(x => x.ShouldUpdate()).Returns(shouldUpdate); @@ -44,6 +46,7 @@ public class SendProgressTests : MoqTest { switch (e) { + case ProgressEvent.UploadingObjects: case ProgressEvent.UploadBytes: sendProgressState.Setup(x => x.PreviouslyFromCacheOrSerialized).Returns(previousFromCacheOrSerialized); if (previousFromCacheOrSerialized) diff --git a/Sdk/Speckle.Connectors.Common/Operations/ReceiveConversionHandler.cs b/Sdk/Speckle.Connectors.Common/Operations/ReceiveConversionHandler.cs new file mode 100644 index 000000000..81cbeb152 --- /dev/null +++ b/Sdk/Speckle.Connectors.Common/Operations/ReceiveConversionHandler.cs @@ -0,0 +1,39 @@ +using Speckle.InterfaceGenerator; +using Speckle.Sdk; +using Speckle.Sdk.Common.Exceptions; +using Speckle.Sdk.Logging; + +namespace Speckle.Connectors.Common.Operations; + +[GenerateAutoInterface] +public class ReceiveConversionHandler(ISdkActivityFactory activityFactory) : IReceiveConversionHandler +{ + public Exception? TryConvert(Action conversion) + { + using var convertActivity = activityFactory.Start("Converting object"); + try + { + conversion(); + convertActivity?.SetStatus(SdkActivityStatusCode.Ok); + return null; + } + catch (ConversionException ce) + { + //handle conversions but don't log to seq + convertActivity?.SetStatus(SdkActivityStatusCode.Error); + return ce; + } + catch (OperationCanceledException) + { + //handle conversions but don't log to seq and also throw + convertActivity?.SetStatus(SdkActivityStatusCode.Error); + throw; + } + catch (Exception ex) when (!ex.IsFatal()) + { + convertActivity?.SetStatus(SdkActivityStatusCode.Error); + convertActivity?.RecordException(ex); + return ex; + } + } +} diff --git a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs index b4981104d..2c488b637 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/ReceiveOperation.cs @@ -1,6 +1,7 @@ using Speckle.Connectors.Common.Builders; using Speckle.Connectors.Common.Threading; using Speckle.Connectors.Logging; +using Speckle.InterfaceGenerator; using Speckle.Sdk; using Speckle.Sdk.Api; using Speckle.Sdk.Credentials; @@ -10,6 +11,7 @@ using Speckle.Sdk.Models.Extensions; namespace Speckle.Connectors.Common.Operations; +[GenerateAutoInterface] public sealed class ReceiveOperation( IHostObjectBuilder hostObjectBuilder, IAccountService accountService, @@ -18,7 +20,7 @@ public sealed class ReceiveOperation( IOperations operations, IReceiveVersionRetriever receiveVersionRetriever, IThreadContext threadContext -) +) : IReceiveOperation { public async Task Execute( ReceiveInfo receiveInfo, @@ -102,6 +104,12 @@ public sealed class ReceiveOperation( conversionActivity?.SetStatus(SdkActivityStatusCode.Ok); return res; } + catch (OperationCanceledException) + { + //handle conversions but don't log to seq and also throw + conversionActivity?.SetStatus(SdkActivityStatusCode.Error); + throw; + } catch (Exception ex) { conversionActivity?.RecordException(ex); diff --git a/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs b/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs index 82fca2f3a..2c478153d 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/SendOperation.cs @@ -3,6 +3,7 @@ using Speckle.Connectors.Common.Caching; using Speckle.Connectors.Common.Conversion; using Speckle.Connectors.Common.Threading; using Speckle.Connectors.Logging; +using Speckle.InterfaceGenerator; using Speckle.Sdk.Api; using Speckle.Sdk.Credentials; using Speckle.Sdk.Logging; @@ -12,6 +13,7 @@ using Speckle.Sdk.Serialisation.V2.Send; namespace Speckle.Connectors.Common.Operations; +[GenerateAutoInterface] public sealed class SendOperation( IRootObjectBuilder rootObjectBuilder, ISendConversionCache sendConversionCache, @@ -21,7 +23,7 @@ public sealed class SendOperation( ISendOperationVersionRecorder sendOperationVersionRecorder, ISdkActivityFactory activityFactory, IThreadContext threadContext -) +) : ISendOperation { public async Task Execute( IReadOnlyList objects, diff --git a/Sdk/Speckle.Connectors.Common/Operations/SendProgress.cs b/Sdk/Speckle.Connectors.Common/Operations/SendProgress.cs index e3ad77971..5c1ac53e8 100644 --- a/Sdk/Speckle.Connectors.Common/Operations/SendProgress.cs +++ b/Sdk/Speckle.Connectors.Common/Operations/SendProgress.cs @@ -14,23 +14,27 @@ public class SendProgressState : ISendProgressState public class SendProgress(IProgressDisplayManager progressDisplayManager, ISendProgressState sendProgressState) : ISendProgress { - private string? _previousSpeed; + private string _previousSpeed = "unknown"; + private double _previousUploaded; public void Begin() => progressDisplayManager.Begin(); public void Report(IProgress onOperationProgressed, ProgressArgs args) { - if (args.ProgressEvent == ProgressEvent.FromCacheOrSerialized) + switch (args.ProgressEvent) { - sendProgressState.PreviouslyFromCacheOrSerialized = args.Count >= args.Total; - } - else if (args.ProgressEvent == ProgressEvent.FindingChildren) - { - sendProgressState.Total = args.Count; - } - else if (args.ProgressEvent == ProgressEvent.UploadBytes) - { - _previousSpeed = progressDisplayManager.CalculateSpeed(args); + case ProgressEvent.FromCacheOrSerialized: + sendProgressState.PreviouslyFromCacheOrSerialized = args.Count >= args.Total; + break; + case ProgressEvent.FindingChildren: + sendProgressState.Total = args.Count; + break; + case ProgressEvent.UploadBytes: + _previousSpeed = progressDisplayManager.CalculateSpeed(args); + break; + case ProgressEvent.UploadingObjects: + _previousUploaded = args.Count; + break; } if (!progressDisplayManager.ShouldUpdate()) { @@ -48,12 +52,13 @@ public class SendProgress(IProgressDisplayManager progressDisplayManager, ISendP new($"Caching... ({args.Count} objects)", progressDisplayManager.CalculatePercentage(args)) ); break; + case ProgressEvent.UploadingObjects: case ProgressEvent.UploadBytes: if (!sendProgressState.PreviouslyFromCacheOrSerialized) { return; } - onOperationProgressed.Report(new($"Uploading... ({_previousSpeed})", null)); + onOperationProgressed.Report(new($"Uploading... {_previousUploaded} ({_previousSpeed})", null)); break; case ProgressEvent.FromCacheOrSerialized: var message = $"Serializing... ({args.Count} / {sendProgressState.Total} found objects)"; diff --git a/Sdk/Speckle.Connectors.Common/Speckle.Connectors.Common.csproj b/Sdk/Speckle.Connectors.Common/Speckle.Connectors.Common.csproj index 8915acf68..8c563953b 100644 --- a/Sdk/Speckle.Connectors.Common/Speckle.Connectors.Common.csproj +++ b/Sdk/Speckle.Connectors.Common/Speckle.Connectors.Common.csproj @@ -1,7 +1,7 @@ - net48;net6.0;net8.0 + net48;net8.0 Debug;Release;Local diff --git a/Sdk/Speckle.Connectors.Common/packages.lock.json b/Sdk/Speckle.Connectors.Common/packages.lock.json index 6a0358924..dd3e19393 100644 --- a/Sdk/Speckle.Connectors.Common/packages.lock.json +++ b/Sdk/Speckle.Connectors.Common/packages.lock.json @@ -317,283 +317,6 @@ "contentHash": "20DtS+FsDRsOD9+AU3TwNFZ0qrKo5f6f7B5ZR9wStsIHHHC9k7DpjbCvuNtmnSjx54MD+TJC7wV2f5iyGVPj1A==" } }, - "net6.0": { - "Microsoft.Extensions.DependencyInjection": { - "type": "Direct", - "requested": "[2.2.0, )", - "resolved": "2.2.0", - "contentHash": "MZtBIwfDFork5vfjpJdG5g8wuJFt7d/y3LOSVVtDK/76wlbtz6cjltfKHqLx2TKVqTj5/c41t77m1+h20zqtPA==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0" - } - }, - "Microsoft.NETFramework.ReferenceAssemblies": { - "type": "Direct", - "requested": "[1.0.3, )", - "resolved": "1.0.3", - "contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==", - "dependencies": { - "Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3" - } - }, - "Microsoft.SourceLink.GitHub": { - "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "8.0.0", - "Microsoft.SourceLink.Common": "8.0.0" - } - }, - "PolySharp": { - "type": "Direct", - "requested": "[1.14.1, )", - "resolved": "1.14.1", - "contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ==" - }, - "Speckle.InterfaceGenerator": { - "type": "Direct", - "requested": "[0.9.6, )", - "resolved": "0.9.6", - "contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w==" - }, - "Speckle.Objects": { - "type": "Direct", - "requested": "[3.4.2, )", - "resolved": "3.4.2", - "contentHash": "2TcYsGm+vG5mpZj+fiwPJv/4wXtstrWb9FasxsQN2JdUNDKvg1/rVFE9Pby1tPWN+4J0X0QaXutGj0yNwLRe7w==", - "dependencies": { - "Speckle.Sdk": "3.4.2" - } - }, - "Speckle.Sdk": { - "type": "Direct", - "requested": "[3.4.2, )", - "resolved": "3.4.2", - "contentHash": "SOjUacHaCt+w19DhSgwQijhcwYZZSgmRVBOLk/O1Lwlq66cHVy3pzyBbsNR8zM+rVAtXrpahf60TjBg2EsD5Zg==", - "dependencies": { - "GraphQL.Client": "6.0.0", - "Microsoft.Bcl.AsyncInterfaces": "5.0.0", - "Microsoft.CSharp": "4.7.0", - "Microsoft.Data.Sqlite": "7.0.5", - "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", - "Microsoft.Extensions.Logging": "2.2.0", - "Speckle.DoubleNumerics": "4.1.0", - "Speckle.Newtonsoft.Json": "13.0.2", - "Speckle.Sdk.Dependencies": "3.4.2" - } - }, - "Speckle.Sdk.Dependencies": { - "type": "Direct", - "requested": "[3.4.2, )", - "resolved": "3.4.2", - "contentHash": "mYjR5i5zaNxkR2VXi2Ills3XG3VZ4z3wLSQBn7GldAudtxI8yS09M6w4ltFNcBmgLlnYHYiIbsWEilIGUbi0Nw==" - }, - "GraphQL.Client": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "8yPNBbuVBpTptivyAlak4GZvbwbUcjeQTL4vN1HKHRuOykZ4r7l5fcLS6vpyPyLn0x8FsL31xbOIKyxbmR9rbA==", - "dependencies": { - "GraphQL.Client.Abstractions": "6.0.0", - "GraphQL.Client.Abstractions.Websocket": "6.0.0", - "System.Reactive": "5.0.0" - } - }, - "GraphQL.Client.Abstractions": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "h7uzWFORHZ+CCjwr/ThAyXMr0DPpzEANDa4Uo54wqCQ+j7qUKwqYTgOrb1W40sqbvNaZm9v/X7It31SUw0maHA==", - "dependencies": { - "GraphQL.Primitives": "6.0.0" - } - }, - "GraphQL.Client.Abstractions.Websocket": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "Nr9bPf8gIOvLuXpqEpqr9z9jslYFJOvd0feHth3/kPqeR3uMbjF5pjiwh4jxyMcxHdr8Pb6QiXkV3hsSyt0v7A==", - "dependencies": { - "GraphQL.Client.Abstractions": "6.0.0" - } - }, - "GraphQL.Primitives": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "yg72rrYDapfsIUrul7aF6wwNnTJBOFvuA9VdDTQpPa8AlAriHbufeXYLBcodKjfUdkCnaiggX1U/nEP08Zb5GA==" - }, - "Microsoft.Bcl.AsyncInterfaces": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==" - }, - "Microsoft.Build.Tasks.Git": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ==" - }, - "Microsoft.CSharp": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA==" - }, - "Microsoft.Data.Sqlite": { - "type": "Transitive", - "resolved": "7.0.5", - "contentHash": "KGxbPeWsQMnmQy43DSBxAFtHz3l2JX8EWBSGUCvT3CuZ8KsuzbkqMIJMDOxWtG8eZSoCDI04aiVQjWuuV8HmSw==", - "dependencies": { - "Microsoft.Data.Sqlite.Core": "7.0.5", - "SQLitePCLRaw.bundle_e_sqlite3": "2.1.4" - } - }, - "Microsoft.Data.Sqlite.Core": { - "type": "Transitive", - "resolved": "7.0.5", - "contentHash": "FTerRmQPqHrCrnoUzhBu+E+1DNGwyrAMLqHkAqOOOu5pGfyMOj8qQUBxI/gDtWtG11p49UxSfWmBzRNlwZqfUg==", - "dependencies": { - "SQLitePCLRaw.core": "2.1.4" - } - }, - "Microsoft.Extensions.Configuration": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "nOP8R1mVb/6mZtm2qgAJXn/LFm/2kMjHDAg/QJLFG6CuWYJtaD3p1BwQhufBVvRzL9ceJ/xF0SQ0qsI2GkDQAA==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "2.2.0" - } - }, - "Microsoft.Extensions.Configuration.Abstractions": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "65MrmXCziWaQFrI0UHkQbesrX5wTwf9XPjY5yFm/VkgJKFJ5gqvXRoXjIZcf2wLi5ZlwGz/oMYfyURVCWbM5iw==", - "dependencies": { - "Microsoft.Extensions.Primitives": "2.2.0" - } - }, - "Microsoft.Extensions.Configuration.Binder": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "vJ9xvOZCnUAIHcGC3SU35r3HKmHTVIeHzo6u/qzlHAqD8m6xv92MLin4oJntTvkpKxVX3vI1GFFkIQtU3AdlsQ==", - "dependencies": { - "Microsoft.Extensions.Configuration": "2.2.0" - } - }, - "Microsoft.Extensions.DependencyInjection.Abstractions": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw==" - }, - "Microsoft.Extensions.Options": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "UpZLNLBpIZ0GTebShui7xXYh6DmBHjWM8NxGxZbdQh/bPZ5e6YswqI+bru6BnEL5eWiOdodsXtEz3FROcgi/qg==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", - "Microsoft.Extensions.Primitives": "2.2.0", - "System.ComponentModel.Annotations": "4.5.0" - } - }, - "Microsoft.Extensions.Primitives": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "azyQtqbm4fSaDzZHD/J+V6oWMFaf2tWP4WEGIYePLCMw3+b2RQdj9ybgbQyjCshcitQKQ4lEDOZjmSlTTrHxUg==", - "dependencies": { - "System.Memory": "4.5.1", - "System.Runtime.CompilerServices.Unsafe": "4.5.1" - } - }, - "Microsoft.NETFramework.ReferenceAssemblies.net461": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA==" - }, - "Microsoft.SourceLink.Common": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" - }, - "Speckle.Newtonsoft.Json": { - "type": "Transitive", - "resolved": "13.0.2", - "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" - }, - "SQLitePCLRaw.bundle_e_sqlite3": { - "type": "Transitive", - "resolved": "2.1.4", - "contentHash": "EWI1olKDjFEBMJu0+3wuxwziIAdWDVMYLhuZ3Qs84rrz+DHwD00RzWPZCa+bLnHCf3oJwuFZIRsHT5p236QXww==", - "dependencies": { - "SQLitePCLRaw.lib.e_sqlite3": "2.1.4", - "SQLitePCLRaw.provider.e_sqlite3": "2.1.4" - } - }, - "SQLitePCLRaw.core": { - "type": "Transitive", - "resolved": "2.1.4", - "contentHash": "inBjvSHo9UDKneGNzfUfDjK08JzlcIhn1+SP5Y3m6cgXpCxXKCJDy6Mka7LpgSV+UZmKSnC8rTwB0SQ0xKu5pA==", - "dependencies": { - "System.Memory": "4.5.3" - } - }, - "SQLitePCLRaw.lib.e_sqlite3": { - "type": "Transitive", - "resolved": "2.1.4", - "contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg==" - }, - "SQLitePCLRaw.provider.e_sqlite3": { - "type": "Transitive", - "resolved": "2.1.4", - "contentHash": "CSlb5dUp1FMIkez9Iv5EXzpeq7rHryVNqwJMWnpq87j9zWZexaEMdisDktMsnnrzKM6ahNrsTkjqNodTBPBxtQ==", - "dependencies": { - "SQLitePCLRaw.core": "2.1.4" - } - }, - "System.ComponentModel.Annotations": { - "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==" - }, - "System.Memory": { - "type": "Transitive", - "resolved": "4.5.3", - "contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==" - }, - "System.Reactive": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==" - }, - "System.Runtime.CompilerServices.Unsafe": { - "type": "Transitive", - "resolved": "4.5.1", - "contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw==" - }, - "speckle.connectors.logging": { - "type": "Project" - }, - "Microsoft.Extensions.Logging": { - "type": "CentralTransitive", - "requested": "[2.2.0, )", - "resolved": "2.2.0", - "contentHash": "Nxqhadc9FCmFHzU+fz3oc8sFlE6IadViYg8dfUdGzJZ2JUxnCsRghBhhOWdM4B2zSZqEc+0BjliBh/oNdRZuig==", - "dependencies": { - "Microsoft.Extensions.Configuration.Binder": "2.2.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", - "Microsoft.Extensions.Logging.Abstractions": "2.2.0", - "Microsoft.Extensions.Options": "2.2.0" - } - }, - "Microsoft.Extensions.Logging.Abstractions": { - "type": "CentralTransitive", - "requested": "[2.2.0, )", - "resolved": "2.2.0", - "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" - }, - "Speckle.DoubleNumerics": { - "type": "CentralTransitive", - "requested": "[4.1.0, )", - "resolved": "4.1.0", - "contentHash": "20DtS+FsDRsOD9+AU3TwNFZ0qrKo5f6f7B5ZR9wStsIHHHC9k7DpjbCvuNtmnSjx54MD+TJC7wV2f5iyGVPj1A==" - } - }, "net8.0": { "Microsoft.Extensions.DependencyInjection": { "type": "Direct", diff --git a/Sdk/Speckle.Converters.Common/Speckle.Converters.Common.csproj b/Sdk/Speckle.Converters.Common/Speckle.Converters.Common.csproj index 3f0e65a75..08745e873 100644 --- a/Sdk/Speckle.Converters.Common/Speckle.Converters.Common.csproj +++ b/Sdk/Speckle.Converters.Common/Speckle.Converters.Common.csproj @@ -1,7 +1,7 @@ - net48;net6.0;net8.0 + net48;net8.0 Debug;Release;Local diff --git a/Sdk/Speckle.Converters.Common/packages.lock.json b/Sdk/Speckle.Converters.Common/packages.lock.json index 55ba08dda..4e656db17 100644 --- a/Sdk/Speckle.Converters.Common/packages.lock.json +++ b/Sdk/Speckle.Converters.Common/packages.lock.json @@ -305,271 +305,6 @@ "contentHash": "mYjR5i5zaNxkR2VXi2Ills3XG3VZ4z3wLSQBn7GldAudtxI8yS09M6w4ltFNcBmgLlnYHYiIbsWEilIGUbi0Nw==" } }, - "net6.0": { - "Microsoft.Extensions.Logging.Abstractions": { - "type": "Direct", - "requested": "[2.2.0, )", - "resolved": "2.2.0", - "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" - }, - "Microsoft.NETFramework.ReferenceAssemblies": { - "type": "Direct", - "requested": "[1.0.3, )", - "resolved": "1.0.3", - "contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==", - "dependencies": { - "Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3" - } - }, - "Microsoft.SourceLink.GitHub": { - "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "8.0.0", - "Microsoft.SourceLink.Common": "8.0.0" - } - }, - "PolySharp": { - "type": "Direct", - "requested": "[1.14.1, )", - "resolved": "1.14.1", - "contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ==" - }, - "Speckle.InterfaceGenerator": { - "type": "Direct", - "requested": "[0.9.6, )", - "resolved": "0.9.6", - "contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w==" - }, - "Speckle.Objects": { - "type": "Direct", - "requested": "[3.4.2, )", - "resolved": "3.4.2", - "contentHash": "2TcYsGm+vG5mpZj+fiwPJv/4wXtstrWb9FasxsQN2JdUNDKvg1/rVFE9Pby1tPWN+4J0X0QaXutGj0yNwLRe7w==", - "dependencies": { - "Speckle.Sdk": "3.4.2" - } - }, - "GraphQL.Client": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "8yPNBbuVBpTptivyAlak4GZvbwbUcjeQTL4vN1HKHRuOykZ4r7l5fcLS6vpyPyLn0x8FsL31xbOIKyxbmR9rbA==", - "dependencies": { - "GraphQL.Client.Abstractions": "6.0.0", - "GraphQL.Client.Abstractions.Websocket": "6.0.0", - "System.Reactive": "5.0.0" - } - }, - "GraphQL.Client.Abstractions": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "h7uzWFORHZ+CCjwr/ThAyXMr0DPpzEANDa4Uo54wqCQ+j7qUKwqYTgOrb1W40sqbvNaZm9v/X7It31SUw0maHA==", - "dependencies": { - "GraphQL.Primitives": "6.0.0" - } - }, - "GraphQL.Client.Abstractions.Websocket": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "Nr9bPf8gIOvLuXpqEpqr9z9jslYFJOvd0feHth3/kPqeR3uMbjF5pjiwh4jxyMcxHdr8Pb6QiXkV3hsSyt0v7A==", - "dependencies": { - "GraphQL.Client.Abstractions": "6.0.0" - } - }, - "GraphQL.Primitives": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "yg72rrYDapfsIUrul7aF6wwNnTJBOFvuA9VdDTQpPa8AlAriHbufeXYLBcodKjfUdkCnaiggX1U/nEP08Zb5GA==" - }, - "Microsoft.Bcl.AsyncInterfaces": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==" - }, - "Microsoft.Build.Tasks.Git": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ==" - }, - "Microsoft.CSharp": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA==" - }, - "Microsoft.Data.Sqlite": { - "type": "Transitive", - "resolved": "7.0.5", - "contentHash": "KGxbPeWsQMnmQy43DSBxAFtHz3l2JX8EWBSGUCvT3CuZ8KsuzbkqMIJMDOxWtG8eZSoCDI04aiVQjWuuV8HmSw==", - "dependencies": { - "Microsoft.Data.Sqlite.Core": "7.0.5", - "SQLitePCLRaw.bundle_e_sqlite3": "2.1.4" - } - }, - "Microsoft.Data.Sqlite.Core": { - "type": "Transitive", - "resolved": "7.0.5", - "contentHash": "FTerRmQPqHrCrnoUzhBu+E+1DNGwyrAMLqHkAqOOOu5pGfyMOj8qQUBxI/gDtWtG11p49UxSfWmBzRNlwZqfUg==", - "dependencies": { - "SQLitePCLRaw.core": "2.1.4" - } - }, - "Microsoft.Extensions.Configuration": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "nOP8R1mVb/6mZtm2qgAJXn/LFm/2kMjHDAg/QJLFG6CuWYJtaD3p1BwQhufBVvRzL9ceJ/xF0SQ0qsI2GkDQAA==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "2.2.0" - } - }, - "Microsoft.Extensions.Configuration.Abstractions": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "65MrmXCziWaQFrI0UHkQbesrX5wTwf9XPjY5yFm/VkgJKFJ5gqvXRoXjIZcf2wLi5ZlwGz/oMYfyURVCWbM5iw==", - "dependencies": { - "Microsoft.Extensions.Primitives": "2.2.0" - } - }, - "Microsoft.Extensions.Configuration.Binder": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "vJ9xvOZCnUAIHcGC3SU35r3HKmHTVIeHzo6u/qzlHAqD8m6xv92MLin4oJntTvkpKxVX3vI1GFFkIQtU3AdlsQ==", - "dependencies": { - "Microsoft.Extensions.Configuration": "2.2.0" - } - }, - "Microsoft.Extensions.DependencyInjection.Abstractions": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw==" - }, - "Microsoft.Extensions.Options": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "UpZLNLBpIZ0GTebShui7xXYh6DmBHjWM8NxGxZbdQh/bPZ5e6YswqI+bru6BnEL5eWiOdodsXtEz3FROcgi/qg==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", - "Microsoft.Extensions.Primitives": "2.2.0", - "System.ComponentModel.Annotations": "4.5.0" - } - }, - "Microsoft.Extensions.Primitives": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "azyQtqbm4fSaDzZHD/J+V6oWMFaf2tWP4WEGIYePLCMw3+b2RQdj9ybgbQyjCshcitQKQ4lEDOZjmSlTTrHxUg==", - "dependencies": { - "System.Memory": "4.5.1", - "System.Runtime.CompilerServices.Unsafe": "4.5.1" - } - }, - "Microsoft.NETFramework.ReferenceAssemblies.net461": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA==" - }, - "Microsoft.SourceLink.Common": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" - }, - "Speckle.Newtonsoft.Json": { - "type": "Transitive", - "resolved": "13.0.2", - "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" - }, - "SQLitePCLRaw.bundle_e_sqlite3": { - "type": "Transitive", - "resolved": "2.1.4", - "contentHash": "EWI1olKDjFEBMJu0+3wuxwziIAdWDVMYLhuZ3Qs84rrz+DHwD00RzWPZCa+bLnHCf3oJwuFZIRsHT5p236QXww==", - "dependencies": { - "SQLitePCLRaw.lib.e_sqlite3": "2.1.4", - "SQLitePCLRaw.provider.e_sqlite3": "2.1.4" - } - }, - "SQLitePCLRaw.core": { - "type": "Transitive", - "resolved": "2.1.4", - "contentHash": "inBjvSHo9UDKneGNzfUfDjK08JzlcIhn1+SP5Y3m6cgXpCxXKCJDy6Mka7LpgSV+UZmKSnC8rTwB0SQ0xKu5pA==", - "dependencies": { - "System.Memory": "4.5.3" - } - }, - "SQLitePCLRaw.lib.e_sqlite3": { - "type": "Transitive", - "resolved": "2.1.4", - "contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg==" - }, - "SQLitePCLRaw.provider.e_sqlite3": { - "type": "Transitive", - "resolved": "2.1.4", - "contentHash": "CSlb5dUp1FMIkez9Iv5EXzpeq7rHryVNqwJMWnpq87j9zWZexaEMdisDktMsnnrzKM6ahNrsTkjqNodTBPBxtQ==", - "dependencies": { - "SQLitePCLRaw.core": "2.1.4" - } - }, - "System.ComponentModel.Annotations": { - "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==" - }, - "System.Memory": { - "type": "Transitive", - "resolved": "4.5.3", - "contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==" - }, - "System.Reactive": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==" - }, - "System.Runtime.CompilerServices.Unsafe": { - "type": "Transitive", - "resolved": "4.5.1", - "contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw==" - }, - "Microsoft.Extensions.Logging": { - "type": "CentralTransitive", - "requested": "[2.2.0, )", - "resolved": "2.2.0", - "contentHash": "Nxqhadc9FCmFHzU+fz3oc8sFlE6IadViYg8dfUdGzJZ2JUxnCsRghBhhOWdM4B2zSZqEc+0BjliBh/oNdRZuig==", - "dependencies": { - "Microsoft.Extensions.Configuration.Binder": "2.2.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", - "Microsoft.Extensions.Logging.Abstractions": "2.2.0", - "Microsoft.Extensions.Options": "2.2.0" - } - }, - "Speckle.DoubleNumerics": { - "type": "CentralTransitive", - "requested": "[4.1.0, )", - "resolved": "4.1.0", - "contentHash": "20DtS+FsDRsOD9+AU3TwNFZ0qrKo5f6f7B5ZR9wStsIHHHC9k7DpjbCvuNtmnSjx54MD+TJC7wV2f5iyGVPj1A==" - }, - "Speckle.Sdk": { - "type": "CentralTransitive", - "requested": "[3.4.2, )", - "resolved": "3.4.2", - "contentHash": "SOjUacHaCt+w19DhSgwQijhcwYZZSgmRVBOLk/O1Lwlq66cHVy3pzyBbsNR8zM+rVAtXrpahf60TjBg2EsD5Zg==", - "dependencies": { - "GraphQL.Client": "6.0.0", - "Microsoft.Bcl.AsyncInterfaces": "5.0.0", - "Microsoft.CSharp": "4.7.0", - "Microsoft.Data.Sqlite": "7.0.5", - "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", - "Microsoft.Extensions.Logging": "2.2.0", - "Speckle.DoubleNumerics": "4.1.0", - "Speckle.Newtonsoft.Json": "13.0.2", - "Speckle.Sdk.Dependencies": "3.4.2" - } - }, - "Speckle.Sdk.Dependencies": { - "type": "CentralTransitive", - "requested": "[3.4.2, )", - "resolved": "3.4.2", - "contentHash": "mYjR5i5zaNxkR2VXi2Ills3XG3VZ4z3wLSQBn7GldAudtxI8yS09M6w4ltFNcBmgLlnYHYiIbsWEilIGUbi0Nw==" - } - }, "net8.0": { "Microsoft.Extensions.Logging.Abstractions": { "type": "Direct", diff --git a/Sdk/Speckle.Performance/Speckle.Performance.csproj b/Sdk/Speckle.Performance/Speckle.Performance.csproj index 84d1253ce..65640cd2e 100644 --- a/Sdk/Speckle.Performance/Speckle.Performance.csproj +++ b/Sdk/Speckle.Performance/Speckle.Performance.csproj @@ -1,7 +1,7 @@  - net48;net6.0;net8.0 + net48;net8.0 diff --git a/Sdk/Speckle.Performance/packages.lock.json b/Sdk/Speckle.Performance/packages.lock.json index 283b1ef5d..9b2995dcb 100644 --- a/Sdk/Speckle.Performance/packages.lock.json +++ b/Sdk/Speckle.Performance/packages.lock.json @@ -80,85 +80,6 @@ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" } }, - "net6.0": { - "JetBrains.Profiler.SelfApi": { - "type": "Direct", - "requested": "[2.5.12, )", - "resolved": "2.5.12", - "contentHash": "m0MGIX6Eut9Z5hzqF4gNVn8oK2jeYDe7kihZTtD2/Iy9P7zE+zemO9VisiMD/1I1V8Es7lHOI49HNq9VGut96A==", - "dependencies": { - "JetBrains.HabitatDetector": "1.4.3", - "JetBrains.Profiler.Api": "1.4.8" - } - }, - "Microsoft.NETFramework.ReferenceAssemblies": { - "type": "Direct", - "requested": "[1.0.3, )", - "resolved": "1.0.3", - "contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==", - "dependencies": { - "Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3" - } - }, - "Microsoft.SourceLink.GitHub": { - "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "8.0.0", - "Microsoft.SourceLink.Common": "8.0.0" - } - }, - "PolySharp": { - "type": "Direct", - "requested": "[1.14.1, )", - "resolved": "1.14.1", - "contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ==" - }, - "Speckle.InterfaceGenerator": { - "type": "Direct", - "requested": "[0.9.6, )", - "resolved": "0.9.6", - "contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w==" - }, - "JetBrains.FormatRipper": { - "type": "Transitive", - "resolved": "2.2.2", - "contentHash": "UvbPJM1ryALWSrnMX428ZxLujOrSAxdCgSwr1/7A0mFFxM8Rxku0OjN+zZENmZQ6Hirm7StkC176qy0m30UgjQ==" - }, - "JetBrains.HabitatDetector": { - "type": "Transitive", - "resolved": "1.4.3", - "contentHash": "4VC4sP/T+16MwsfUjwbKVYwKEOEu9cdQxLvN9uUiIm17m2y1SlV4Aj29HKsFbFyCbTePOGQMw3ccoPuym6d+EQ==", - "dependencies": { - "JetBrains.FormatRipper": "2.2.2" - } - }, - "JetBrains.Profiler.Api": { - "type": "Transitive", - "resolved": "1.4.8", - "contentHash": "hH0Hej/hjwTn14yhhzEcGaB3HJ40C/CwW2E8RrhsqCcBg5bs50LQFOx2a5dFXjWDMzspAso5xADtQmBI6lXKTw==", - "dependencies": { - "JetBrains.HabitatDetector": "1.4.3" - } - }, - "Microsoft.Build.Tasks.Git": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ==" - }, - "Microsoft.NETFramework.ReferenceAssemblies.net461": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA==" - }, - "Microsoft.SourceLink.Common": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" - } - }, "net8.0": { "JetBrains.Profiler.SelfApi": { "type": "Direct", diff --git a/Speckle.Connectors.Mac.slnx b/Speckle.Connectors.Mac.slnx new file mode 100644 index 000000000..46dee93f4 --- /dev/null +++ b/Speckle.Connectors.Mac.slnx @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Speckle.Connectors.sln b/Speckle.Connectors.sln index 77fdc98ea..2b0b043bc 100644 --- a/Speckle.Connectors.sln +++ b/Speckle.Connectors.sln @@ -914,6 +914,7 @@ Global Connectors\Revit\Speckle.Connectors.RevitShared.Cef\Speckle.Connectors.RevitShared.Cef.projitems*{01f98733-7352-47ad-a594-537d979de3de}*SharedItemsImports = 5 Connectors\Revit\Speckle.Connectors.RevitShared\Speckle.Connectors.RevitShared.projitems*{01f98733-7352-47ad-a594-537d979de3de}*SharedItemsImports = 5 Connectors\Tekla\Speckle.Connector.TeklaShared\Speckle.Connectors.TeklaShared.projitems*{025c85f8-f741-4600-bc46-5fead754b65d}*SharedItemsImports = 5 + Connectors\Tekla\Speckle.Connector.TeklaShared\Speckle.Connectors.TeklaShared.projitems*{0454eabf-8252-4421-9e94-eec6143dc012}*SharedItemsImports = 5 Connectors\Navisworks\Speckle.Connectors.NavisworksShared\Speckle.Connectors.NavisworksShared.projitems*{04fc86a3-2e25-41a1-98c5-10898616cd78}*SharedItemsImports = 5 Converters\Navisworks\Speckle.Converters.NavisworksShared\Speckle.Converters.NavisworksShared.projitems*{0b5ab325-3791-4a81-b0ef-bca040381be2}*SharedItemsImports = 5 Connectors\CSi\Speckle.Connectors.CsiShared\Speckle.Connectors.CsiShared.projitems*{115d6106-1801-484a-b4e5-bcc94b6e5c7f}*SharedItemsImports = 5 @@ -984,6 +985,7 @@ Global Connectors\Autocad\Speckle.Connectors.Civil3dShared\Speckle.Connectors.Civil3dShared.projitems*{afab80bd-a4dd-4cad-9937-acbfed668a48}*SharedItemsImports = 5 Converters\Navisworks\Speckle.Converters.NavisworksShared\Speckle.Converters.NavisworksShared.projitems*{b12d6a2e-51fd-4197-b442-46c7d8f5e4e4}*SharedItemsImports = 5 Connectors\Rhino\Speckle.Connectors.RhinoShared\Speckle.Connectors.RhinoShared.projitems*{b37d4b9a-8d3f-4fa5-b9c8-e6c5f8a0c1e2}*SharedItemsImports = 13 + Converters\Tekla\Speckle.Converters.TeklaShared\Speckle.Converters.TeklaShared.projitems*{b42013eb-6180-4fbd-a6f9-ecb7822fda84}*SharedItemsImports = 5 Connectors\Navisworks\Speckle.Connectors.NavisworksShared\Speckle.Connectors.NavisworksShared.projitems*{b6985672-4704-4f86-a3e0-2310bf8e6d73}*SharedItemsImports = 5 Connectors\Rhino\Speckle.Connectors.GrasshopperShared\Speckle.Connectors.GrasshopperShared.projitems*{b6fbb8f4-4e2d-41d9-ac3f-1e30d0c8e87c}*SharedItemsImports = 13 Connectors\Autocad\Speckle.Connectors.AutocadShared\Speckle.Connectors.AutocadShared.projitems*{bbf2c19e-221e-4aa0-8521-fe75d8f4a2b0}*SharedItemsImports = 5 diff --git a/Speckle.Revit.Local.slnx b/Speckle.Revit.Local.slnx new file mode 100644 index 000000000..59ddc72e8 --- /dev/null +++ b/Speckle.Revit.Local.slnx @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/copilot.ignore b/copilot.ignore new file mode 100644 index 000000000..7d0908fcf --- /dev/null +++ b/copilot.ignore @@ -0,0 +1,3 @@ +# Ignore the Speckle.Performance directory for GitHub Copilot suggestions +Speckle.Performance/ +Connectors/