using Microsoft.AspNet.SignalR.Client; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO.Ports; using System.Linq; using System.Management; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using Tango.BL.Entities; using Tango.BL.Enumerations; using Tango.Core; using Tango.Core.Helpers; using Tango.Integration.ExternalBridge.Web; using Tango.Logging; using Tango.PMR; using Tango.PMR.Common; using Tango.PMR.Integration; using Tango.Settings; using Tango.Transport; using Tango.Transport.Adapters; using Tango.Transport.Discovery; using Tango.Transport.Helpers; namespace Tango.Integration.ExternalBridge { /// /// Scans for available machines on the local area network and physically connected via USB. /// /// public class ExternalBridgeScanner : ExtendedObject { private Thread _tcpDiscoveryThread; private Thread _usbDiscoveryThread; private Thread _signalRDiscoveryThread; private IntegrationSettings _settings; private HubConnection _connection; private IHubProxy _proxy; public event EventHandler MachineDiscovered; public event EventHandler MachineLost; private SynchronizedObservableCollection _availableMachines; /// /// Gets the available machines. /// public SynchronizedObservableCollection AvailableMachines { get { return _availableMachines; } private set { _availableMachines = value; RaisePropertyChangedAuto(); } } /// /// Gets or sets the SignalR configuration. /// public ExternalBridgeSignalRConfiguration SignalRConfiguration { get; set; } /// /// Gets or sets the known machines. /// public List KnownMachines { get; set; } private bool _isStarted; /// /// Gets or sets a value indicating whether this instance is started. /// public bool IsStarted { get { return _isStarted; } private set { _isStarted = value; RaisePropertyChangedAuto(); } } /// /// Initializes a new instance of the class. /// public ExternalBridgeScanner() { _settings = SettingsManager.Default.GetOrCreate(); AvailableMachines = new SynchronizedObservableCollection(); KnownMachines = new List(); SignalRConfiguration = new ExternalBridgeSignalRConfiguration(); } public ExternalBridgeScanner(List knownMachines) : this() { KnownMachines = knownMachines; } /// /// Start scanning. (Results will be available through ). /// public void Start() { if (!IsStarted) { LogManager.Log("External bridge scanner started..."); IsStarted = true; foreach (var machine in AvailableMachines.OfType().ToList()) { AvailableMachines.Remove(machine); } foreach (var machine in AvailableMachines.OfType().ToList()) { AvailableMachines.Remove(machine); } _tcpDiscoveryThread = new Thread(TcpDiscoveryThreadMethod); _tcpDiscoveryThread.IsBackground = true; _tcpDiscoveryThread.Start(); _usbDiscoveryThread = new Thread(UsbDiscoveryThreadMethod); _usbDiscoveryThread.IsBackground = true; _usbDiscoveryThread.Start(); if (SignalRConfiguration.Enabled) { try { _connection = new HubConnection(SignalRConfiguration.Address); _proxy = _connection.CreateHubProxy(SignalRConfiguration.Hub); bool signalRStarted = false; _connection.StateChanged += (x) => { if (x.NewState == ConnectionState.Connected) { if (!signalRStarted) { signalRStarted = true; _signalRDiscoveryThread = new Thread(SignalRDiscoveryThreadMethod); _signalRDiscoveryThread.IsBackground = true; _signalRDiscoveryThread.Start(); } } }; _connection.Start(); } catch (Exception ex) { Debug.WriteLine(ex); } } } } /// /// Stops this instance. /// public void Stop() { if (IsStarted) { IsStarted = false; try { _usbDiscoveryThread.Abort(); _tcpDiscoveryThread.Abort(); _signalRDiscoveryThread.Abort(); AvailableMachines.Clear(); } catch (Exception ex) { Debug.WriteLine(ex); } LogManager.Log("External bridge scanner stopped."); } } /// /// USB discovery thread method. /// private void UsbDiscoveryThreadMethod() { while (IsStarted) { foreach (var device in Transport.Components.ComPortEnumerator.EnumerateComPorts()) { if (device.Description.Contains(_settings.EmbeddedDeviceName) || !_settings.FilterExternalBridgeUsbMachines) { if (!AvailableMachines.OfType().ToList().Exists(x => x.ComPort == device.Port)) { LogManager.Log("Found a new machine via USB " + device.Description); ThreadsHelper.InvokeUINow(() => { var machine = new ExternalBridgeUsbClient(device.Port, device.Description, _settings.EmbeddedSerialBaudRate); AvailableMachines.Add(machine); MachineDiscovered?.Invoke(this, machine); }); } } } Thread.Sleep(2000); } } /// /// TCP discovery thread method. /// //[DebuggerStepThrough] private void TcpDiscoveryThreadMethod() { while (IsStarted) { try { ExternalBridgeUdpDiscoveryPacket discoveryPacket = null; String address = null; if (_settings.ExternalBridgeDiscoveryMethod == DiscoveryMethod.Multicast) { using (UdpClient udpClient = new UdpClient()) { udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, _settings.ExternalBridgeServiceDiscoveryPort)); udpClient.JoinMulticastGroup(IPAddress.Parse(_settings.ExternalBridgeMulticastGroup), IPAddress.Parse(IPAddressHelper.GetLocalIpAddress())); var endPoint = new IPEndPoint(IPAddress.Any, 0); var discoveryData = udpClient.Receive(ref endPoint); discoveryPacket = ExternalBridgeUdpDiscoveryPacket.Parser.ParseFrom(discoveryData); address = endPoint.Address.ToString(); } } else { using (UdpClient udpClient = new UdpClient()) { udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, _settings.ExternalBridgeServiceDiscoveryPort)); var endPoint = new IPEndPoint(IPAddress.Any, _settings.ExternalBridgeServiceDiscoveryPort); udpClient.EnableBroadcast = true; var discoveryData = udpClient.Receive(ref endPoint); discoveryPacket = ExternalBridgeUdpDiscoveryPacket.Parser.ParseFrom(discoveryData); address = endPoint.Address.ToString(); } } //validate service existence using TCP connection. try { TcpClient client = new TcpClient(); client.Connect(address, _settings.ExternalBridgeServiceDiscoveryPort); client.Dispose(); } catch { var disconnected_machine = AvailableMachines.OfType().ToList().FirstOrDefault(x => x.SerialNumber == discoveryPacket.SerialNumber && x.IPAddress == address); if (disconnected_machine != null) { LogManager.Log("Disconnected machine detected via TCP: " + disconnected_machine.SerialNumber); AvailableMachines.Remove(disconnected_machine); MachineLost?.Invoke(this, disconnected_machine); } continue; } if (!AvailableMachines.OfType().ToList().Exists(x => x.SerialNumber == discoveryPacket.SerialNumber && x.IPAddress == address)) { ExternalBridgeTcpClient newMachine = null; var knownMachine = KnownMachines.FirstOrDefault(x => x.SerialNumber == discoveryPacket.SerialNumber); if (knownMachine == null && KnownMachines.Count == 0) { newMachine = new ExternalBridgeTcpClient(discoveryPacket.SerialNumber, address); } else if (knownMachine != null) { newMachine = new ExternalBridgeTcpClient(knownMachine, address); } if (newMachine != null) { newMachine.MachineType = (MachineTypes)discoveryPacket.MachineType; LogManager.Log("Found a new machine via TCP " + newMachine.SerialNumber); ThreadsHelper.InvokeUINow(() => { if (AvailableMachines.Count > 0) { AvailableMachines.Insert(1, newMachine); } else { AvailableMachines.Add(newMachine); } MachineDiscovered?.Invoke(this, newMachine); }); } } } catch (Exception ex) { LogManager.Log(ex); } Thread.Sleep(100); } } private void SignalRDiscoveryThreadMethod() { while (IsStarted && SignalRConfiguration.Enabled) { if (_connection.State == ConnectionState.Connected) { try { var machines = _proxy.Invoke>("GetAvailableMachines").Result; foreach (var machine in AvailableMachines.OfType().ToList().Where(x => !machines.Exists(y => y.SerialNumber == x.SerialNumber))) { AvailableMachines.Remove(machine); MachineLost?.Invoke(this, machine); } foreach (var machine in machines.Where(x => !AvailableMachines.OfType().ToList().Exists(y => y.SerialNumber == x.SerialNumber))) { ExternalBridgeSignalRClient newMachine = null; var knownMachine = KnownMachines.FirstOrDefault(x => x.SerialNumber == machine.SerialNumber); if (knownMachine == null && KnownMachines.Count == 0) { newMachine = new ExternalBridgeSignalRClient(SignalRConfiguration.Address, SignalRConfiguration.Hub, machine); } else if (knownMachine != null) { newMachine = new ExternalBridgeSignalRClient(SignalRConfiguration.Address, SignalRConfiguration.Hub, knownMachine, machine); } if (newMachine != null) { newMachine.MachineType = (MachineTypes)machine.MachineType; LogManager.Log("Found a new machine via SignalR " + newMachine.SerialNumber); ThreadsHelper.InvokeUINow(() => { if (AvailableMachines.Count > 0) { AvailableMachines.Insert(1, newMachine); } else { AvailableMachines.Add(newMachine); } MachineDiscovered?.Invoke(this, newMachine); }); } } } catch (Exception ex) { Debug.WriteLine(ex); } } Thread.Sleep(5000); } } private DateTime ParseDateTime(String dateTime) { try { return DateTime.ParseExact(dateTime, "dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture); } catch (Exception) { return DateTime.Parse(dateTime); } } /// /// Handles the available machines component state changed event. /// /// The sender. /// The e. private void Client_StateChanged(object sender, Transport.TransportComponentState e) { if (e == Transport.TransportComponentState.Failed || e == Transport.TransportComponentState.Disposed) { LogManager.Log("External bridge client failed or disposed. Removing from available machines..."); AvailableMachines.Remove(sender as IExternalBridgeClient); MachineLost?.Invoke(this, sender as IExternalBridgeClient); } } public void TryGetMachineByIP(String ip) { IPAddress _IP; if (IPAddress.TryParse(ip, out _IP)) { try { TcpClient client = new TcpClient(); client.Connect(ip, _settings.ExternalBridgeServiceDiscoveryPort); Thread.Sleep(100); byte[] data = new byte[client.Available]; client.GetStream().Read(data, 0, data.Length); client.Dispose(); TcpValidationInfo info = GenericMessageSerializer.Deserialize(data, GenericMessageProtocol.Bson); ExternalBridgeTcpClient newMachine = null; var knownMachine = KnownMachines.FirstOrDefault(x => x.SerialNumber == info.SerialNumber); if (knownMachine == null && KnownMachines.Count == 0) { newMachine = new ExternalBridgeTcpClient(info.SerialNumber, ip); } else if (knownMachine != null) { newMachine = new ExternalBridgeTcpClient(knownMachine, ip); } if (newMachine != null) { newMachine.MachineType = (MachineTypes)info.MachineType; LogManager.Log("Found a new machine via IP Address" + newMachine.SerialNumber); ThreadsHelper.InvokeUINow(() => { if (AvailableMachines.Count > 0) { AvailableMachines.Insert(1, newMachine); } else { AvailableMachines.Add(newMachine); } MachineDiscovered?.Invoke(this, newMachine); }); } } catch (Exception ex) { LogManager.Log(ex, "Error occurred when trying to find a machine by IP."); } } } } }