feat(dcl): BrowseNext continuation paging + StubOpcUaClient canned browse (T15)
This commit is contained in:
@@ -132,15 +132,21 @@ public interface IOpcUaClient : IAsyncDisposable
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates the immediate children of <paramref name="parentNodeId"/>
|
||||
/// (or the server's ObjectsFolder when null). Throws
|
||||
/// (or the server's ObjectsFolder when null). Pageable via the OPC UA
|
||||
/// continuation-point mechanism: when a prior call returned a non-null
|
||||
/// <see cref="BrowseChildrenResult.ContinuationToken"/>, pass it back via
|
||||
/// <paramref name="continuationToken"/> to fetch the next page (BrowseNext);
|
||||
/// a null/empty token starts a fresh browse. Throws
|
||||
/// <see cref="ConnectionNotConnectedException"/> when the session is not
|
||||
/// currently up.
|
||||
/// </summary>
|
||||
/// <param name="parentNodeId">Node id whose children to browse, or null for the server root.</param>
|
||||
/// <param name="continuationToken">Opaque token from a prior <see cref="BrowseChildrenResult.ContinuationToken"/> to fetch the next page via BrowseNext; null/empty starts a fresh browse.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
|
||||
/// <returns>A task that completes with the immediate children of the requested node.</returns>
|
||||
/// <returns>A task that completes with the immediate children of the requested node and a continuation token for the next page (null when exhausted).</returns>
|
||||
Task<BrowseChildrenResult> BrowseChildrenAsync(
|
||||
string? parentNodeId,
|
||||
string? continuationToken = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -235,8 +241,48 @@ internal class StubOpcUaClient : IOpcUaClient
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<BrowseChildrenResult> BrowseChildrenAsync(
|
||||
string? parentNodeId, CancellationToken cancellationToken = default)
|
||||
=> throw new NotImplementedException();
|
||||
string? parentNodeId, string? continuationToken = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// Canned address-space tree so DCL browse/paging flows can be exercised
|
||||
// without a live OPC UA server (T15):
|
||||
// (root)
|
||||
// ├─ Folder1 (Object, HasChildren=true)
|
||||
// │ ├─ Tag1 (Variable) ← page 1
|
||||
// │ └─ Tag2 (Variable) ← page 2 (continuation token "STUB_PAGE2")
|
||||
// └─ Folder2 (Object, HasChildren=false, leaf)
|
||||
// Folder1 fakes BrowseNext continuation paging so the continuation-token
|
||||
// round-trip is testable; everything else is a single, exhausted page.
|
||||
if (string.IsNullOrEmpty(parentNodeId))
|
||||
{
|
||||
return Task.FromResult(new BrowseChildrenResult(
|
||||
new[]
|
||||
{
|
||||
new BrowseNode("Folder1", "Folder1", BrowseNodeClass.Object, HasChildren: true),
|
||||
new BrowseNode("Folder2", "Folder2", BrowseNodeClass.Object, HasChildren: false),
|
||||
},
|
||||
Truncated: false));
|
||||
}
|
||||
|
||||
if (parentNodeId == "Folder1")
|
||||
{
|
||||
// Page 2: the caller passed back the continuation token from page 1.
|
||||
if (continuationToken == "STUB_PAGE2")
|
||||
{
|
||||
return Task.FromResult(new BrowseChildrenResult(
|
||||
new[] { new BrowseNode("Tag2", "Tag2", BrowseNodeClass.Variable, HasChildren: false) },
|
||||
Truncated: false));
|
||||
}
|
||||
|
||||
// Page 1: return only Tag1 and a continuation token for the next page.
|
||||
return Task.FromResult(new BrowseChildrenResult(
|
||||
new[] { new BrowseNode("Tag1", "Tag1", BrowseNodeClass.Variable, HasChildren: false) },
|
||||
Truncated: true,
|
||||
ContinuationToken: "STUB_PAGE2"));
|
||||
}
|
||||
|
||||
// Leaves (Folder2, Variable nodes, anything unknown) have no children.
|
||||
return Task.FromResult(new BrowseChildrenResult(Array.Empty<BrowseNode>(), Truncated: false));
|
||||
}
|
||||
|
||||
/// <summary>Disposes this stub client and marks the connection as closed.</summary>
|
||||
/// <returns>A completed <see cref="ValueTask"/>.</returns>
|
||||
|
||||
Reference in New Issue
Block a user