using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Data; using Tango.BL.Entities; using Tango.Core.Commands; using Tango.Core.DI; using Tango.Core.Threading; using Tango.Emulations.ExternalBridge; using Tango.FSE.BL; using Tango.FSE.Common; using Tango.FSE.Common.FSEApplication; using Tango.Integration.ExternalBridge; using Tango.Settings; using Tango.SharedUI; namespace Tango.FSE.UI.Panes { /// /// Represents the machine connection pane view model. /// /// public class MachineConnectionPaneVM : FSEViewModel { private const string WEB_DEBUG_ADDRESS = "http://localhost:1111"; private ExternalBridgeScanner _scanner; private EmulatorExternalBridge _emulator; private List _allowedMachines; private ICollectionView _tcpMachinesView; private ICollectionView _signalRMachinesView; private String _filter; public String Filter { get { return _filter; } set { _filter = value; RaisePropertyChangedAuto(); _tcpMachinesView?.Refresh(); _signalRMachinesView?.Refresh(); OnFilterChanged(); } } /// /// Occurs when a machine has been selected for connection. /// public event EventHandler MachineSelected; /// /// Gets or sets the available machines via USB. /// public ObservableCollection UsbMachines { get; set; } /// /// Gets or sets the available machines via local WiFi network. /// public ObservableCollection TcpMachines { get; set; } /// /// Gets or sets the available machine via Internet connection (SignalR). /// public ObservableCollection SignalRMachines { get; set; } /// /// Gets or sets the available emulated machines. /// public ObservableCollection EmulatorMachines { get; set; } /// /// Gets or sets the connect to machine command. /// public RelayCommand ConnectToMachineCommand { get; set; } private IExternalBridgeClient _selectedMachine; /// /// Gets or sets the selected machine. /// public IExternalBridgeClient SelectedMachine { get { return _selectedMachine; } set { _selectedMachine = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } } /// /// Initializes a new instance of the class. /// public MachineConnectionPaneVM() { TangoIOC.Default.Inject(this); ConnectToMachineCommand = new RelayCommand(ConnectToMachine, () => SelectedMachine != null); UsbMachines = new ObservableCollection(); TcpMachines = new ObservableCollection(); SignalRMachines = new ObservableCollection(); EmulatorMachines = new ObservableCollection(); _tcpMachinesView = CollectionViewSource.GetDefaultView(TcpMachines); _signalRMachinesView = CollectionViewSource.GetDefaultView(SignalRMachines); _tcpMachinesView.Filter = OnFilterMachines; _signalRMachinesView.Filter = OnFilterMachines; _scanner = new ExternalBridgeScanner(); _scanner.MachineDiscovered += _scanner_MachineDiscovered; _scanner.MachineLost += _scanner_MachineLost; ApplicationManager.ApplicationReady += ApplicationManager_ApplicationReady; } private void ApplicationManager_ApplicationReady(object sender, EventArgs e) { _allowedMachines = null; } /// /// Connects to the selected machine. /// internal void ConnectToMachine() { if (SelectedMachine != null) { Settings.LastSelectedMachine = SelectedMachine.GetUniqueString(); Settings.Save(); MachineSelected?.Invoke(this, SelectedMachine); } } /// /// Handles the external bridge scanner machine lost event. /// /// The sender. /// The machine. private void _scanner_MachineLost(object sender, IExternalBridgeClient machine) { InvokeUI(() => { if (machine is ExternalBridgeUsbClient) { UsbMachines.Remove(machine as ExternalBridgeUsbClient); } else if (machine is ExternalBridgeSignalRClient) { SignalRMachines.Remove(machine as ExternalBridgeSignalRClient); } else if (machine is ExternalBridgeTcpClient) { TcpMachines.Remove(machine as ExternalBridgeTcpClient); } }); } /// /// Handles the external bridge scanner machine discovered event. /// /// The sender. /// The machine. private void _scanner_MachineDiscovered(object sender, IExternalBridgeClient machine) { if (machine is ExternalBridgeTcpClient) { if (!_allowedMachines.Exists(x => x.SerialNumber == machine.SerialNumber)) { return; } } InvokeUI(() => { bool insert = false; try { if (Settings.LastSelectedMachine != null) { if (machine.GetUniqueString() == Settings.LastSelectedMachine) { insert = true; } } } catch { } if (machine is ExternalBridgeUsbClient && !BuildProvider.IsTwineRSM) { if (insert) { UsbMachines.Insert(0, machine as ExternalBridgeUsbClient); } else { UsbMachines.Add(machine as ExternalBridgeUsbClient); } } else if (machine is ExternalBridgeSignalRClient && !BuildProvider.IsTwineRSM) { if (!CurrentUser.PreventRemoteMachineAccess) { if (insert) { SignalRMachines.Insert(0, machine as ExternalBridgeSignalRClient); } else { SignalRMachines.Add(machine as ExternalBridgeSignalRClient); } } } else if (machine is ExternalBridgeTcpClient) { if (insert) { TcpMachines.Insert(0, machine as ExternalBridgeTcpClient); } else { TcpMachines.Add(machine as ExternalBridgeTcpClient); } } TryAutoSelectMachine(); }); } /// /// Tries to automatically select a machine by the last connected machine stored on settings. /// private void TryAutoSelectMachine() { if (SelectedMachine == null && Settings.LastSelectedMachine != null) { SelectedMachine = UsbMachines.Select(x => x.As()) .Concat(TcpMachines.Select(x => x.As())) .Concat(SignalRMachines.Select(x => x.As())) .Concat(EmulatorMachines.Select(x => x.As())) .ToList().SingleOrDefault(x => x.GetUniqueString() == Settings.LastSelectedMachine); if (SelectedMachine != null) { this.SetFocus(() => ConnectToMachineCommand); } } } /// /// Starts scanning for machines. /// public async void Start() { LogManager.Log("Starting machine scanning..."); if (_allowedMachines == null) { _allowedMachines = await Services.MachinesService.GetAllMachines(); _scanner.KnownMachines = _allowedMachines; } TcpMachines.Clear(); SignalRMachines.Clear(); EmulatorMachines.Clear(); SelectedMachine = null; if (Settings.EnableMachineEmulator) { ThreadFactory.StartNew(() => { try { LogManager.Log("Initializing machine emulator..."); if (_emulator != null) { _emulator.Disconnect().Wait(); } _emulator = new EmulatorExternalBridge(); InvokeUI(() => { EmulatorMachines.Add(_emulator); }); } catch (Exception ex) { LogManager.Log(ex, "Error initializing machine emulator."); } }); } TryAutoSelectMachine(); _scanner.SignalRConfiguration.Enabled = Settings.EnableExternalBridgeSignalR && !BuildProvider.IsTwineRSM; if (ApplicationManager.IsWebDebugMode) { LogManager.Log($"Application is in web debug mode. Scanning for SignalR machine on address '{WEB_DEBUG_ADDRESS}'..."); _scanner.SignalRConfiguration.Address = WEB_DEBUG_ADDRESS; } else { _scanner.SignalRConfiguration.Address = AuthenticationProvider.CurrentEnvironment.MachineServiceAddress; } _scanner.SignalRConfiguration.Hub = Settings.ExternalBridgeSignalRHub; LogManager.Log("Starting external bridge scanner..."); _scanner.Start(); } /// /// Stops scanning for machines. /// public void Stop() { LogManager.Log("Stopping external bridge scanner..."); _scanner.Stop(); } private bool OnFilterMachines(object obj) { var machine = obj as ExternalBridgeTcpClient; if (machine != null) { return machine.SerialNumber.ToLower().Contains(Filter.ToStringOrEmpty().ToLower()) || (machine.GetType() == typeof(ExternalBridgeTcpClient) && machine.IPAddress == Filter); } return true; } private void OnFilterChanged() { if (Filter.IsNotNullOrEmpty()) { Task.Factory.StartNew(() => { _scanner.TryGetMachineByIP(Filter); }); } } } }