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;
}
}
}