feat(mesh): deployment_artifact.v1 proto + first in-repo Grpc.Tools codegen
The repo has consumed packaged gRPC clients (LocalDb.Replication, HistorianGateway.Client) but never compiled a proto locally. This adds the Grpc.Tools toolchain to Commons and a deployment_artifact.proto with a single server-streaming Fetch(deployment_id) -> stream ArtifactChunk RPC, generating both the server base and the client stub (GrpcServices="Both") so central (Host/AdminUI) and the node (Runtime) share one reference. A compile-touch test pins the codegen: it stops compiling if generation regresses. Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
<PackageVersion Include="Grpc.AspNetCore" Version="2.76.0" />
|
<PackageVersion Include="Grpc.AspNetCore" Version="2.76.0" />
|
||||||
<PackageVersion Include="Grpc.Core.Api" Version="2.76.0" />
|
<PackageVersion Include="Grpc.Core.Api" Version="2.76.0" />
|
||||||
<PackageVersion Include="Grpc.Net.Client" Version="2.76.0" />
|
<PackageVersion Include="Grpc.Net.Client" Version="2.76.0" />
|
||||||
|
<PackageVersion Include="Grpc.Tools" Version="2.76.0" />
|
||||||
<PackageVersion Include="libplctag" Version="1.5.2" />
|
<PackageVersion Include="libplctag" Version="1.5.2" />
|
||||||
<PackageVersion Include="MessagePack" Version="2.5.301" />
|
<PackageVersion Include="MessagePack" Version="2.5.301" />
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="10.0.7" />
|
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="10.0.7" />
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package deployment_artifact.v1;
|
||||||
|
|
||||||
|
option csharp_namespace = "ZB.MOM.WW.OtOpcUa.Commons.Protos.DeploymentArtifact.V1";
|
||||||
|
|
||||||
|
// Central serves the deployed-configuration artifact bytes to a driver node (per-cluster mesh
|
||||||
|
// Phase 3). Only admin-role nodes — which hold the central SQL connection — serve; driver nodes in
|
||||||
|
// FetchAndCache mode are the clients. The bytes travel here, out-of-band, precisely so they never
|
||||||
|
// ride an Akka message and hit the frame-size limit.
|
||||||
|
service DeploymentArtifactService {
|
||||||
|
// Streams the artifact for a sealed deployment as ordered chunks. NotFound when the id is
|
||||||
|
// unknown, the deployment is not sealed, or the blob is empty (existence-hiding + the #485
|
||||||
|
// "empty bytes are never an empty config" rule). The client verifies
|
||||||
|
// SHA-256(reassembled) == the RevisionHash it already holds from DispatchDeployment, so no hash
|
||||||
|
// is carried here.
|
||||||
|
rpc Fetch(FetchRequest) returns (stream ArtifactChunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
message FetchRequest {
|
||||||
|
string deployment_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ArtifactChunk {
|
||||||
|
bytes data = 1;
|
||||||
|
}
|
||||||
@@ -11,6 +11,24 @@
|
|||||||
<PackageReference Include="ZB.MOM.WW.Audit"/>
|
<PackageReference Include="ZB.MOM.WW.Audit"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Per-cluster mesh Phase 3: the first locally-compiled proto in the repo (all other gRPC here
|
||||||
|
is packaged clients). Grpc.Tools generates both the server base and the client stub from
|
||||||
|
deployment_artifact.proto; Google.Protobuf + Grpc.Core.Api carry the generated code's runtime
|
||||||
|
types. Placed in Commons so both the central server (Host/AdminUI) and the node client
|
||||||
|
(Runtime) get the types from one reference. -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Google.Protobuf"/>
|
||||||
|
<PackageReference Include="Grpc.Core.Api"/>
|
||||||
|
<PackageReference Include="Grpc.Tools">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Protobuf Include="Protos\deployment_artifact.proto" GrpcServices="Both"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\ZB.MOM.WW.OtOpcUa.Core.Abstractions\ZB.MOM.WW.OtOpcUa.Core.Abstractions.csproj"/>
|
<ProjectReference Include="..\ZB.MOM.WW.OtOpcUa.Core.Abstractions\ZB.MOM.WW.OtOpcUa.Core.Abstractions.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using Shouldly;
|
||||||
|
using Xunit;
|
||||||
|
using ZB.MOM.WW.OtOpcUa.Commons.Protos.DeploymentArtifact.V1;
|
||||||
|
|
||||||
|
namespace ZB.MOM.WW.OtOpcUa.Commons.Tests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A compile-touch test: it exists so that the repo's first locally-compiled proto
|
||||||
|
/// (<c>deployment_artifact.proto</c>) is proven to generate both the client stub and the server
|
||||||
|
/// base and the message types. If Grpc.Tools codegen regresses, this file stops compiling —
|
||||||
|
/// which, under TreatWarningsAsErrors, breaks the build loudly rather than silently.
|
||||||
|
/// </summary>
|
||||||
|
public class DeploymentArtifactProtoTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void The_request_message_carries_the_deployment_id()
|
||||||
|
{
|
||||||
|
var request = new FetchRequest { DeploymentId = "abc" };
|
||||||
|
|
||||||
|
request.DeploymentId.ShouldBe("abc");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void The_chunk_message_carries_bytes()
|
||||||
|
{
|
||||||
|
var chunk = new ArtifactChunk { Data = Google.Protobuf.ByteString.CopyFromUtf8("x") };
|
||||||
|
|
||||||
|
chunk.Data.Length.ShouldBe(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void The_service_base_and_client_types_generate()
|
||||||
|
{
|
||||||
|
// Referencing these types is the whole assertion — GrpcServices="Both" must emit both.
|
||||||
|
typeof(DeploymentArtifactService.DeploymentArtifactServiceBase).ShouldNotBeNull();
|
||||||
|
typeof(DeploymentArtifactService.DeploymentArtifactServiceClient).ShouldNotBeNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user