Initial commit
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace RobotNet10.RobotApp.Xloc;
|
||||
|
||||
/// <summary>
|
||||
/// Polls XLOC diagnostics and calls <see cref="XlocIntegrationService.StartLocalization"/> when
|
||||
/// state transitions to READY (3) with an active map. Does not depend on the web UI.
|
||||
/// </summary>
|
||||
public sealed class XlocAutoLocalizationHostedService : BackgroundService
|
||||
{
|
||||
private readonly XlocIntegrationService _xloc;
|
||||
private readonly ILogger<XlocAutoLocalizationHostedService> _logger;
|
||||
private readonly XlocIntegrationConfiguration _config = new();
|
||||
private byte? _previousXlocState;
|
||||
private bool _hasAutoStartedOnce;
|
||||
|
||||
public XlocAutoLocalizationHostedService(
|
||||
XlocIntegrationService xloc,
|
||||
IConfiguration configuration,
|
||||
ILogger<XlocAutoLocalizationHostedService> logger)
|
||||
{
|
||||
_xloc = xloc;
|
||||
_logger = logger;
|
||||
|
||||
var section = configuration.GetSection("Xloc:Integration");
|
||||
if (section.Exists())
|
||||
section.Bind(_config);
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
if (!_config.Enabled)
|
||||
{
|
||||
_logger.LogInformation("XlocAutoLocalizationHostedService skipped: Xloc:Integration:Enabled is false");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_config.AutoStartLocalizationOnReady)
|
||||
{
|
||||
_logger.LogInformation("XlocAutoLocalizationHostedService skipped: AutoStartLocalizationOnReady is false");
|
||||
return;
|
||||
}
|
||||
|
||||
var pollMs = Math.Clamp(_config.AutoStartLocalizationPollIntervalMs, 100, 10_000);
|
||||
var cooldownMs = Math.Max(0, _config.AutoStartLocalizationCooldownAfterStopMs);
|
||||
|
||||
_logger.LogInformation(
|
||||
"XlocAutoLocalizationHostedService running (poll {PollMs}ms, stop cooldown {CooldownMs}ms)",
|
||||
pollMs,
|
||||
cooldownMs);
|
||||
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(pollMs, stoppingToken).ConfigureAwait(false);
|
||||
|
||||
var diag = _xloc.GetDiagnostics();
|
||||
if (diag == null)
|
||||
continue;
|
||||
|
||||
var s = diag.XlocState;
|
||||
var transitionedToReady = s == 3 && (!_previousXlocState.HasValue || _previousXlocState.Value != 3);
|
||||
_previousXlocState = s;
|
||||
|
||||
if (!transitionedToReady || _hasAutoStartedOnce)
|
||||
continue;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(diag.CurrentActiveMap))
|
||||
{
|
||||
_logger.LogDebug("Auto-start localization skipped: no active map in diagnostics");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_xloc.LastLocalizationStopUtc.HasValue)
|
||||
{
|
||||
var elapsedMs = (DateTime.UtcNow - _xloc.LastLocalizationStopUtc.Value).TotalMilliseconds;
|
||||
if (elapsedMs < cooldownMs)
|
||||
{
|
||||
_logger.LogDebug(
|
||||
"Auto-start localization skipped: cooldown after stop ({ElapsedMs:F0}ms < {CooldownMs}ms)",
|
||||
elapsedMs,
|
||||
cooldownMs);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
_hasAutoStartedOnce = true;
|
||||
|
||||
_logger.LogInformation(
|
||||
"XLOC READY with active map '{Map}'. Auto-starting localization...",
|
||||
diag.CurrentActiveMap);
|
||||
|
||||
var ok = _xloc.StartLocalization();
|
||||
if (!ok)
|
||||
_logger.LogWarning("Auto-start localization failed (StartLocalization returned false)");
|
||||
}
|
||||
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error in XlocAutoLocalizationHostedService loop");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user