diff --git a/.editorconfig b/.editorconfig
index 0ccff01..32c963d 100755
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,10 +1,31 @@
-# How to format:
-# (1) Add dotnet_diagnostic.XXXX.severity = error
-# (2) Run dotnet-format: dotnet format --diagnostics XXXX
+# How to apply single rule:
+# Run dotnet format --diagnostics XXXX --severity info
+
+# How to apply all rules:
+# Run dotnet format --severity error/info/warn/
+
+[*]
+trim_trailing_whitespace = true
[*.cs]
# "run cleanup": https://betterprogramming.pub/enforce-net-code-style-with-editorconfig-d2f0d79091ac
-# TODO: build real editorconfig file: https://github.com/dotnet/roslyn/blob/main/.editorconfig
+# TODO: build real editorconfig file: https://github.com/dotnet/roslyn/blob/main/.editorconfig
+
+# Prefer var
+csharp_style_var_for_built_in_types = false
+csharp_style_var_when_type_is_apparent = true
+csharp_style_var_elsewhere = true
+dotnet_diagnostic.IDE0007.severity = warning
+
+# Make field
+dotnet_diagnostic.IDE0044.severity = warning
+
+# Use file scoped namespace declarations
+dotnet_diagnostic.IDE0161.severity = error
+csharp_style_namespace_declarations = file_scoped
+
+# Collection initialization can be simplified
+dotnet_diagnostic.IDE0300.severity = warning
# Enable naming rule violation errors on build (alternative: dotnet_analyzer_diagnostic.category-Style.severity = error)
dotnet_diagnostic.IDE1006.severity = error
diff --git a/.gitignore b/.gitignore
index e95dc5b..4bbc1fa 100755
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
.vs/
+.venv/
+
artifacts/
BenchmarkDotNet.Artifacts
diff --git a/Directory.Build.props b/Directory.Build.props
index a73d076..db678da 100755
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -2,7 +2,7 @@
true
- net7.0
+ net8.0
enable
enable
true
diff --git a/src/Nexus.Sources.Federation/Federation.cs b/src/Nexus.Sources.Federation/Federation.cs
index a451fb9..4d9cb53 100644
--- a/src/Nexus.Sources.Federation/Federation.cs
+++ b/src/Nexus.Sources.Federation/Federation.cs
@@ -6,141 +6,136 @@
using Nexus.DataModel;
using Nexus.Extensibility;
-namespace Nexus.Sources
+namespace Nexus.Sources;
+
+[ExtensionDescription(
+ "Provides access to other Nexus databases.",
+ "https://github.com/Apollo3zehn/nexus-sources-federation",
+ "https://github.com/Apollo3zehn/nexus-sources-federation")]
+public class Federation : IDataSource
{
- [ExtensionDescription(
- "Provides access to other Nexus databases.",
- "https://github.com/Apollo3zehn/nexus-sources-federation",
- "https://github.com/Apollo3zehn/nexus-sources-federation")]
- public class Federation : IDataSource
- {
- private DataSourceContext _context = default!;
- private Api.INexusClient _nexusClient = default!;
- private string _sourcePath = "/";
- private string _mountPoint = "/";
- private string _includePattern = default!;
+ private DataSourceContext _context = default!;
+ private Api.INexusClient _nexusClient = default!;
+ private string _sourcePath = "/";
+ private string _mountPoint = "/";
+ private string _includePattern = default!;
- private static JsonSerializerOptions _jsonSerializerOptions;
+ private static readonly JsonSerializerOptions _jsonSerializerOptions;
- static Federation()
- {
- _jsonSerializerOptions = new JsonSerializerOptions();
- _jsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
- }
+ static Federation()
+ {
+ _jsonSerializerOptions = new JsonSerializerOptions();
+ _jsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
+ }
- public Func CreateNexusClient { get; set; }
- = httpClient => new Api.NexusClient(httpClient);
+ public Func CreateNexusClient { get; set; }
+ = httpClient => new Api.NexusClient(httpClient);
- public Task SetContextAsync(DataSourceContext context, ILogger logger, CancellationToken cancellationToken)
- {
- _context = context;
+ public Task SetContextAsync(DataSourceContext context, ILogger logger, CancellationToken cancellationToken)
+ {
+ _context = context;
- // http client
- if (_context.ResourceLocator is null)
- throw new Exception("The resource locator must be set.");
+ // http client
+ if (_context.ResourceLocator is null)
+ throw new Exception("The resource locator must be set.");
- var httpClient = new HttpClient()
- {
- BaseAddress = _context.ResourceLocator
- };
+ var httpClient = new HttpClient()
+ {
+ BaseAddress = _context.ResourceLocator
+ };
- // token
- var token = _context.SourceConfiguration?.GetStringValue($"access-token");
+ // token
+ var token = (_context.SourceConfiguration?.GetStringValue($"access-token")) ?? throw new Exception("The access-token property is not set.");
+ httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
- if (token is null)
- throw new Exception("The access-token property is not set.");
+ _nexusClient = CreateNexusClient(httpClient);
- httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
+ // source-path
+ var sourcePath = _context.SourceConfiguration?.GetStringValue($"source-path");
- _nexusClient = CreateNexusClient(httpClient);
+ if (sourcePath is not null)
+ _sourcePath = '/' + sourcePath.Trim('/');
- // source-path
- var sourcePath = _context.SourceConfiguration?.GetStringValue($"source-path");
+ // mount-point
+ var mountPoint = _context.SourceConfiguration?.GetStringValue($"mount-point");
- if (sourcePath is not null)
- _sourcePath = '/' + sourcePath.Trim('/');
+ if (mountPoint is not null)
+ _mountPoint = '/' + mountPoint.Trim('/');
- // mount-point
- var mountPoint = _context.SourceConfiguration?.GetStringValue($"mount-point");
+ // include-pattern
+ var includePattern = _context.SourceConfiguration?.GetStringValue($"include-pattern");
+ _includePattern = includePattern ?? "";
- if (mountPoint is not null)
- _mountPoint = '/' + mountPoint.Trim('/');
+ return Task.CompletedTask;
+ }
- // include-pattern
- var includePattern = _context.SourceConfiguration?.GetStringValue($"include-pattern");
- _includePattern = includePattern ?? "";
+ public async Task GetCatalogRegistrationsAsync(string path, CancellationToken cancellationToken)
+ {
+ if (path == "/")
+ path = _mountPoint;
- return Task.CompletedTask;
- }
+ var catalogInfos = await _nexusClient.Catalogs.GetChildCatalogInfosAsync(ToSourcePathPrefixedCatalogId(path), cancellationToken);
- public async Task GetCatalogRegistrationsAsync(string path, CancellationToken cancellationToken)
- {
- if (path == "/")
- path = _mountPoint;
+ return catalogInfos
+ .Where(catalogInfo => Regex.IsMatch(catalogInfo.Id, _includePattern))
+ .Select(catalogInfo => new CatalogRegistration(ToMountPointPrefixedCatalogId(catalogInfo.Id), catalogInfo.Title, IsTransient: true))
+ .ToArray();
+ }
- var catalogInfos = await _nexusClient.Catalogs.GetChildCatalogInfosAsync(ToSourcePathPrefixedCatalogId(path), cancellationToken);
+ public async Task GetCatalogAsync(string catalogId, CancellationToken cancellationToken)
+ {
+ var resourceCatalog = await _nexusClient.Catalogs.GetAsync(ToSourcePathPrefixedCatalogId(catalogId), cancellationToken);
+ resourceCatalog = resourceCatalog with { Id = catalogId };
- return catalogInfos
- .Where(catalogInfo => Regex.IsMatch(catalogInfo.Id, _includePattern))
- .Select(catalogInfo => new CatalogRegistration(ToMountPointPrefixedCatalogId(catalogInfo.Id), catalogInfo.Title, IsTransient: true))
- .ToArray();
- }
+ var jsonString = JsonSerializer.Serialize(resourceCatalog, _jsonSerializerOptions);
+ var actualResourceCatalog = JsonSerializer.Deserialize(jsonString, _jsonSerializerOptions)!;
- public async Task GetCatalogAsync(string catalogId, CancellationToken cancellationToken)
- {
- var resourceCatalog = await _nexusClient.Catalogs.GetAsync(ToSourcePathPrefixedCatalogId(catalogId));
- resourceCatalog = resourceCatalog with { Id = catalogId };
+ return actualResourceCatalog;
+ }
- var jsonString = JsonSerializer.Serialize(resourceCatalog, _jsonSerializerOptions);
- var actualResourceCatalog = JsonSerializer.Deserialize(jsonString, _jsonSerializerOptions)!;
+ public async Task GetAvailabilityAsync(string catalogId, DateTime begin, DateTime end, CancellationToken cancellationToken)
+ {
+ var availability = await _nexusClient.Catalogs
+ .GetAvailabilityAsync(ToSourcePathPrefixedCatalogId(catalogId), begin, end, end - begin, cancellationToken);
- return actualResourceCatalog;
- }
+ return availability.Data[0];
+ }
- public async Task GetAvailabilityAsync(string catalogId, DateTime begin, DateTime end, CancellationToken cancellationToken)
- {
- var availability = await _nexusClient.Catalogs
- .GetAvailabilityAsync(ToSourcePathPrefixedCatalogId(catalogId), begin, end, end - begin, cancellationToken);
+ public async Task<(DateTime Begin, DateTime End)> GetTimeRangeAsync(string catalogId, CancellationToken cancellationToken)
+ {
+ var timeRange = await _nexusClient.Catalogs
+ .GetTimeRangeAsync(ToSourcePathPrefixedCatalogId(catalogId), cancellationToken);
- return availability.Data[0];
- }
+ return (timeRange.Begin, timeRange.End);
+ }
- public async Task<(DateTime Begin, DateTime End)> GetTimeRangeAsync(string catalogId, CancellationToken cancellationToken)
+ public async Task ReadAsync(DateTime begin, DateTime end, ReadRequest[] requests, ReadDataHandler readData, IProgress progress, CancellationToken cancellationToken)
+ {
+ foreach (var request in requests)
{
- var timeRange = await _nexusClient.Catalogs
- .GetTimeRangeAsync(ToSourcePathPrefixedCatalogId(catalogId), cancellationToken);
-
- return (timeRange.Begin, timeRange.End);
- }
+ var response = await _nexusClient.Data.GetStreamAsync(ToSourcePathPrefixedCatalogId(request.CatalogItem.ToPath()), begin, end, cancellationToken);
+ var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
+ var targetBuffer = request.Data;
- public async Task ReadAsync(DateTime begin, DateTime end, ReadRequest[] requests, ReadDataHandler readData, IProgress progress, CancellationToken cancellationToken)
- {
- foreach (var request in requests)
+ while (targetBuffer.Length > 0)
{
- var response = await _nexusClient.Data.GetStreamAsync(ToSourcePathPrefixedCatalogId(request.CatalogItem.ToPath()), begin, end, cancellationToken);
- var stream = await response.Content.ReadAsStreamAsync();
- var targetBuffer = request.Data;
-
- while (targetBuffer.Length > 0)
- {
- var bytesRead = await stream.ReadAsync(targetBuffer);
- targetBuffer = targetBuffer.Slice(bytesRead);
- }
-
- request.Status.Span.Fill(1);
+ var bytesRead = await stream.ReadAsync(targetBuffer, cancellationToken);
+ targetBuffer = targetBuffer[bytesRead..];
}
- }
- private string ToMountPointPrefixedCatalogId(string catalogId)
- {
- // absolute, relative
- return Path.Combine(_mountPoint, catalogId.Substring(_sourcePath.Length).TrimStart('/'));
+ request.Status.Span.Fill(1);
}
+ }
- private string ToSourcePathPrefixedCatalogId(string catalogId)
- {
- // absolute, relative
- return Path.Combine(_sourcePath, catalogId.Substring(_mountPoint.Length).TrimStart('/'));
- }
+ private string ToMountPointPrefixedCatalogId(string catalogId)
+ {
+ // absolute, relative
+ return Path.Combine(_mountPoint, catalogId[_sourcePath.Length..].TrimStart('/'));
+ }
+
+ private string ToSourcePathPrefixedCatalogId(string catalogId)
+ {
+ // absolute, relative
+ return Path.Combine(_sourcePath, catalogId[_mountPoint.Length..].TrimStart('/'));
}
}
diff --git a/src/Nexus.Sources.Federation/Nexus.Sources.Federation.csproj b/src/Nexus.Sources.Federation/Nexus.Sources.Federation.csproj
index b216f94..d044c2b 100644
--- a/src/Nexus.Sources.Federation/Nexus.Sources.Federation.csproj
+++ b/src/Nexus.Sources.Federation/Nexus.Sources.Federation.csproj
@@ -6,8 +6,8 @@
-
-
+
+
runtime;native
diff --git a/tests/Nexus.Sources.Federation.Tests/FederationTests.cs b/tests/Nexus.Sources.Federation.Tests/FederationTests.cs
index f01de5b..ce7d9bb 100644
--- a/tests/Nexus.Sources.Federation.Tests/FederationTests.cs
+++ b/tests/Nexus.Sources.Federation.Tests/FederationTests.cs
@@ -32,7 +32,7 @@ public async Task ProvidesCatalogRegistrations(string? sourcePath, string? mount
It.IsAny(),
It.IsAny()
))
- .ReturnsAsync((string catalogId, CancellationToken cancellationToken) =>
+ .ReturnsAsync((string catalogId, CancellationToken cancellationToken) =>
{
Assert.True(catalogId.StartsWith('/'));
diff --git a/tests/Nexus.Sources.Federation.Tests/Nexus.Sources.Federation.Tests.csproj b/tests/Nexus.Sources.Federation.Tests/Nexus.Sources.Federation.Tests.csproj
index f89d76e..ebea1a0 100644
--- a/tests/Nexus.Sources.Federation.Tests/Nexus.Sources.Federation.Tests.csproj
+++ b/tests/Nexus.Sources.Federation.Tests/Nexus.Sources.Federation.Tests.csproj
@@ -8,7 +8,7 @@
-
+
all