21cac4c8c40ae30b57022eaa06ff141da8482076
9 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
21cac4c8c4 |
PR 4.W — Galaxy:Backend wiring + server-side factory registration
- GalaxyDriver.InitializeAsync now builds the production gw runtime (MxGatewayClient, GalaxyMxSession, GatewayGalaxySubscriber, GatewayGalaxyDataWriter, ReconnectSupervisor, HostConnectivityForwarder, PerPlatformProbeWatcher) when no test seams are pre-injected; Dispose tears the chain down in order. - GetHealth surfaces supervisor.IsDegraded as DriverState.Degraded so a transport drop is observable without polling the supervisor directly. - DiscoverAsync now refreshes the per-platform probe watcher's membership against $WinPlatform / $AppEngine objects after every discovery pass. - OnPumpDataChange routes ScanState changes through the probe watcher in addition to fanning out OnDataChange to ISubscribable consumers. - Server registers GalaxyDriver under "GalaxyMxGateway" alongside the legacy "Galaxy" GalaxyProxyDriver factory so DriverInstance rows can opt in. - Bumped Server.Tests' Microsoft.Extensions.Logging.Abstractions to 10.0.7 to resolve the downgrade pulled in transitively via MxGateway.Client. - Lifecycle factory tests switched to the internal seam-injection ctor so they no longer attempt a real gRPC connect during InitializeAsync. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
dae520b9c0 |
PR 4.7 — Host-connectivity probes (IHostConnectivityProbe scaffold)
HostStatusAggregator merges transport + per-platform host entries with change-event diffing (re-asserting same state is a no-op so a stable ScanState=Running burst doesn't fan out duplicates). PerPlatformProbeWatcher ports the legacy GalaxyRuntimeProbeManager state machine onto the gw subscription path: SubscribeBulk for `<tag>.ScanState`, idempotent SyncPlatformsAsync (subscribe new, unsubscribe dropped), and a DecodeState helper pinning bool/int/string ScanState values + bad-quality fallback. HostConnectivityForwarder is the skeleton for the gw-6 StreamSessionHealth signal — until that mxaccessgw RPC ships, PR 4.5's ReconnectSupervisor pushes transport state by calling SetTransport on session connect/disconnect. GalaxyDriver wiring (implement IHostConnectivityProbe, route OnDataChange to PerPlatformProbeWatcher, expose GetHostStatuses() / OnHostStatusChanged, push transport from supervisor) is deferred to PR 4.W to avoid conflict with the rest of the Phase 4 deferred wiring (4.5 supervisor + 4.6 DeployWatcher). Tests: 19 new - HostStatusAggregatorTests (9): empty snapshot, new-host change with Unknown predecessor, same-state silence, transition diff, snapshot reflects every host, case-insensitive host names, Remove returns true for tracked, Remove false for unknown, concurrent updates don't corrupt. - HostConnectivityForwarderTests (5): SetTransport routes under client name, transitions fire change, repeated same-state silent, empty client name throws, post-dispose throws. - PerPlatformProbeWatcherTests (5 + theory pinning DecodeState's full truth table): subscribe N platforms, idempotent re-sync, removed platforms unsubscribed + dropped from aggregator, OnProbeValueChanged routing for Running/Stopped/bad-quality/foreign-ref, Dispose unsubscribes everything. NOTE: build is currently broken because mxaccessgw/clients/dotnet/ has been removed from C:\Users\dohertj2\Desktop\mxaccessgw — this PR's source is internally consistent and isolated from the missing dependency, but the existing Driver.Galaxy code (PRs 4.1–4.6) can't compile until the .NET client is restored. Once it is, expect 116 + 19 = 135 tests in the Driver.Galaxy.Tests project. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
123e3e48b9 |
PR 4.5 — ReconnectSupervisor
State machine that drives GalaxyDriver's recovery from gw transport failure. Healthy → TransportLost → Reopening → Replaying → Healthy. Drivers report failure signals; the supervisor runs reopen + replay with capped exponential backoff (default 500ms → 30s) until both succeed. Files: - Runtime/ReconnectSupervisor.cs — state machine with snapshot, change event, last-error tracking, and a one-attempt-at-a-time recovery loop. Idempotent ReportTransportFailure: repeated failure reports during an in-flight recovery do not spawn parallel loops. Reopen + replay are caller-supplied callbacks (the driver injects them in the wire-up PR); reopen re-Registers the gw session, replay re-establishes every active subscription via gw's ReplaySubscriptionsCommand (mxaccessgw issue gw-3) or the SubscribeBulk fallback. Dispose cancels the loop cleanly. - Public StateTransition record + IsDegraded predicate the driver maps to DriverState.Degraded for health snapshots. Wiring (GalaxyDriver subscribes the supervisor to its EventPump's transport-failure signal, exposes IsDegraded through GetHealth(), routes reopen/replay callbacks through GalaxyMxSession + SubscriptionRegistry) lands in PR 4.W to avoid conflict with the parallel host-probe track (PR 4.7) and align the wire-up with the rest of Phase 4's plumbing. 9 supervisor tests (full state-machine traversal, retry-until-success on both reopen and replay failures, idempotent failure reports, last-error propagation, Dispose mid-recovery, post-dispose throws, fast-path Healthy WaitForHealthy). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
7922e573b1 |
PR 4.6 — DeployWatcher (IRediscoverable scaffold)
DeployWatcher consumes GalaxyRepositoryClient.WatchDeployEventsAsync, suppresses the bootstrap event, and raises RediscoveryEventArgs whenever time_of_last_deploy actually changes. Reconnect-on-error with capped exponential backoff. GalaxyDriver wiring (IRediscoverable.OnRediscoveryNeeded event + StartAsync inside InitializeAsync) lands in a follow-up so this PR doesn't conflict with the parallel runtime track. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
ce004c80ab |
PR 4.4 — ISubscribable + EventPump
Subscription path online. GalaxyDriver implements ISubscribable; subscribes batches via gw SubscribeBulkAsync, runs a single shared EventPump consumer of StreamEventsAsync, fans out OnDataChange events to every driver subscription that observes the changed gw item handle. Files: - Runtime/GalaxySubscriptionHandle.cs — record implementing ISubscriptionHandle. - Runtime/SubscriptionRegistry.cs — bookkeeping with forward (subscriptionId → bindings) and reverse (itemHandle → list of subscriptionIds) maps. The reverse map is the fan-out index so a single OnDataChange dispatches to every subscription that observes the changed handle. - Runtime/IGalaxySubscriber.cs — driver-side seam: SubscribeBulk + UnsubscribeBulk + StreamEventsAsync. Production wraps GalaxyMxSession; tests substitute a fake driving synthetic MxEvents. - Runtime/GatewayGalaxySubscriber.cs — production. Forwards to MxGatewaySession; bufferedUpdateIntervalMs is captured for now and becomes a SetBufferedUpdateInterval call once gw issue #102 / gw-9 lands (PR 6.3 picks this up). - Runtime/EventPump.cs — long-running background consumer of StreamEventsAsync. Decodes MxValue + maps quality byte/MxStatusProxy via StatusCodeMap. Fan-out per subscriber resolves through the registry; bad handler exceptions are caught + logged, never break the dispatch loop. Filters out non-OnDataChange families (write-complete and operation- complete come back via InvokeAsync's reply path, not the event stream). GalaxyDriver: - Adds ISubscribable. SubscribeAsync allocates a subscription id, SubscribeBulks, builds the binding list (failed gw entries get ItemHandle=0 + a per-tag warn log), registers, and returns the handle. EventPump is started lazily on first subscribe; one pump per driver shared across all subscriptions. - UnsubscribeAsync removes from the registry first (so stale events are filtered immediately) then calls UnsubscribeBulk best-effort. Foreign handles throw ArgumentException. - ReadAsync NotSupportedException message updated: PR 4.4 no longer the pointer (deferred to a small follow-up that wraps the pump as a one-shot reader). - Dispose tears down the pump first, then the repository client, then clears state. - Internal ctor extended with optional subscriber parameter. Tests (15 new, 109 Galaxy total): - SubscriptionRegistryTests: monotonic id allocation, single+multi subscription fan-out, failed-handle exclusion, removal isolation, count invariants. - GalaxyDriverSubscribeTests: handle allocation + value-change dispatch, multi-subscription fan-out, failed-tag silence, unsubscribe drops gw handle and stops dispatch, foreign handle throws, no-subscriber throws, empty-tag-list returns handle without calling gw. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
a617086da1 |
PR 4.3 — IWritable + secured-write routing
Write path online. GalaxyDriver implements IWritable; routes by SecurityClassification — SecuredWrite / VerifiedWrite tags go through MxCommandKind.WriteSecured, everything else through MxGatewaySession. WriteAsync. Per-tag classifications are captured during ITagDiscovery via a SecurityCapturingBuilder wrapper that intercepts Variable() calls without the discoverer needing to know about the driver's internal state. Files: - Runtime/MxValueEncoder.cs — boxed CLR value → MxValue. Covers seven Galaxy scalar types (bool/int8-32/uint8-32 → Int32, int64/uint64 → Int64, float, double, string, DateTime/DateTimeOffset → Timestamp) and 1-D array variants. Inverse of MxValueDecoder; round-trip pinned by tests. DateTime.Local converts to UTC; unsupported types throw ArgumentException. - Runtime/IGalaxyDataWriter.cs — driver-side seam. Tests inject a fake to capture routing decisions; production path uses GatewayGalaxyDataWriter. - Runtime/GatewayGalaxyDataWriter.cs — production. Lazy-AddItem caches itemHandles, encodes value, routes Write vs WriteSecured, translates MxCommandReply (ProtocolStatus → BadCommunicationError; first MxStatusProxy in statuses[] via StatusCodeMap.FromMxStatus). Per-tag exception isolation: one bad write doesn't fail the batch. - GalaxyDriver: now implements IWritable. Discovery wraps the supplied IAddressSpaceBuilder in SecurityCapturingBuilder which records each attribute's SecurityClass into _securityByFullRef before delegating. WriteAsync resolves classification per tag (FreeAccess default for unknown tags — matches the legacy backend), routes through the injected writer. Throws NotSupportedException with PR 4.4 pointer when no writer is wired (production path requires GalaxyMxSession.Connect from PR 4.4). Tests (32 new, 94 Galaxy total): - MxValueEncoder: every scalar type, narrowing checks (sbyte/short/byte/ ushort fit Int32; uint within Int32 range; ulong within Int64), DateTime.Local → UTC conversion, array variants for bool/double/string/ DateTime, Dimensions populated, unsupported-type throws ArgumentException, encoder/decoder round-trip pin. - GalaxyDriverWriteTests: WriteAsync routes through fake writer with values intact; theory exercises every SecurityClassification value through the discovery-then-write path; unknown-tag defaults to FreeAccess; empty- request short-circuit; no-writer fail-loud; post-dispose throws. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
85bdf0d58b |
PR 4.2 — IReadable abstraction + StatusCodeMap + MxValueDecoder
Read path scaffold + the byte→uint quality mapping table that the parity matrix (PR 5.x) pins. PR 4.4 supplies the production GW-backed reader; this PR ships the abstraction and the supporting infrastructure so 4.4 just plugs the implementation in. Files: - Runtime/StatusCodeMap.cs — explicit OPC DA quality byte → OPC UA StatusCode uint mapping. Extends the legacy Galaxy.Host HistorianQualityMapper with named constants (Good / GoodLocalOverride, Uncertain + 4 substatuses, Bad + 7 substatuses, BadInternalError) and an MxStatusProxy → uint helper that honors success flag → detail byte → detected_by transport-error fallback. Unknown bytes fall back to category bucket with a once-per-session diagnostic log so field captures can extend the table. - Runtime/MxValueDecoder.cs — gateway MxValue → boxed CLR value for the seven Galaxy data types (Boolean, Int32, Int64, Float32, Float64, String, DateTime) plus their array variants. Honors MxValue.IsNull and RawValue passthrough. - Runtime/IGalaxyDataReader.cs — driver-side seam for one-shot reads. PR 4.4 ships the production wrapper around MxGatewaySession.SubscribeBulk + StreamEvents + UnsubscribeBulk; this PR exposes the contract so GalaxyDriver.ReadAsync wires through it. - Runtime/GalaxyMxSession.cs — wrapper around MxGatewaySession that owns the Register handle. ConnectAsync opens session + Register; AttachForTests lets tests bypass real gw construction. PR 4.3/4.4/4.5 add write, subscribe, and reconnect surfaces. GalaxyDriver: - Implements IReadable. ReadAsync routes through the injected IGalaxyDataReader (test seam) when present; production path throws NotSupportedException pointing at PR 4.4 — protects deployments running this PR from silent wrong reads while signaling that the legacy-host backend (Galaxy:Backend=legacy-host) handles reads in the meantime. - Internal ctor extended with optional dataReader parameter (default null, preserves PR 4.0/4.1 callers). Tests: 42 new — exhaustive byte→uint table for StatusCodeMap (15 known codes + category-bucket fallback for unknowns + MxStatusProxy precedence rules + OPC UA top-byte invariants), every MxValue oneof case for the decoder (bool/int32/int64/float/double/string/timestamp/3 array variants/ raw bytes/null), GalaxyDriver IReadable wiring (route-through, empty- request, no-reader-throws, post-dispose-throws, status-code preservation). 62 Galaxy tests total pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
ecba5cedf9 |
PR 4.1 — ITagDiscovery via GalaxyRepositoryClient + AlarmRefBuilder
Browse path online. GalaxyDriver now implements ITagDiscovery against the gateway's GalaxyRepositoryClient (PR 0.1's mxaccessgw browse RPC) and feeds the address-space builder one folder per gobject + one variable per dynamic attribute, with alarm-bearing attributes carrying all five sub-attribute refs the server-level AlarmConditionService (PR 2.2) needs. Files: - Browse/IGalaxyHierarchySource.cs — driver-side seam between the discoverer and the gateway. Test fakes return canned hierarchies so the discoverer's translation logic is exercised without a real gRPC channel. - Browse/GatewayGalaxyHierarchySource.cs — production wrapper around GalaxyRepositoryClient.DiscoverHierarchyAsync (paged internally). - Browse/GalaxyDiscoverer.cs — translates GalaxyObject → IAddressSpaceBuilder calls. Browse name = contained_name (falls back to tag_name); full reference = attr.full_tag_reference when set, else tag_name + "." + attribute_name. Skips objects/attributes with empty identity. - Browse/DataTypeMap.cs — mx_data_type → DriverDataType (port from legacy GalaxyProxyDriver.MapDataType, same fallback to String for unknown codes). - Browse/SecurityMap.cs — security_classification → SecurityClassification (port from legacy GalaxyProxyDriver.MapSecurity). - Browse/AlarmRefBuilder.cs — populates the five sub-attribute refs by Galaxy convention (.InAlarm/.Priority/.DescAttrName/.Acked/.AckMsg). The same convention the legacy GalaxyAlarmTracker hard-coded; concentrated here so PR 2.2's service receives complete AlarmConditionInfo rows. GalaxyDriver: - Added internal ctor accepting IGalaxyHierarchySource? for test injection. Default lazily builds GatewayGalaxyHierarchySource around a GalaxyRepositoryClient constructed from options on first DiscoverAsync. - Owned GalaxyRepositoryClient disposed in Dispose. - ApiKey resolution is currently a passthrough of ApiKeySecretRef — PR 4.W (or follow-up) wires DPAPI-backed secret resolution. csproj: path-based ProjectReference to mxaccessgw (the user is shipping that repo on a parallel track; both repos sit side-by-side on the dev box). Tests project also references MxGateway.Contracts directly to construct GalaxyObject / GalaxyAttribute fixtures. Tests: 10 new in Browse/GalaxyDiscovererTests.cs covering folder-per-object, variable-per-attribute, full-ref defaulting + gw-supplied override, browse- name fallback, every metadata field propagation, alarm sub-attribute ref population, non-alarm rows skip MarkAsAlarmCondition, empty-identity skips, empty-attribute-name skips, end-to-end through GalaxyDriver.DiscoverAsync. 20 total Galaxy tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
f6a4f919e2 |
PR 4.0 — Driver.Galaxy project skeleton + factory
New in-process .NET 10 driver project at src/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/. The Tier-A replacement for Driver.Galaxy.Host + Driver.Galaxy.Proxy. PR 4.0 ships only the IDriver shape + factory + options; capability bodies (browse, read, write, subscribe, deploy-watch, host probes) land in PRs 4.1–4.7. Files: - Driver.Galaxy.csproj — net10 x64, AnyCPU+x64 platforms, references Core.Abstractions + Core. No MxGatewayClient ProjectReference yet — that comes in PR 4.2 once the gw NuGet package is wired (the user is shipping mxaccessgw on a parallel track). - Config/GalaxyDriverOptions.cs — nested record hierarchy (Gateway/MxAccess/Repository/Reconnect) mirroring the JSON shape spelled out in lmx_mxgw_impl.md PR 4.0 acceptance section. - GalaxyDriver.cs — minimal IDriver impl. Initialize/Shutdown toggle DriverHealth between Healthy/Unknown; Reinitialize bumps the timestamp; GetMemoryFootprint=0 (PR 4.4 wires SubscriptionRegistry size); FlushOptionalCachesAsync no-op. Logs intent on lifecycle calls so partial deployments are diagnosable. - GalaxyDriverFactoryExtensions.cs — JSON parser, default fill-ins, validation throw on missing required fields. Driver type name "GalaxyMxGateway" intentionally distinct from legacy "Galaxy" so both factories coexist during parity testing (Phase 5). PR 4.W's Galaxy:Backend switch picks one or the other. Tests: - 10 tests in Driver.Galaxy.Tests covering minimal-config defaults, full override path, three required-field error cases, factory registration via DriverFactoryRegistry.TryGet, lifecycle health transitions (Init → Shutdown → Reinit), Dispose idempotency, and post-disposal ObjectDisposedException. slnx: registers the new Driver.Galaxy + Driver.Galaxy.Tests projects. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |