using DTS.Common.Enums.DASFactory; using DTS.Common.Interface.DASFactory; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace DTS.DASLib.DASFactory { internal class AutoDiscovery { private readonly IDASFactory _dasFactory; /// /// this is the task that is actively looking for UDP devices /// private Task _scanTask = null; /// /// this is the cancellation token source for the cancel token used by the scan task /// private CancellationTokenSource tokenSource = new CancellationTokenSource(); /// /// this is a lock used to make start/stop and Get thread safe /// private static readonly object _multicastLock = new object(); /// /// starts a background discovery process /// public void StartMulticastAutoDiscovery() { lock (_multicastLock) { //start scanning (unless we are already scanning) if (null == _scanTask || _scanTask.IsCompleted) { if (tokenSource.IsCancellationRequested) { tokenSource.Dispose(); // token has been cancelled. no "reset" other than creating a new token source tokenSource = new CancellationTokenSource(); } _scanTask = Task.Run(() => DiscoveryWork(null, tokenSource.Token, false)); } } } /// /// stops a background discovery process /// public void StopMulticastAutoDiscovery() { lock (_multicastLock) { //stop scanning (unless it's not currently scanning) if (null == _scanTask || _scanTask.IsCompleted) { return; } if (tokenSource.Token.CanBeCanceled) { tokenSource.Cancel(); } } _scanTask.Wait(); _scanTask = null; } /// /// list of any discovered devices since discovery started /// private readonly List _discoveredDevices = new List(); /// /// this is the actual discovery thread /// /// /// /// private void DiscoveryWork(DFConstantsAndEnums.MultiCastDeviceClasses[] deviceFilter, CancellationToken ct, bool discoverParents = true) { var keepGoing = !ct.IsCancellationRequested; ClearDiscoveredDevices(); while (keepGoing) { var discoveries = _dasFactory.AutoDiscoverMulticast(ct, discoverParents).ToArray(); var filteredDiscoveries = deviceFilter?.Count() > 0 ? discoveries.Where(x => deviceFilter.Contains(x.DevClass)).ToArray() : discoveries; UpdateDevices(filteredDiscoveries); ct.WaitHandle.WaitOne(1000); keepGoing = !ct.IsCancellationRequested; } } /// /// adds any new devices to list of devices /// does not change any existing entries /// /// private void UpdateDevices(IDiscoveredDevice[] devices) { lock (_multicastLock) { foreach (var device in devices) { if (!_discoveredDevices.Exists(x => x.Serial == device.Serial)) { _discoveredDevices.Add(device); } } } } /// /// clears any discovered devices /// private void ClearDiscoveredDevices() { lock (_multicastLock) { _discoveredDevices.Clear(); } } /// /// retrieves all discovered devices /// /// public IDiscoveredDevice[] GetDiscoveredDevices() { lock (_multicastLock) { return _discoveredDevices.ToArray(); } } public AutoDiscovery(IDASFactory dasFactory) { _dasFactory = dasFactory; } } }