Implement Galaxy filters and API key constraints
This commit is contained in:
@@ -160,6 +160,37 @@ public sealed class GalaxyRepositoryClientTests
|
||||
Assert.Contains("repeated page token", exception.Message, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DiscoverHierarchyAsync_WithOptions_MapsTypedFilters()
|
||||
{
|
||||
FakeGalaxyRepositoryTransport transport = CreateTransport();
|
||||
await using GalaxyRepositoryClient client = CreateClient(transport);
|
||||
|
||||
await client.DiscoverHierarchyAsync(new DiscoverHierarchyOptions
|
||||
{
|
||||
RootContainedPath = "Area1/Line3",
|
||||
MaxDepth = 2,
|
||||
CategoryIds = [10, 13],
|
||||
TemplateChainContains = ["Pump"],
|
||||
TagNameGlob = "Pump_*",
|
||||
IncludeAttributes = false,
|
||||
AlarmBearingOnly = true,
|
||||
HistorizedOnly = true,
|
||||
});
|
||||
|
||||
DiscoverHierarchyRequest request = Assert.Single(transport.DiscoverHierarchyCalls).Request;
|
||||
Assert.Equal(DiscoverHierarchyRequest.RootOneofCase.RootContainedPath, request.RootCase);
|
||||
Assert.Equal("Area1/Line3", request.RootContainedPath);
|
||||
Assert.Equal(2, request.MaxDepth);
|
||||
Assert.Equal([10, 13], request.CategoryIds);
|
||||
Assert.Equal(["Pump"], request.TemplateChainContains);
|
||||
Assert.Equal("Pump_*", request.TagNameGlob);
|
||||
Assert.True(request.HasIncludeAttributes);
|
||||
Assert.False(request.IncludeAttributes);
|
||||
Assert.True(request.AlarmBearingOnly);
|
||||
Assert.True(request.HistorizedOnly);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TestConnectionAsync_RetriesOnTransientGrpcFailure()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace MxGateway.Client;
|
||||
|
||||
public sealed record DiscoverHierarchyOptions
|
||||
{
|
||||
public int? RootGobjectId { get; init; }
|
||||
|
||||
public string? RootTagName { get; init; }
|
||||
|
||||
public string? RootContainedPath { get; init; }
|
||||
|
||||
public int? MaxDepth { get; init; }
|
||||
|
||||
public IReadOnlyList<int> CategoryIds { get; init; } = Array.Empty<int>();
|
||||
|
||||
public IReadOnlyList<string> TemplateChainContains { get; init; } = Array.Empty<string>();
|
||||
|
||||
public string? TagNameGlob { get; init; }
|
||||
|
||||
public bool? IncludeAttributes { get; init; }
|
||||
|
||||
public bool AlarmBearingOnly { get; init; }
|
||||
|
||||
public bool HistorizedOnly { get; init; }
|
||||
}
|
||||
@@ -144,18 +144,24 @@ public sealed class GalaxyRepositoryClient : IAsyncDisposable
|
||||
/// they may subscribe to via the MxAccessGateway service.
|
||||
/// </summary>
|
||||
public async Task<IReadOnlyList<GalaxyObject>> DiscoverHierarchyAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await DiscoverHierarchyAsync(new DiscoverHierarchyOptions(), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<GalaxyObject>> DiscoverHierarchyAsync(
|
||||
DiscoverHierarchyOptions options,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
List<GalaxyObject> objects = [];
|
||||
HashSet<string> seenPageTokens = new(StringComparer.Ordinal);
|
||||
string pageToken = string.Empty;
|
||||
do
|
||||
{
|
||||
DiscoverHierarchyRequest request = CreateDiscoverHierarchyRequest(options);
|
||||
request.PageSize = DiscoverHierarchyPageSize;
|
||||
request.PageToken = pageToken;
|
||||
DiscoverHierarchyReply reply = await DiscoverHierarchyRawAsync(
|
||||
new DiscoverHierarchyRequest
|
||||
{
|
||||
PageSize = DiscoverHierarchyPageSize,
|
||||
PageToken = pageToken,
|
||||
},
|
||||
request,
|
||||
cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
@@ -173,6 +179,49 @@ public sealed class GalaxyRepositoryClient : IAsyncDisposable
|
||||
return objects;
|
||||
}
|
||||
|
||||
private static DiscoverHierarchyRequest CreateDiscoverHierarchyRequest(DiscoverHierarchyOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(options);
|
||||
|
||||
DiscoverHierarchyRequest request = new()
|
||||
{
|
||||
AlarmBearingOnly = options.AlarmBearingOnly,
|
||||
HistorizedOnly = options.HistorizedOnly,
|
||||
};
|
||||
|
||||
if (options.RootGobjectId.HasValue)
|
||||
{
|
||||
request.RootGobjectId = options.RootGobjectId.Value;
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(options.RootTagName))
|
||||
{
|
||||
request.RootTagName = options.RootTagName;
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(options.RootContainedPath))
|
||||
{
|
||||
request.RootContainedPath = options.RootContainedPath;
|
||||
}
|
||||
|
||||
if (options.MaxDepth.HasValue)
|
||||
{
|
||||
request.MaxDepth = options.MaxDepth.Value;
|
||||
}
|
||||
|
||||
request.CategoryIds.Add(options.CategoryIds);
|
||||
request.TemplateChainContains.Add(options.TemplateChainContains);
|
||||
if (!string.IsNullOrWhiteSpace(options.TagNameGlob))
|
||||
{
|
||||
request.TagNameGlob = options.TagNameGlob;
|
||||
}
|
||||
|
||||
if (options.IncludeAttributes.HasValue)
|
||||
{
|
||||
request.IncludeAttributes = options.IncludeAttributes.Value;
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
public Task<DiscoverHierarchyReply> DiscoverHierarchyRawAsync(
|
||||
DiscoverHierarchyRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -164,6 +164,19 @@ foreach (GalaxyObject galaxyObject in objects)
|
||||
}
|
||||
```
|
||||
|
||||
Use `DiscoverHierarchyOptions` to request a server-side slice without pulling
|
||||
the full Galaxy:
|
||||
|
||||
```csharp
|
||||
IReadOnlyList<GalaxyObject> pumps = await repository.DiscoverHierarchyAsync(
|
||||
new DiscoverHierarchyOptions
|
||||
{
|
||||
RootContainedPath = "Area1/Line3",
|
||||
TagNameGlob = "Pump_*",
|
||||
IncludeAttributes = false,
|
||||
});
|
||||
```
|
||||
|
||||
The CLI exposes the same operations:
|
||||
|
||||
```powershell
|
||||
|
||||
Reference in New Issue
Block a user