feat(runtime): DEV-STUB mode for Windows-only drivers on non-Windows or dev role

This commit is contained in:
Joseph Doherty
2026-05-26 05:23:02 -04:00
parent fa1d685ccd
commit 8b4de8080b

View File

@@ -45,15 +45,48 @@ public sealed class DriverInstanceActor : ReceiveActor, IWithTimers
public ITimerScheduler Timers { get; set; } = null!;
public static Props Props(IDriver driver, TimeSpan? reconnectInterval = null) =>
Akka.Actor.Props.Create(() => new DriverInstanceActor(driver, reconnectInterval ?? DefaultReconnectInterval));
public static Props Props(IDriver driver, TimeSpan? reconnectInterval = null, bool startStubbed = false) =>
Akka.Actor.Props.Create(() => new DriverInstanceActor(driver, reconnectInterval ?? DefaultReconnectInterval, startStubbed));
public DriverInstanceActor(IDriver driver, TimeSpan reconnectInterval)
/// <summary>
/// Returns true when the driver should boot in DEV-STUB mode based on host platform and
/// configured roles. Mirrors plan §Task 55: Windows-only driver types (Galaxy, Wonderware
/// Historian) are stubbed when running on non-Windows OR when the host carries the
/// <c>dev</c> role.
/// </summary>
public static bool ShouldStub(string driverType, IEnumerable<string> roles)
{
var isWindowsOnly = driverType is "Galaxy" or "Historian.Wonderware";
if (!OperatingSystem.IsWindows() && isWindowsOnly) return true;
if (roles.Contains("dev") && isWindowsOnly) return true;
return false;
}
public DriverInstanceActor(IDriver driver, TimeSpan reconnectInterval, bool startStubbed = false)
{
_driver = driver;
_driverInstanceId = driver.DriverInstanceId;
_reconnectInterval = reconnectInterval;
Become(Connecting);
if (startStubbed)
{
Context.GetLogger().Info("[DEV-STUB] driver={Name} type={Type}",
_driverInstanceId, driver.DriverType);
Become(Stubbed);
}
else
{
Become(Connecting);
}
}
private void Stubbed()
{
// Stubbed drivers accept the standard message contracts but return deterministic
// success without touching real hardware. Read returns null; Write succeeds.
Receive<InitializeRequested>(_ => { /* no-op */ });
Receive<ApplyDelta>(msg => Sender.Tell(new ApplyResult(true, "stubbed", msg.Correlation)));
Receive<WriteAttribute>(_ => Sender.Tell(new WriteAttributeResult(true, "stubbed")));
Receive<DisconnectObserved>(_ => { /* stubbed drivers don't disconnect */ });
}
private void Connecting()