Skip to content

Commit cdaccae

Browse files
committed
feat(http): expose Devices accessor and fix DeviceReceived to fire
Adds a public read-only Devices snapshot accessor on MTConnectHttpClient and fixes DeviceReceived to actually fire for every parsed device. The client already cached the wired device model in a private _devices dictionary populated by ProcessProbeDocument, but never exposed it; the only public path to the post-probe model was ProbeReceived, which carries the raw IDevicesResponseDocument before InstanceId stamping. The new accessor returns an independent Dictionary copy under the same internal lock the populate path uses, so callers can enumerate without synchronising against the worker thread. DeviceReceived previously built an empty outputDevices list, populated only _devices in the first loop, then iterated the empty list — so the event was raised zero times across the lifetime of every client. The fix folds the invocation into the populate loop, keeping the cache and the event in lockstep and dropping the dead second loop. The new public Devices member shadows the MTConnect.Devices namespace inside the class scope, so the two pre-existing in-class references to that namespace are now fully qualified as MTConnect.Devices.* to keep their resolution unambiguous. The matching HttpClientDeviceModel test fixture, added in the previous commit, transitions from RED to GREEN: the missing accessor was a compile-error RED, the never-fired event was a behavioural RED, and both invariants now hold end to end against the AgentRunner-backed embedded HTTP server. Closes #176.
1 parent 142a4c4 commit cdaccae

1 file changed

Lines changed: 37 additions & 7 deletions

File tree

libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpClient.cs

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,40 @@ private void Init()
179179
/// </summary>
180180
public bool UseStreaming { get; set; }
181181

182+
/// <summary>
183+
/// A snapshot of the device model received from the most recent Probe response,
184+
/// keyed by device UUID. The dictionary is empty until the first probe succeeds,
185+
/// and is replaced on every subsequent probe. Each <see cref="IDevice"/>'s
186+
/// DataItems carry the fully wired <see cref="IDataItem.Container"/> and
187+
/// <see cref="IDataItem.Device"/> back-pointers set during parsing, so consumers
188+
/// can walk the component ancestry of any DataItem without re-parsing the
189+
/// document.
190+
/// </summary>
191+
/// <remarks>
192+
/// The accessor returns an independent copy under the client's internal lock,
193+
/// so callers may enumerate the snapshot without synchronising against the
194+
/// worker thread that processes subsequent probes.
195+
/// </remarks>
196+
public IReadOnlyDictionary<string, IDevice> Devices
197+
{
198+
get
199+
{
200+
lock (_lock)
201+
{
202+
return new Dictionary<string, IDevice>(_devices);
203+
}
204+
}
205+
}
206+
182207

183208
#region "Events"
184209

185210
/// <summary>
186-
/// Raised when a Device is received
211+
/// Raised once per parsed device for every Probe response the client receives,
212+
/// carrying the fully wired <see cref="IDevice"/> instance — the same instance
213+
/// the <see cref="Devices"/> snapshot accessor would return for that UUID — with
214+
/// its DataItems' <see cref="IDataItem.Container"/> and <see cref="IDataItem.Device"/>
215+
/// back-pointers set, and the agent's <c>InstanceId</c> stamped on each DataItem.
187216
/// </summary>
188217
public event EventHandler<IDevice> DeviceReceived;
189218

@@ -835,7 +864,6 @@ private void ProcessProbeDocument(IDevicesResponseDocument document)
835864
_cachedDataItems.Clear();
836865
}
837866

838-
var outputDevices = new List<IDevice>();
839867
foreach (var device in document.Devices)
840868
{
841869
var outputDevice = ProcessDevice(document.Header, device);
@@ -846,10 +874,12 @@ private void ProcessProbeDocument(IDevicesResponseDocument document)
846874
_devices.Remove(outputDevice.Uuid);
847875
_devices.Add(outputDevice.Uuid, outputDevice);
848876
}
849-
}
850877

851-
foreach (var outputDevice in outputDevices)
852-
{
878+
// Raise DeviceReceived for each parsed device. The event was
879+
// previously raised against a separate list that was never
880+
// populated, so it did not fire in the field; folding the
881+
// invocation into the populate loop keeps the cache and the
882+
// event in lockstep.
853883
DeviceReceived?.Invoke(this, outputDevice);
854884
}
855885

@@ -1092,7 +1122,7 @@ private IComponentStream ProcessComponentStream(IMTConnectStreamsHeader header,
10921122
outputComponentStream.NativeName = inputComponentStream.NativeName;
10931123
outputComponentStream.Uuid = inputComponentStream.Uuid;
10941124

1095-
if (inputComponentStream.ComponentType == Agent.TypeId || inputComponentStream.ComponentType == Devices.Device.TypeId)
1125+
if (inputComponentStream.ComponentType == Agent.TypeId || inputComponentStream.ComponentType == MTConnect.Devices.Device.TypeId)
10961126
{
10971127
outputComponentStream.Component = GetCachedDevice(deviceUuid);
10981128
}
@@ -1148,7 +1178,7 @@ private async void CheckAssetChanged(IEnumerable<IObservation> observations, Can
11481178
{
11491179
if (observations != null && observations.Count() > 0)
11501180
{
1151-
var assetsChanged = observations.Where(o => o.Type.ToUnderscoreUpper() == Devices.DataItems.AssetChangedDataItem.TypeId);
1181+
var assetsChanged = observations.Where(o => o.Type.ToUnderscoreUpper() == MTConnect.Devices.DataItems.AssetChangedDataItem.TypeId);
11521182
if (assetsChanged != null)
11531183
{
11541184
foreach (var assetChanged in assetsChanged)

0 commit comments

Comments
 (0)