feat: complete gRPC streaming channel — site host, docker config, docs, integration tests

Switch site host to WebApplicationBuilder with Kestrel HTTP/2 gRPC server,
add GrpcPort/keepalive config, wire SiteStreamManager as ISiteStreamSubscriber,
expose gRPC ports in docker-compose, add site seed script, update all 10
requirement docs + CLAUDE.md + README.md for the new dual-transport architecture.
This commit is contained in:
Joseph Doherty
2026-03-21 12:38:33 -04:00
parent 3fe3c4161b
commit 416a03b782
34 changed files with 728 additions and 156 deletions

View File

@@ -156,22 +156,40 @@ try
}
else if (nodeRole.Equals("Site", StringComparison.OrdinalIgnoreCase))
{
var builder = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args);
builder.ConfigureAppConfiguration(config => config.AddConfiguration(configuration));
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddConfiguration(configuration);
// WP-14: Serilog
builder.UseSerilog();
builder.Host.UseSerilog();
// WP-17: Windows Service support (no-op when not running as a Windows Service)
builder.UseWindowsService();
builder.Host.UseWindowsService();
builder.ConfigureServices((context, services) =>
// Read GrpcPort from config (NodeOptions already has default 8083)
var grpcPort = configuration.GetValue<int>("ScadaLink:Node:GrpcPort", 8083);
// Configure Kestrel for HTTP/2 only on the gRPC port
builder.WebHost.ConfigureKestrel(options =>
{
SiteServiceRegistration.Configure(services, context.Configuration);
options.ListenAnyIP(grpcPort, listenOptions =>
{
listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http2;
});
});
var host = builder.Build();
await host.RunAsync();
// gRPC server registration
builder.Services.AddGrpc();
builder.Services.AddSingleton<ScadaLink.Communication.Grpc.SiteStreamGrpcServer>();
// Existing site service registrations
SiteServiceRegistration.Configure(builder.Services, builder.Configuration);
var app = builder.Build();
// Map gRPC service — resolves the singleton SiteStreamGrpcServer from DI
app.MapGrpcService<ScadaLink.Communication.Grpc.SiteStreamGrpcServer>();
await app.RunAsync();
}
else
{