Compare commits

..

21 Commits

Author SHA1 Message Date
Jedd Morgan 98223e251c Use OIDC for auth (#397)
.NET Build and Publish / build (push) Has been cancelled
2025-10-15 10:45:58 +01:00
Jedd Morgan 08f702794a skip some slow tests (#403) 2025-10-15 09:25:07 +00:00
Jedd Morgan 879ebf7e3c feat(sdk): align SpecklePathProvider with connector repo (#400)
* path provider

* tweaks

* Align with duplicated class
2025-10-15 10:14:57 +01:00
Dogukan Karatas 1046e2aafc removes the extra serializer (#402)
.NET Build and Publish / build (push) Has been cancelled
2025-10-14 16:20:30 +01:00
Jedd Morgan 5cb0eddf4e Update RenderMaterial.cs (#399) 2025-10-13 19:00:26 +00:00
Jedd Morgan e97ce83c6b chore(docs): Update doc comments (#398)
* path provider

* tweaks
2025-10-13 17:01:38 +00:00
Adam Hathcock ea23e72c77 Expose options for sending and receiving (#394) 2025-10-08 10:16:28 +01:00
Adam Hathcock 37358570ec Use new endpoint with attribute mask support (#392)
* Use new endpoint with attribute mask support

* fix test
2025-09-24 11:00:44 +02:00
Adam Hathcock 02b9a73164 Don't record cancelled exceptions (#391)
Co-authored-by: Jedd Morgan <45512892+JR-Morgan@users.noreply.github.com>
2025-09-17 11:05:21 +01:00
Adam Hathcock 530387b87c Remove the cache that avoids recalculating IDs from JSON (#384)
Co-authored-by: Jedd Morgan <45512892+JR-Morgan@users.noreply.github.com>
Co-authored-by: Claire Kuang <kuang.claire@gmail.com>
2025-09-12 10:47:53 +00:00
Adam Hathcock b16e32d1ff fix: Correctly pass options to object saver (#387)
* Correctly pass options to object saver

* formatting
2025-09-12 10:30:47 +00:00
Jedd Morgan d91fccbb10 Merge pull request #386 from specklesystems/jrm/local-account-ids
chore(sdk): deprecate local ids
2025-09-11 11:03:27 +00:00
Jedd Morgan 62f687b589 Merge pull request #385 from specklesystems/jrm/hashed-account-fallbacks
.NET Build and Publish / build (push) Has been cancelled
chore(sdk)!: Remove fallback behaviour from hashed account info
2025-09-10 14:50:27 +01:00
Adam Hathcock c0d4d951df Merge pull request #383 from specklesystems/dependabot/github_actions/actions/setup-dotnet-5
Bump actions/setup-dotnet from 4 to 5
2025-09-09 08:26:29 +01:00
dependabot[bot] 4e1753e1fd Bump actions/setup-dotnet from 4 to 5
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 4 to 5.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 19:09:58 +00:00
Jedd Morgan 4c615ae8c6 Back Merge Main -> dev (#381)
Co-authored-by: Adam Hathcock <adamhathcock@users.noreply.github.com>
2025-09-08 10:43:16 +01:00
Jedd Morgan d5ee9fb76c Merge branch 'dev' into jrm/dev-main 2025-09-08 10:42:30 +01:00
Björn Steinhagen ea118bcdbb fix: collection order (#380)
* fix: collection order

* chore: format

* refactor: keeping depth first
2025-09-08 09:21:02 +00:00
Adam Hathcock ba456ee3eb Merge pull request #378 from specklesystems/dev
.NET Build and Publish / build (push) Has been cancelled
Dev to main for release (NO SQUASH)
2025-08-28 09:33:09 +01:00
Adam Hathcock 10d283a9f7 Report increment rather than total position (#377)
* Report increment rather than total position

* Report progress before saving SQLite
2025-08-26 16:45:53 +01:00
Jedd Morgan 30c9b17dab Merge pull request #374 from specklesystems/dev
.NET Build and Publish / build (push) Has been cancelled
Dev -> Main
2025-08-06 13:39:59 +01:00
31 changed files with 145 additions and 149 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
uses: actions/checkout@v5
- name: Setup .NET
uses: actions/setup-dotnet@v4
uses: actions/setup-dotnet@v5
with:
dotnet-version: 8.x.x
+18 -7
View File
@@ -2,17 +2,22 @@ name: .NET Build and Publish
on:
push:
tags: ["3.*"]
tags: ["3.*.*"]
jobs:
build:
runs-on: ubuntu-latest
environment:
name: 'nuget.org'
permissions:
id-token: write # enable GitHub OIDC token issuance for this job
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Setup .NET
uses: actions/setup-dotnet@v4
uses: actions/setup-dotnet@v5
with:
dotnet-version: 8.x.x
@@ -20,7 +25,7 @@ jobs:
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
- id: set-version
name: Set version to output
run: |
@@ -37,18 +42,24 @@ jobs:
echo $SEMVER
echo $FILE_VERSION
- name: 🔫 Build and Pack
run: ./build.sh pack
env:
SEMVER: ${{ steps.set-version.outputs.SEMVER }}
FILE_VERSION: ${{ steps.set-version.outputs.FILE_VERSION }}
- name: Upload coverage reports to Codecov with GitHub Action
uses: codecov/codecov-action@v5
with:
files: tests/**/coverage.xml
token: ${{ secrets.CODECOV_TOKEN }}
- name: NuGet login (OIDC → temp API key)
uses: NuGet/login@v1
id: login
with:
user: ${{ secrets.NUGET_USER }}
- name: Push to nuget.org
run: dotnet nuget push output/*.nupkg --source "https://api.nuget.org/v3/index.json" --api-key ${{secrets.CONNECTORS_NUGET_TOKEN }} --skip-duplicate
run: dotnet nuget push output/*.nupkg --source "https://api.nuget.org/v3/index.json" --api-key ${{steps.login.outputs.NUGET_API_KEY}}
+1 -1
View File
@@ -35,6 +35,6 @@ public class RenderMaterial : Base
public Color emissiveColor
{
get => Color.FromArgb(emissive);
set => diffuse = value.ToArgb();
set => emissive = value.ToArgb();
}
}
@@ -19,6 +19,9 @@ public sealed class ServerInfo
[Obsolete("Don't use")]
public bool frontend2 { get; set; } = true;
/// <summary>
/// The URL that should be used to talk with the server
/// </summary>
/// <remarks>
/// This field is not returned from the GQL API,
/// it should be populated after construction.
@@ -2,6 +2,7 @@ using Microsoft.Extensions.Logging;
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models;
using Speckle.Sdk.Serialisation;
using Speckle.Sdk.Serialisation.V2.Receive;
using Speckle.Sdk.Transports;
namespace Speckle.Sdk.Api;
@@ -22,7 +23,8 @@ public partial class Operations
string objectId,
string? authorizationToken,
IProgress<ProgressArgs>? onProgressAction,
CancellationToken cancellationToken
CancellationToken cancellationToken,
DeserializeProcessOptions? options = null
)
{
using var receiveActivity = activityFactory.Start("Operations.Receive");
@@ -36,7 +38,8 @@ public partial class Operations
streamId,
authorizationToken,
onProgressAction,
cancellationToken
cancellationToken,
options
);
try
{
@@ -44,6 +47,11 @@ public partial class Operations
receiveActivity?.SetStatus(SdkActivityStatusCode.Ok);
return result;
}
catch (OperationCanceledException)
{
//this is handled by the caller
throw;
}
catch (Exception ex)
{
receiveActivity?.SetStatus(SdkActivityStatusCode.Error);
@@ -25,7 +25,8 @@ public partial class Operations
string? authorizationToken,
Base value,
IProgress<ProgressArgs>? onProgressAction,
CancellationToken cancellationToken
CancellationToken cancellationToken,
SerializeProcessOptions? options = null
)
{
using var receiveActivity = activityFactory.Start("Operations.Send");
@@ -38,7 +39,8 @@ public partial class Operations
streamId,
authorizationToken,
onProgressAction,
cancellationToken
cancellationToken,
options
);
try
{
+10 -2
View File
@@ -59,15 +59,20 @@ public class Account : IEquatable<Account>
#region public methods
/// <remarks>The logic is aligned with <c>distinct_id</c> mixpanel property</remarks>
/// <exception cref="ArgumentNullException">Thrown if <see name="userInfo.email"/> was <see langword="null"/></exception>
public string GetHashedEmail()
{
string email = userInfo?.email ?? "unknown";
string email = userInfo.email.NotNull();
return "@" + Md5.GetString(email).ToUpperInvariant();
}
/// <remarks>The logic is aligned with <c>server</c> mixpanel property</remarks>
/// <exception cref="ArgumentNullException">Thrown if <see name="serverInfo.url"/> was <see langword="null"/></exception>
public string GetHashedServer()
{
string url = serverInfo?.url ?? AccountManager.DEFAULT_SERVER_URL;
string url = serverInfo.url.NotNull();
return Md5.GetString(CleanURL(url)).ToUpperInvariant();
}
@@ -97,6 +102,8 @@ public class Account : IEquatable<Account>
#endregion
internal const string LOCAL_IDENTIFIER_DEPRECATION_MESSAGE = "Local identifiers no longer nesseary";
/// <summary>
/// Retrieves the local identifier for the current user.
/// </summary>
@@ -121,5 +128,6 @@ public class Account : IEquatable<Account>
/// https://speckle.xyz?id=123
/// </code>
/// </example>
[Obsolete(LOCAL_IDENTIFIER_DEPRECATION_MESSAGE)]
internal Uri GetLocalIdentifier() => new($"{serverInfo.url}?id={userInfo.id}");
}
@@ -419,6 +419,7 @@ public sealed class AccountManager(
/// <remarks>
/// <inheritdoc cref="Account.GetLocalIdentifier"/>
/// </remarks>
[Obsolete(Account.LOCAL_IDENTIFIER_DEPRECATION_MESSAGE)]
public Uri? GetLocalIdentifierForAccount(Account account)
{
var identifier = account.GetLocalIdentifier();
@@ -440,6 +441,7 @@ public sealed class AccountManager(
/// </summary>
/// <param name="localIdentifier">The local identifier of the account.</param>
/// <returns>The account that matches the local identifier, or null if no match is found.</returns>
[Obsolete(Account.LOCAL_IDENTIFIER_DEPRECATION_MESSAGE)]
public Account? GetAccountForLocalIdentifier(Uri localIdentifier)
{
var searchResult = GetAccounts()
+10 -16
View File
@@ -9,6 +9,8 @@ public static class SpecklePathProvider
{
private const string APPLICATION_NAME = "Speckle";
private const string LOG_FOLDER_NAME = "Logs";
private const string BLOB_FOLDER_NAME = "Blobs";
private const string ACCOUNTS_FOLDER_NAME = "Accounts";
@@ -43,7 +45,7 @@ public static class SpecklePathProvider
/// <see cref="Environment.SpecialFolder.ApplicationData"/> path usually maps to
/// <ul>
/// <li>win: <c>%appdata%/</c></li>
/// <li>MacOS: <c>~/.config/</c></li>
/// <li>MacOS: <c>~/Library/Application Support</c></li>
/// <li>Linux: <c>~/.config/</c></li>
/// </ul>
/// </remarks>
@@ -57,29 +59,18 @@ public static class SpecklePathProvider
return pathOverride;
}
// on desktop linux and macos we use the appdata.
// but we might not have write access to the disk
// so the catch falls back to the user profile
try
{
return Environment.GetFolderPath(
Environment.SpecialFolder.ApplicationData,
// if the folder doesn't exist, we get back an empty string on OSX,
// which in turn, breaks other stuff down the line.
// passing in the Create option ensures that this directory exists,
// which is not a given on all OS-es.
// It's not a given that the folder is already there on all OS-es, so we'll create it
Environment.SpecialFolderOption.Create
);
}
catch (SystemException ex) when (ex is PlatformNotSupportedException or ArgumentException)
catch (PlatformNotSupportedException)
{
//Adding this log just so we confidently know which Exception type to catch here.
// TODO: Must re-add log call when (and if) this get's made as a service
//SpeckleLog.Logger.Warning(ex, "Falling back to user profile path");
// on server linux, there might not be a user setup, things can run under root
// in that case, the appdata variable is most probably not set up
// we fall back to the value of the home folder
// We might not have write access to the disk to create the folder,
// so we'll fall back to the user profile
return Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
}
}
@@ -96,4 +87,7 @@ public static class SpecklePathProvider
Directory.CreateDirectory(path);
return path;
}
public static string LogFolderPath(string applicationAndVersion) =>
EnsureFolderExists(UserSpeckleFolderPath, LOG_FOLDER_NAME, applicationAndVersion);
}
@@ -109,9 +109,9 @@ public abstract class GraphTraversal<T>
break;
case IList list:
{
foreach (object? obj in list)
for (int i = list.Count - 1; i >= 0; i--)
{
TraverseMemberToStack(stack, obj, memberName, parent);
TraverseMemberToStack(stack, list[i], memberName, parent);
}
break;
@@ -9,6 +9,7 @@ public class MemoryServerObjectManager(ConcurrentDictionary<string, string> obje
{
public virtual async IAsyncEnumerable<(string, string)> DownloadObjects(
IReadOnlyCollection<string> objectIds,
string? attributeMask,
IProgress<ProgressArgs>? progress,
[EnumeratorCancellation] CancellationToken cancellationToken
)
@@ -14,7 +14,8 @@ public record DeserializeProcessOptions(
bool ThrowOnMissingReferences = true,
bool SkipInvalidConverts = false,
int? MaxParallelism = null,
bool SkipServer = false
bool SkipServer = false,
string? AttributeMask = null
);
public partial interface IDeserializeProcess : IAsyncDisposable;
@@ -44,6 +45,7 @@ public sealed class DeserializeProcess(
new ObjectLoader(
sqLiteJsonCacheManager,
serverObjectManager,
options?.AttributeMask,
progress,
loggerFactory.CreateLogger<ObjectLoader>(),
cancellationToken
@@ -16,6 +16,7 @@ public partial interface IObjectLoader : IDisposable;
public sealed class ObjectLoader(
ISqLiteJsonCacheManager sqLiteJsonCacheManager,
IServerObjectManager serverObjectManager,
string? attributeMask,
IProgress<ProgressArgs>? progress,
ILogger<ObjectLoader> logger,
CancellationToken cancellationToken
@@ -111,6 +112,7 @@ public sealed class ObjectLoader(
await foreach (
var (id, json) in serverObjectManager.DownloadObjects(
ids.Select(x => x.NotNull()).ToList(),
attributeMask,
progress,
cancellationToken
)
@@ -21,12 +21,7 @@ public class BaseSerializer(
public IReadOnlyDictionary<Id, ObjectReference> ObjectReferences => _objectReferences;
//leave this sync
public IEnumerable<BaseItem> Serialise(
Base obj,
IReadOnlyDictionary<Id, NodeInfo> childInfo,
bool skipCacheRead,
CancellationToken cancellationToken
)
public IEnumerable<BaseItem> Serialise(Base obj, bool skipCacheRead, CancellationToken cancellationToken)
{
if (!skipCacheRead && obj.id != null)
{
@@ -38,7 +33,7 @@ public class BaseSerializer(
}
}
using var serializer2 = objectSerializerFactory.Create(childInfo, cancellationToken);
using var serializer2 = objectSerializerFactory.Create(cancellationToken);
var items = _pool.Get();
try
{
@@ -20,10 +20,10 @@ public sealed class ObjectSaver(
ISqLiteJsonCacheManager sqLiteJsonCacheManager,
IServerObjectManager serverObjectManager,
ILogger<ObjectSaver> logger,
CancellationToken cancellationToken,
SerializeProcessOptions options,
CancellationToken cancellationToken
#pragma warning disable CS9107
#pragma warning disable CA2254
SerializeProcessOptions? options = null
) : ChannelSaver<BaseItem>, IObjectSaver
#pragma warning restore CA2254
#pragma warning restore CS9107
@@ -26,8 +26,6 @@ public sealed class ObjectSerializer : IObjectSerializer
{
private HashSet<object> _parentObjects = new();
private readonly IReadOnlyDictionary<Id, NodeInfo> _childCache;
private readonly IBasePropertyGatherer _propertyGatherer;
private readonly CancellationToken _cancellationToken;
@@ -52,7 +50,6 @@ public sealed class ObjectSerializer : IObjectSerializer
/// <param name="cancellationToken"></param>
public ObjectSerializer(
IBasePropertyGatherer propertyGatherer,
IReadOnlyDictionary<Id, NodeInfo> childCache,
Pool<List<(Id, Json, Closures)>> chunksPool,
Pool<List<DataChunk>> chunks2Pool,
Pool<List<object?>> chunks3Pool,
@@ -60,7 +57,6 @@ public sealed class ObjectSerializer : IObjectSerializer
)
{
_propertyGatherer = propertyGatherer;
_childCache = childCache;
_chunksPool = chunksPool;
_chunks2Pool = chunks2Pool;
_chunks3Pool = chunks3Pool;
@@ -299,28 +295,14 @@ public sealed class ObjectSerializer : IObjectSerializer
private (Id, Json)? SerializeDetachedBase(Base baseObj, Closures closures)
{
Closures childClosures;
Id id;
Json json;
//avoid multiple serialization to get closures
if (baseObj.id != null && _childCache.TryGetValue(new(baseObj.id), out var info))
{
id = new Id(baseObj.id);
childClosures = info.GetClosures(_cancellationToken);
json = info.Json;
closures.IncrementClosures(childClosures);
}
else
{
childClosures = [];
var sb = Pools.StringBuilders.Get();
using var writer = new StringWriter(sb);
using var jsonWriter = SpeckleObjectSerializerPool.Instance.GetJsonTextWriter(writer);
id = SerializeBaseWithClosures(baseObj, jsonWriter, childClosures, true);
closures.IncrementClosures(childClosures);
json = new Json(writer.ToString());
Pools.StringBuilders.Return(sb);
}
Closures childClosures = [];
var sb = Pools.StringBuilders.Get();
using var writer = new StringWriter(sb);
using var jsonWriter = SpeckleObjectSerializerPool.Instance.GetJsonTextWriter(writer);
var id = SerializeBaseWithClosures(baseObj, jsonWriter, childClosures, true);
var json = new Json(writer.ToString());
Pools.StringBuilders.Return(sb);
closures.IncrementClosures(childClosures);
var json2 = ReferenceGenerator.CreateReference(id);
closures.MergeClosure(id);
// add to obj refs to return
@@ -12,6 +12,6 @@ public class ObjectSerializerFactory(IBasePropertyGatherer propertyGatherer) : I
private readonly Pool<List<DataChunk>> _chunk2Pool = Pools.CreateListPool<DataChunk>();
private readonly Pool<List<object?>> _chunk3Pool = Pools.CreateListPool<object?>();
public IObjectSerializer Create(IReadOnlyDictionary<Id, NodeInfo> baseCache, CancellationToken cancellationToken) =>
new ObjectSerializer(propertyGatherer, baseCache, _chunkPool, _chunk2Pool, _chunk3Pool, cancellationToken);
public IObjectSerializer Create(CancellationToken cancellationToken) =>
new ObjectSerializer(propertyGatherer, _chunkPool, _chunk2Pool, _chunk3Pool, cancellationToken);
}
@@ -1,4 +1,3 @@
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Logging;
using Speckle.InterfaceGenerator;
@@ -37,8 +36,8 @@ public sealed class SerializeProcess(
IBaseChildFinder baseChildFinder,
IBaseSerializer baseSerializer,
ILoggerFactory loggerFactory,
CancellationToken cancellationToken,
SerializeProcessOptions? options = null
SerializeProcessOptions options,
CancellationToken cancellationToken
) : ISerializeProcess
{
private static readonly Dictionary<Id, NodeInfo> EMPTY_CLOSURES = new();
@@ -64,13 +63,8 @@ public sealed class SerializeProcess(
ThreadPriority.BelowNormal,
Environment.ProcessorCount * 2
);
private readonly SerializeProcessOptions _options = options ?? new();
private readonly Pool<Dictionary<Id, NodeInfo>> _currentClosurePool = Pools.CreateDictionaryPool<Id, NodeInfo>();
private readonly Pool<ConcurrentDictionary<Id, NodeInfo>> _childClosurePool = Pools.CreateConcurrentDictionaryPool<
Id,
NodeInfo
>();
private readonly Pool<List<Task<Dictionary<Id, NodeInfo>>>> _taskResultPool = Pools.CreateListPool<
Task<Dictionary<Id, NodeInfo>>
@@ -113,13 +107,13 @@ public sealed class SerializeProcess(
try
{
var channelTask = objectSaver.Start(
options?.MaxParallelism,
options?.MaxHttpSendBatchSize,
options?.MaxCacheBatchSize,
options.MaxParallelism,
options.MaxHttpSendBatchSize,
options.MaxCacheBatchSize,
_processSource.Token
);
var findTotalObjectsTask = Task.CompletedTask;
if (!_options.SkipFindTotalObjects)
if (!options.SkipFindTotalObjects)
{
ThrowIfFailed();
findTotalObjectsTask = Task.Factory.StartNew(
@@ -225,7 +219,6 @@ public sealed class SerializeProcess(
return EMPTY_CLOSURES;
}
var childClosures = _childClosurePool.Get();
foreach (var childClosure in taskClosures)
{
if (IsCancelled())
@@ -234,7 +227,6 @@ public sealed class SerializeProcess(
}
foreach (var kvp in childClosure)
{
childClosures[kvp.Key] = kvp.Value;
if (IsCancelled())
{
return EMPTY_CLOSURES;
@@ -249,7 +241,7 @@ public sealed class SerializeProcess(
return EMPTY_CLOSURES;
}
var items = baseSerializer.Serialise(obj, childClosures, _options.SkipCacheRead, _processSource.Token);
var items = baseSerializer.Serialise(obj, options.SkipCacheRead, _processSource.Token);
if (IsCancelled())
{
@@ -257,32 +249,26 @@ public sealed class SerializeProcess(
}
var currentClosures = _currentClosurePool.Get();
try
Interlocked.Increment(ref _objectCount);
progress?.Report(new(ProgressEvent.FromCacheOrSerialized, _objectCount, Math.Max(_objectCount, _objectsFound)));
foreach (var item in items)
{
Interlocked.Increment(ref _objectCount);
progress?.Report(new(ProgressEvent.FromCacheOrSerialized, _objectCount, Math.Max(_objectCount, _objectsFound)));
foreach (var item in items)
if (IsCancelled())
{
if (IsCancelled())
{
return EMPTY_CLOSURES;
}
if (item.NeedsStorage)
{
Interlocked.Increment(ref _objectsSerialized);
await objectSaver.SaveAsync(item).ConfigureAwait(false);
}
if (!currentClosures.ContainsKey(item.Id))
{
currentClosures.Add(item.Id, new NodeInfo(item.Json, item.Closures));
}
return EMPTY_CLOSURES;
}
if (item.NeedsStorage)
{
Interlocked.Increment(ref _objectsSerialized);
await objectSaver.SaveAsync(item).ConfigureAwait(false);
}
if (!currentClosures.ContainsKey(item.Id))
{
currentClosures.Add(item.Id, new NodeInfo(item.Json, item.Closures));
}
}
finally
{
_childClosurePool.Return(childClosures);
}
return currentClosures;
@@ -44,13 +44,14 @@ public class SerializeProcessFactory(
sqLiteJsonCacheManager,
serverObjectManager,
loggerFactory.CreateLogger<ObjectSaver>(),
options ?? new SerializeProcessOptions(),
cancellationToken
),
baseChildFinder,
new BaseSerializer(sqLiteJsonCacheManager, objectSerializerFactory),
loggerFactory,
cancellationToken,
options
options ?? new SerializeProcessOptions(),
cancellationToken
);
public ISerializeProcess CreateSerializeProcess(
@@ -51,6 +51,7 @@ public class ServerObjectManager : IServerObjectManager
public async IAsyncEnumerable<(string, string)> DownloadObjects(
IReadOnlyCollection<string> objectIds,
string? attributeMask,
IProgress<ProgressArgs>? progress,
[EnumeratorCancellation] CancellationToken cancellationToken
)
@@ -59,10 +60,14 @@ public class ServerObjectManager : IServerObjectManager
cancellationToken.ThrowIfCancellationRequested();
using var childrenHttpMessage = new HttpRequestMessage();
childrenHttpMessage.RequestUri = new Uri($"/api/getobjects/{_streamId}", UriKind.Relative);
childrenHttpMessage.RequestUri = new Uri($"/api/v2/projects/{_streamId}/object-stream/", UriKind.Relative);
childrenHttpMessage.Method = HttpMethod.Post;
Dictionary<string, string> postParameters = new() { { "objects", JsonConvert.SerializeObject(objectIds) } };
Dictionary<string, object> postParameters = new() { { "objectIds", objectIds } };
if (!string.IsNullOrWhiteSpace(attributeMask))
{
postParameters.Add("attributeMask", attributeMask.NotNull());
}
string serializedPayload = JsonConvert.SerializeObject(postParameters);
childrenHttpMessage.Content = new StringContent(serializedPayload, Encoding.UTF8, "application/json");
childrenHttpMessage.Headers.Add("Accept", "text/plain");
@@ -18,10 +18,7 @@ public sealed class ObjectsSerializationTest
private static IReadOnlyList<(Id, Json, Dictionary<Id, int>)> Serialize(Base data)
{
using var serializer = new ObjectSerializerFactory(new BasePropertyGatherer()).Create(
new Dictionary<Id, NodeInfo>(),
default
);
using var serializer = new ObjectSerializerFactory(new BasePropertyGatherer()).Create(default);
return serializer.Serialize(data).ToList();
}
@@ -41,7 +41,7 @@ public class DataObjectTests
new DummyServerObjectManager(),
null,
default,
new SerializeProcessOptions(true, true, false, true)
new SerializeProcessOptions(false, false, true, true)
);
await serializeProcess.Serialize(x);
await VerifyJson(json.Single().Value.Value).UseParameters(type);
@@ -41,7 +41,7 @@ public class DetachedTests
objects,
null,
default,
new SerializeProcessOptions(false, false, true, true)
new SerializeProcessOptions(true, true, false, true)
);
await serializeProcess.Serialize(@base);
@@ -123,7 +123,7 @@ public class DetachedTests
objects,
null,
default,
new SerializeProcessOptions(false, false, true, true) { MaxParallelism = 1, MaxHttpSendBatchSize = 1 }
new SerializeProcessOptions(true, true, false, true) { MaxParallelism = 1, MaxHttpSendBatchSize = 1 }
);
var results = await serializeProcess.Serialize(@base);
@@ -150,7 +150,7 @@ public class DetachedTests
objects,
null,
default,
new SerializeProcessOptions(false, false, true, true) { MaxParallelism = 1, MaxHttpSendBatchSize = 1 }
new SerializeProcessOptions(true, true, false, true) { MaxParallelism = 1, MaxHttpSendBatchSize = 1 }
);
var results = await serializeProcess.Serialize(@base);
@@ -172,7 +172,7 @@ public class DetachedTests
objects,
null,
default,
new SerializeProcessOptions(false, false, true, true) { MaxParallelism = 1, MaxHttpSendBatchSize = 1 }
new SerializeProcessOptions(true, true, false, true) { MaxParallelism = 1, MaxHttpSendBatchSize = 1 }
);
var results = await serializeProcess.Serialize(@base);
@@ -239,7 +239,7 @@ public class DetachedTests
objects,
null,
default,
new SerializeProcessOptions(false, false, true, true)
new SerializeProcessOptions(true, true, false, true)
);
var results = await serializeProcess.Serialize(@base);
@@ -272,7 +272,7 @@ public class DetachedTests
objects,
null,
default,
new SerializeProcessOptions(false, false, true, true)
new SerializeProcessOptions(true, true, false, true)
);
var results = await serializeProcess.Serialize(@base);
await VerifyJsonDictionary(objects);
@@ -338,6 +338,7 @@ public class DummyServerObjectManager : IServerObjectManager
{
public IAsyncEnumerable<(string, string)> DownloadObjects(
IReadOnlyCollection<string> objectIds,
string? attributeMask,
IProgress<ProgressArgs>? progress,
CancellationToken cancellationToken
) => throw new NotImplementedException();
@@ -112,6 +112,7 @@ public class ExceptionTests
new DummySqLiteReceiveManager(new Dictionary<string, string>()),
new ExceptionServerObjectManager(),
null,
null,
new NullLogger<ObjectLoader>(),
default
);
@@ -203,7 +204,7 @@ public class ExceptionTests
public void Test_SpeckleSerializerException()
{
var factory = new ObjectSerializerFactory(new BasePropertyGatherer());
var serializer = factory.Create(new Dictionary<Id, NodeInfo>(), default);
var serializer = factory.Create(default);
Assert.Throws<SpeckleSerializeException>(() =>
{
var _ = serializer.Serialize(new BadBase()).ToList();
@@ -3,7 +3,6 @@ using Speckle.Objects.Primitive;
using Speckle.Sdk.Host;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Extensions;
using Speckle.Sdk.Serialisation;
using Speckle.Sdk.Serialisation.V2.Send;
namespace Speckle.Sdk.Serialization.Tests;
@@ -20,10 +19,7 @@ public class ExternalIdTests
public async Task ExternalIdTest_Detached()
{
var p = new Polyline() { units = "cm", value = [1, 2] };
using var serializer = new ObjectSerializerFactory(new BasePropertyGatherer()).Create(
new Dictionary<Id, NodeInfo>(),
default
);
using var serializer = new ObjectSerializerFactory(new BasePropertyGatherer()).Create(default);
var objects = serializer.Serialize(p).ToDictionary(x => x.Item1, x => x.Item2);
await VerifyJsonDictionary(objects);
@@ -45,10 +41,7 @@ public class ExternalIdTests
knots = [],
weights = [],
};
using var serializer = new ObjectSerializerFactory(new BasePropertyGatherer()).Create(
new Dictionary<Id, NodeInfo>(),
default
);
using var serializer = new ObjectSerializerFactory(new BasePropertyGatherer()).Create(default);
var objects = serializer.Serialize(curve).ToDictionary(x => x.Item1, x => x.Item2);
await VerifyJsonDictionary(objects);
@@ -71,10 +64,7 @@ public class ExternalIdTests
weights = [],
};
var polycurve = new Polycurve() { segments = [curve], units = "cm" };
using var serializer = new ObjectSerializerFactory(new BasePropertyGatherer()).Create(
new Dictionary<Id, NodeInfo>(),
default
);
using var serializer = new ObjectSerializerFactory(new BasePropertyGatherer()).Create(default);
var objects = serializer.Serialize(polycurve).ToDictionary(x => x.Item1, x => x.Item2);
await VerifyJsonDictionary(objects);
@@ -99,10 +89,7 @@ public class ExternalIdTests
var polycurve = new Polycurve() { segments = [curve], units = "cm" };
var @base = new Base();
@base.SetDetachedProp("profile", polycurve);
using var serializer = new ObjectSerializerFactory(new BasePropertyGatherer()).Create(
new Dictionary<Id, NodeInfo>(),
default
);
using var serializer = new ObjectSerializerFactory(new BasePropertyGatherer()).Create(default);
var objects = serializer.Serialize(@base).ToDictionary(x => x.Item1, x => x.Item2);
await VerifyJsonDictionary(objects);
}
@@ -8,6 +8,7 @@ public class ExceptionServerObjectManager : IServerObjectManager
{
public IAsyncEnumerable<(string, string)> DownloadObjects(
IReadOnlyCollection<string> objectIds,
string? attributeMask,
IProgress<ProgressArgs>? progress,
CancellationToken cancellationToken
) => throw new NotImplementedException();
@@ -150,7 +150,7 @@ public class SerializationTests
id.Should().Be(newId.Value);
}
[Theory]
[Theory(Skip = "Takes too long")]
[InlineData("RevitObject.json.gz", "3416d3fe01c9196115514c4a2f41617b", 7818)]
public async Task Roundtrip_Test_Old(string fileName, string _, int count)
{
@@ -186,8 +186,6 @@ public class SerializationTests
[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
[InlineData(4)]
public async Task Roundtrip_Test_New(int concurrency)
{
@@ -204,6 +202,7 @@ public class SerializationTests
new DummySqLiteReceiveManager(closures),
new DummyReceiveServerObjectManager(closures),
null,
null,
new NullLogger<ObjectLoader>(),
default
)
@@ -31,14 +31,17 @@ public class ServerObjectManagerTests : MoqTest
var jObject = new JObject { { "id", id }, { "value", true } };
var jObject2 = new JObject { { "id", id2 }, { "value", true } };
var mockHttp = new MockHttpMessageHandler();
Dictionary<string, string> postParameters = new()
Dictionary<string, object> postParameters = new()
{
{ "objects", JsonConvert.SerializeObject(new List<string> { id, id2 }) },
{
"objectIds",
new List<string> { id, id2 }
},
};
string serializedPayload = JsonConvert.SerializeObject(postParameters);
mockHttp
.When(HttpMethod.Post, $"http://localhost/api/getobjects/{streamId}")
.When(HttpMethod.Post, $"http://localhost/api/v2/projects/{streamId}/object-stream/")
.WithContent(serializedPayload)
.Respond(
"application/json",
@@ -59,7 +62,7 @@ public class ServerObjectManagerTests : MoqTest
token,
new(timeout: TimeSpan.FromSeconds(timeout))
);
var results = serverObjectManager.DownloadObjects(new List<string> { id, id2 }, null, ct);
var results = serverObjectManager.DownloadObjects(new List<string> { id, id2 }, null, null, ct);
var objects = new JObject();
await foreach (var (x, json) in results)
{
@@ -10,6 +10,7 @@ public class DummyReceiveServerObjectManager(IReadOnlyDictionary<string, string>
{
public async IAsyncEnumerable<(string, string)> DownloadObjects(
IReadOnlyCollection<string> objectIds,
string? attributeMask,
IProgress<ProgressArgs>? progress,
[EnumeratorCancellation] CancellationToken cancellationToken
)
@@ -9,6 +9,7 @@ public class DummySendServerObjectManager(ConcurrentDictionary<string, string> s
{
public IAsyncEnumerable<(string, string)> DownloadObjects(
IReadOnlyCollection<string> objectIds,
string? attributeMask,
IProgress<ProgressArgs>? progress,
CancellationToken cancellationToken
) => throw new NotImplementedException();
@@ -31,6 +31,7 @@ public class SerializeProcessRecordExceptionTests : MoqTest
baseChildFinderMock.Object,
baseSerializerMock.Object,
loggerFactoryMock.Object,
new(),
cts.Token
);
var ex = new Exception("Test error");
@@ -67,6 +68,7 @@ public class SerializeProcessRecordExceptionTests : MoqTest
baseChildFinderMock.Object,
baseSerializerMock.Object,
loggerFactoryMock.Object,
new(),
cts.Token
);
var ex = new OperationCanceledException();
@@ -98,6 +100,7 @@ public class SerializeProcessRecordExceptionTests : MoqTest
baseChildFinderMock.Object,
baseSerializerMock.Object,
loggerFactoryMock.Object,
new(),
cts.Token
);
var ex = new AggregateException(new OperationCanceledException());