feat(site): HTTP deployment-config fetcher + DI + options
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.SiteRuntime.Deployment;
|
||||
|
||||
/// <summary>HTTP <see cref="IDeploymentConfigFetcher"/> — GETs the config from central's internal endpoint.</summary>
|
||||
public sealed class HttpDeploymentConfigFetcher : IDeploymentConfigFetcher
|
||||
{
|
||||
private readonly HttpClient _http;
|
||||
private readonly ILogger<HttpDeploymentConfigFetcher> _log;
|
||||
|
||||
public HttpDeploymentConfigFetcher(HttpClient http, ILogger<HttpDeploymentConfigFetcher> log)
|
||||
{
|
||||
_http = http;
|
||||
_log = log;
|
||||
}
|
||||
|
||||
public async Task<string> FetchAsync(string centralFetchBaseUrl, string deploymentId, string token, CancellationToken ct)
|
||||
{
|
||||
var url = $"{centralFetchBaseUrl.TrimEnd('/')}/api/internal/deployments/{Uri.EscapeDataString(deploymentId)}/config";
|
||||
using var req = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
req.Headers.Add("X-Deployment-Token", token);
|
||||
|
||||
HttpResponseMessage resp;
|
||||
try
|
||||
{
|
||||
resp = await _http.SendAsync(req, ct);
|
||||
}
|
||||
catch (OperationCanceledException) when (ct.IsCancellationRequested)
|
||||
{
|
||||
throw; // genuine caller cancellation — propagate
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Includes HttpClient.Timeout (surfaces as TaskCanceledException with ct NOT cancelled) — treat as transport.
|
||||
_log.LogWarning(ex, "deployment-config fetch transport error for {DeploymentId}", deploymentId);
|
||||
throw new DeploymentConfigFetchException($"deployment-config fetch transport error: {ex.Message}", isSuperseded: false, ex);
|
||||
}
|
||||
|
||||
using (resp)
|
||||
{
|
||||
if (resp.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||
{
|
||||
_log.LogWarning("deployment-config not found (expired/superseded/unknown) for {DeploymentId} (HTTP 404)", deploymentId);
|
||||
throw new DeploymentConfigFetchException($"deployment-config not found (expired/superseded/unknown): {deploymentId}", isSuperseded: true);
|
||||
}
|
||||
if (!resp.IsSuccessStatusCode)
|
||||
{
|
||||
_log.LogWarning("deployment-config fetch failed for {DeploymentId}: HTTP {StatusCode}", deploymentId, (int)resp.StatusCode);
|
||||
throw new DeploymentConfigFetchException($"deployment-config fetch failed: HTTP {(int)resp.StatusCode}", isSuperseded: false);
|
||||
}
|
||||
|
||||
var body = await resp.Content.ReadAsStringAsync(ct);
|
||||
_log.LogDebug("deployment-config fetched for {DeploymentId} (HTTP {StatusCode})", deploymentId, (int)resp.StatusCode);
|
||||
return body;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace ZB.MOM.WW.ScadaBridge.SiteRuntime.Deployment;
|
||||
|
||||
/// <summary>
|
||||
/// Fetches a deployment's flattened config JSON from central over HTTP
|
||||
/// (notify-and-fetch). The site calls this after receiving a small notify.
|
||||
/// </summary>
|
||||
public interface IDeploymentConfigFetcher
|
||||
{
|
||||
/// <summary>
|
||||
/// GETs the flattened config JSON for <paramref name="deploymentId"/> from
|
||||
/// <paramref name="centralFetchBaseUrl"/>, presenting <paramref name="token"/>
|
||||
/// in the X-Deployment-Token header. Throws <see cref="DeploymentConfigFetchException"/>
|
||||
/// on any non-success; a 404 (expired/superseded/unknown) sets IsSuperseded.
|
||||
/// </summary>
|
||||
Task<string> FetchAsync(string centralFetchBaseUrl, string deploymentId, string token, CancellationToken ct);
|
||||
}
|
||||
|
||||
/// <summary>Raised when a deployment-config fetch fails. <see cref="IsSuperseded"/> is true on HTTP 404.</summary>
|
||||
public sealed class DeploymentConfigFetchException : Exception
|
||||
{
|
||||
public bool IsSuperseded { get; }
|
||||
public DeploymentConfigFetchException(string message, bool isSuperseded, Exception? inner = null)
|
||||
: base(message, inner) => IsSuperseded = isSuperseded;
|
||||
}
|
||||
Reference in New Issue
Block a user