feat(grpc): tool the WCF-only config ops over the gRPC transport
Wire the config operations that previously only worked over WCF onto RemoteGrpc, reusing the proven 2020 byte serializers verbatim inside the protobuf bytes fields (keyed by the Open2 session handle). Live-verified against a real 2023 R2 server where noted. Read ops (live-verified): - GetRuntimeParameterAsync -> StatusService.GetRuntimeParameter (GETRP serializer) - GetTagExtendedPropertiesAsync -> RetrievalService.GetTagExtendedPropertiesFromName (GetTepByNm serializer + sequence paging; page-0 FillBufferFromVector is the benign no-data terminator, matched to the WCF break-and-return-empty semantics) Server-walled (bounded with captured evidence): - ExecuteSqlCommandAsync -> RetrievalService.ExecuteSqlCommand. The request rides the RPC but the server-side CSrvDbConnection.ExecuteSqlCommand faults (IndexOutOfRange / native err 38) on a DB-connection precondition the pure managed gRPC session doesn't establish (same class as OpenStorageConnection). Surfaced as ProtocolEvidenceMissingException. Write ops (tooled + routed, sandbox-gated — not run destructively live): - EnsureTagAsync / DeleteTagAsync / RenameTagsAsync / AddTagExtendedPropertiesAsync via HistoryService.EnsureTags / DeleteTags / StartJob / AddTagExtendedProperties on a write-enabled (0x401) session, reusing the WCF golden serializers. The WCF priming discovery-dance is omitted (the M3 gRPC write probe worked without it); add it first if a live sandbox run is rejected. Routed in Historian2020ProtocolDialect / HistorianClient on the RemoteGrpc branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B6mcaT2PjRFKcogzp9UkfC
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using AVEVA.Historian.Client.Models;
|
||||
using AVEVA.Historian.Client.Wcf;
|
||||
using GrpcStatus = ArchestrA.Grpc.Contract.Status;
|
||||
|
||||
namespace AVEVA.Historian.Client.Grpc;
|
||||
@@ -142,4 +144,46 @@ internal static class HistorianGrpcStatusClient
|
||||
string? value = response.StrSystemTimeZoneName;
|
||||
return string.IsNullOrEmpty(value) ? null : value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a Historian runtime parameter over gRPC (<c>StatusService.GetRuntimeParameter</c>).
|
||||
/// The request/response byte buffers are the proven 2020 <c>GETRP</c> wire format
|
||||
/// (<see cref="HistorianRuntimeParameterProtocol"/>) carried unchanged inside the protobuf
|
||||
/// <c>btRequest</c>/<c>btResponse</c> fields; the op keys on the uppercase string session handle.
|
||||
/// </summary>
|
||||
public static Task<string?> GetRuntimeParameterAsync(
|
||||
HistorianClientOptions options,
|
||||
string parameterName,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(parameterName);
|
||||
return Task.Run(() => GetRuntimeParameter(options, parameterName, cancellationToken), cancellationToken);
|
||||
}
|
||||
|
||||
private static string? GetRuntimeParameter(HistorianClientOptions options, string parameterName, CancellationToken cancellationToken)
|
||||
{
|
||||
using HistorianGrpcConnection connection = HistorianGrpcChannelFactory.Create(options);
|
||||
HistorianGrpcHandshake.Session session = HistorianGrpcHandshake.OpenSession(connection, options, cancellationToken);
|
||||
|
||||
byte[] request = HistorianRuntimeParameterProtocol.SerializeRequest(parameterName);
|
||||
|
||||
var statusClient = new GrpcStatus.StatusService.StatusServiceClient(connection.Channel);
|
||||
GrpcStatus.GetRuntimeParameterResponse response = statusClient.GetRuntimeParameter(
|
||||
new GrpcStatus.GetRuntimeParameterRequest
|
||||
{
|
||||
StrHandle = session.StringHandle,
|
||||
BtRequest = ByteString.CopyFrom(request)
|
||||
},
|
||||
connection.Metadata,
|
||||
DateTime.UtcNow.Add(options.RequestTimeout),
|
||||
cancellationToken);
|
||||
|
||||
if (!(response.Status?.BSuccess ?? false))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] responseBuffer = response.BtResponse?.ToByteArray() ?? [];
|
||||
return HistorianRuntimeParameterProtocol.ParseSingleStringResult(responseBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user