From 5774f40b650a376e9b622dba9df6c43589b0d398 Mon Sep 17 00:00:00 2001 From: Roy Ben Shabat Date: Thu, 9 Apr 2020 00:29:06 +0300 Subject: Logs, Comments & General organization on FSE/PPC. Several improvements. --- .../MachineUpdate/MachineUpdateManager.cs | 29 ++++++++-------------- 1 file changed, 11 insertions(+), 18 deletions(-) (limited to 'Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate') diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs index 733574f72..9a12552bc 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs @@ -1687,30 +1687,23 @@ namespace Tango.PPC.Common.MachineUpdate public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) { - + //Do nothing. } - [ExternalBridgeRequestHandlerMethod(typeof(GetUpdatesAndPackagesRequest))] - public async void OnGetUpdatesAndPackagesRequest(GetUpdatesAndPackagesRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(GetUpdatesAndPackagesRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnGetUpdatesAndPackagesRequest(GetUpdatesAndPackagesRequest request, String token, ExternalBridgeReceiver receiver) { - try + using (ObservablesContext db = ObservablesContext.CreateDefault()) { - using (ObservablesContext db = ObservablesContext.CreateDefault()) - { - var updates = await db.TangoUpdates.OrderByDescending(x => x.StartDate).ToListAsync(); - var updatesDTO = updates.Select(x => TangoUpdateDTO.FromObservable(x)).ToList(); - var packages = (await _packageRunner.GetPackagesFile()).PackageInstallations; + var updates = await db.TangoUpdates.OrderByDescending(x => x.StartDate).ToListAsync(); + var updatesDTO = updates.Select(x => TangoUpdateDTO.FromObservable(x)).ToList(); + var packages = (await _packageRunner.GetPackagesFile()).PackageInstallations; - var response = new GetUpdatesAndPackagesResponse(); - response.Updates.AddRange(updatesDTO); - response.Packages.AddRange(packages); + var response = new GetUpdatesAndPackagesResponse(); + response.Updates.AddRange(updatesDTO); + response.Packages.AddRange(packages); - await receiver.SendGenericResponse(response, token); - } - } - catch (Exception ex) - { - await receiver.SendErrorResponse(ex, token); + await receiver.SendGenericResponse(response, token); } } -- cgit v1.3.1 From 76ebe53d89a1b0cbf21d66dc9f26dc95cc7b3be9 Mon Sep 17 00:00:00 2001 From: Roy Ben Shabat Date: Mon, 13 Apr 2020 03:41:41 +0300 Subject: FSE TUP --- .../Tango.FSE.Upgrade/Tango.FSE.Upgrade.csproj | 16 ++ .../Modules/Tango.FSE.Upgrade/ViewModelLocator.cs | 18 ++ .../ApplicationUpgradeGeneratedViewVM.cs | 182 +++++++++++++++++++++ .../ViewModels/ApplicationUpgradeViewVM.cs | 42 ++++- .../ViewModels/FirmwareUpgradeGeneratedViewVM.cs | 13 ++ .../Views/ApplicationUpgradeGeneratedView.xaml | 69 ++++++++ .../Views/ApplicationUpgradeGeneratedView.xaml.cs | 28 ++++ .../Views/FirmwareUpgradeGeneratedView.xaml | 16 ++ .../Views/FirmwareUpgradeGeneratedView.xaml.cs | 28 ++++ .../Modules/Tango.FSE.Upgrade/Views/MainView.xaml | 2 + .../FileSystem/FileSystemHandler.cs | 10 ++ .../FileSystem/IFileSystemProvider.cs | 9 + .../Navigation/INavigationBlocker.cs | 7 + .../Navigation/INavigationManager.cs | 13 +- .../RemoteUpgrade/IRemoteUpgradeManager.cs | 7 + .../FileSystem/DefaultFileSystemProvider.cs | 19 ++- .../Navigation/DefaultNavigationManager.cs | 81 +++++++-- .../RemoteUpgrade/DefaultRemoteUpgradeManager.cs | 99 ++++++++++- .../MachineUpdate/MachineUpdateManager.cs | 2 + .../StartRemoteApplicationRemoteUpgradeRequest.cs | 15 ++ .../StartRemoteApplicationRemoteUpgradeResponse.cs | 23 +++ .../PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj | 2 + .../Tango.PPC.UI/ViewModels/MachineUpdateViewVM.cs | 110 ++++++++++++- 23 files changed, 782 insertions(+), 29 deletions(-) create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/ApplicationUpgradeGeneratedViewVM.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/FirmwareUpgradeGeneratedViewVM.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeGeneratedView.xaml create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeGeneratedView.xaml.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeGeneratedView.xaml create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeGeneratedView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationRemoteUpgradeRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationRemoteUpgradeResponse.cs (limited to 'Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate') diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Tango.FSE.Upgrade.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Tango.FSE.Upgrade.csproj index daca836b7..fd8b99820 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Tango.FSE.Upgrade.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Tango.FSE.Upgrade.csproj @@ -84,9 +84,17 @@ + + + ApplicationUpgradeGeneratedView.xaml + ApplicationUpgradeView.xaml + + + FirmwareUpgradeGeneratedView.xaml + FirmwareUpgradeView.xaml @@ -173,10 +181,18 @@ MSBuild:Compile Designer + + Designer + MSBuild:Compile + Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModelLocator.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModelLocator.cs index 739562ce3..1c6999c6d 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModelLocator.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModelLocator.cs @@ -16,6 +16,8 @@ namespace Tango.FSE.Upgrade TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); } public static MainViewVM MainViewVM @@ -49,5 +51,21 @@ namespace Tango.FSE.Upgrade return TangoIOC.Default.GetInstance(); } } + + public static ApplicationUpgradeGeneratedViewVM ApplicationUpgradeGeneratedViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + + public static FirmwareUpgradeGeneratedViewVM FirmwareUpgradeGeneratedViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/ApplicationUpgradeGeneratedViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/ApplicationUpgradeGeneratedViewVM.cs new file mode 100644 index 000000000..f5dbb7270 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/ApplicationUpgradeGeneratedViewVM.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.Core.Commands; +using Tango.FSE.Common; +using Tango.FSE.Common.Navigation; +using Tango.FSE.Common.RemoteUpgrade; +using Tango.FSE.Upgrade.Views; +using static Tango.FSE.Upgrade.ViewModels.ApplicationUpgradeGeneratedViewVM; + +namespace Tango.FSE.Upgrade.ViewModels +{ + public class ApplicationUpgradeGeneratedViewVM : FSEViewModel, INavigationObjectReceiver + { + public class NavigationObject + { + public Machine SelectedMachine { get; set; } + public bool UpgradeNow { get; set; } + public String TupFileLocation { get; set; } + } + + private String _tupFileLocation; + public String TupFileLocation + { + get { return _tupFileLocation; } + set { _tupFileLocation = value; RaisePropertyChangedAuto(); } + } + + private bool _canUpgradeNow; + public bool CanUpgradeNow + { + get { return _canUpgradeNow; } + set { _canUpgradeNow = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private String _canUpgradeNowError; + public String CanUpgradeNowError + { + get { return _canUpgradeNowError; } + set { _canUpgradeNowError = value; RaisePropertyChangedAuto(); } + } + + private bool _isUpgradeNow; + public bool IsUpgradeNow + { + get { return _isUpgradeNow; } + set { _isUpgradeNow = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private Machine _selectedMachine; + public Machine SelectedMachine + { + get { return _selectedMachine; } + set { _selectedMachine = value; RaisePropertyChangedAuto(); } + } + + private RemoteUpgradeHandler _handler; + public RemoteUpgradeHandler Handler + { + get { return _handler; } + set { _handler = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand StartUpgradeCommand { get; set; } + public RelayCommand ShowPackageInExplorerCommand { get; set; } + + public ApplicationUpgradeGeneratedViewVM() + { + Handler = new RemoteUpgradeHandler(null) { Message = "Ready" }; + StartUpgradeCommand = new RelayCommand(StartUpgrade, () => CanUpgradeNow && Handler.Status != RemoteUpgradeHandlerStatus.Completed); + ShowPackageInExplorerCommand = new RelayCommand(ShowPackageInExplorer); + } + + public override void OnApplicationStarted() + { + base.OnApplicationStarted(); + MachineProvider.MachineConnected += (_, __) => InvalidateCanUpgradeNow(); + MachineProvider.MachineDisconnected += (_, __) => InvalidateCanUpgradeNow(); + } + + private void InvalidateCanUpgradeNow() + { + CanUpgradeNowError = null; + + if (!IsUpgradeNow) return; + + if (SelectedMachine == null) + { + CanUpgradeNow = false; + CanUpgradeNowError = "Target machine not specified."; + return; + } + + if (!MachineProvider.IsConnected) + { + CanUpgradeNow = false; + CanUpgradeNowError = "The selected machine is not currently connected."; + return; + } + + if (MachineProvider.Machine.Guid != SelectedMachine.Guid) + { + CanUpgradeNow = false; + CanUpgradeNowError = "The selected machine is different from the one currently connected."; + return; + } + + if (!MachineProvider.ConnectionType.IsRemote()) + { + CanUpgradeNow = false; + CanUpgradeNowError = "The current machine connection type does not support remote upgrade."; + return; + } + + CanUpgradeNow = true; + } + + private async void StartUpgrade() + { + try + { + IsFree = false; + Handler = await RemoteUpgradeManager.PerformRemoteApplicationUpgrade(TupFileLocation); + await Handler.WaitForCompletion(); + await Task.Delay(5000); + InvalidateRelayCommands(); + await NotificationProvider.ShowSuccess("Remote upgrade completed successfully!"); + + if (IsVisible) + { + await NavigationManager.NavigateTo(nameof(WelcomeView), false); + } + } + catch (OperationCanceledException) + { + //Aborted... + } + catch (Exception ex) + { + LogManager.Log("Error occurred while executing remote application upgrade."); + await NotificationProvider.ShowError($"Error occurred while executing the remote application upgrade.\n{ex.FlattenMessage()}"); + } + finally + { + IsFree = true; + } + } + + private void ShowPackageInExplorer() + { + throw new NotImplementedException(); + } + + public void OnNavigatedToWithObject(NavigationObject obj) + { + SelectedMachine = obj.SelectedMachine; + IsUpgradeNow = obj.UpgradeNow; + TupFileLocation = obj.TupFileLocation; + InvalidateCanUpgradeNow(); + } + + public override Task OnNavigateBackRequest() + { + if (IsFree) + { + return base.OnNavigateBackRequest(); + } + else + { + Task.Delay(100).ContinueWith((x) => + { + NavigationManager.NavigateTo(NavigationView.Home); + }, TaskScheduler.FromCurrentSynchronizationContext()); + + return Task.FromResult(false); + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/ApplicationUpgradeViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/ApplicationUpgradeViewVM.cs index c120b3f74..f7dae41e7 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/ApplicationUpgradeViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/ApplicationUpgradeViewVM.cs @@ -2,12 +2,14 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using Tango.BL.Entities; using Tango.Core.Commands; using Tango.FSE.Common; using Tango.FSE.Common.Navigation; using Tango.FSE.Common.RemoteUpgrade; +using Tango.FSE.Upgrade.Views; namespace Tango.FSE.Upgrade.ViewModels { @@ -25,6 +27,13 @@ namespace Tango.FSE.Upgrade.ViewModels public Machine SelectedMachine { get; set; } } + private ApplicationUpgradeMode _upgradeMode; + public ApplicationUpgradeMode UpgradeMode + { + get { return _upgradeMode; } + set { _upgradeMode = value; RaisePropertyChangedAuto(); } + } + private List _tangoVersions; public List TangoVersions { @@ -86,8 +95,19 @@ namespace Tango.FSE.Upgrade.ViewModels try { IsFree = false; - Handler = await RemoteUpgradeManager.CreateTupFile(SelectedVersion, SelectedMachine.SerialNumber, TupFileLocation); - await Handler.WaitForCompletion(); + //Handler = await RemoteUpgradeManager.CreateTupFile(SelectedVersion, SelectedMachine.SerialNumber, TupFileLocation); + //await Handler.WaitForCompletion(); + + await NavigationManager.NavigateWithObject< + UpgradeModule, + ApplicationUpgradeGeneratedView, + ApplicationUpgradeGeneratedViewVM.NavigationObject>( + new ApplicationUpgradeGeneratedViewVM.NavigationObject() + { + UpgradeNow = UpgradeMode == ApplicationUpgradeMode.ConnectedMachine, + SelectedMachine = SelectedMachine, + TupFileLocation = TupFileLocation + }, false); } catch (OperationCanceledException) { @@ -123,9 +143,27 @@ namespace Tango.FSE.Upgrade.ViewModels } } + public override Task OnNavigateBackRequest() + { + if (IsFree) + { + return base.OnNavigateBackRequest(); + } + else + { + Task.Delay(100).ContinueWith((x) => + { + NavigationManager.NavigateTo(NavigationView.Home); + }, TaskScheduler.FromCurrentSynchronizationContext()); + + return Task.FromResult(false); + } + } + public void OnNavigatedToWithObject(NavigationObject obj) { SelectedMachine = obj.SelectedMachine; + UpgradeMode = obj.ApplicationUpgradeMode; } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/FirmwareUpgradeGeneratedViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/FirmwareUpgradeGeneratedViewVM.cs new file mode 100644 index 000000000..3d190aa01 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/FirmwareUpgradeGeneratedViewVM.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.FSE.Common; + +namespace Tango.FSE.Upgrade.ViewModels +{ + public class FirmwareUpgradeGeneratedViewVM : FSEViewModel + { + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeGeneratedView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeGeneratedView.xaml new file mode 100644 index 000000000..d70b496e7 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeGeneratedView.xaml @@ -0,0 +1,69 @@ + + + + Application Upgrade Ready! + + + Your machine application and firmware upgrade is ready. + + + + + You have chosen to upgrade the currently connected machine. + press 'start upgrade' to start upgrading remotely. + That is not currently possible due to the following reason: + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeGeneratedView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeGeneratedView.xaml.cs new file mode 100644 index 000000000..1bcc56b92 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeGeneratedView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.FSE.Upgrade.Views +{ + /// + /// Interaction logic for ApplicationUpgradeGeneratedView.xaml + /// + public partial class ApplicationUpgradeGeneratedView : UserControl + { + public ApplicationUpgradeGeneratedView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeGeneratedView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeGeneratedView.xaml new file mode 100644 index 000000000..08bb74b6b --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeGeneratedView.xaml @@ -0,0 +1,16 @@ + + + + + diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeGeneratedView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeGeneratedView.xaml.cs new file mode 100644 index 000000000..687e8ca92 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeGeneratedView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.FSE.Upgrade.Views +{ + /// + /// Interaction logic for FirmwareUpgradeGeneratedView.xaml + /// + public partial class FirmwareUpgradeGeneratedView : UserControl + { + public FirmwareUpgradeGeneratedView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/MainView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/MainView.xaml index f06753409..efc9913ea 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/MainView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/MainView.xaml @@ -51,6 +51,8 @@ + + diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/FileSystemHandler.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/FileSystemHandler.cs index e74395ade..9cceb4fa3 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/FileSystemHandler.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/FileSystemHandler.cs @@ -14,6 +14,7 @@ namespace Tango.FSE.Common.FileSystem private FileSystemHandlerStatus _statusBeforePause; private System.Timers.Timer _transferRateTimer; private double _lastPosition; + private TaskCompletionSource _completionSource; public event EventHandler StatusChanged; @@ -93,6 +94,7 @@ namespace Tango.FSE.Common.FileSystem public FileSystemHandler(FileSystemHandlerType type, FileSystemItem fileSystemItem, String destination, Action abortAction) { + _completionSource = new TaskCompletionSource(); Type = type; FileSystemItem = fileSystemItem; Destination = destination; @@ -133,16 +135,19 @@ namespace Tango.FSE.Common.FileSystem { Status = FileSystemHandlerStatus.Failed; FailedException = exception; + _completionSource.SetException(exception); } internal void RaiseAborted() { Status = FileSystemHandlerStatus.Aborted; + _completionSource.SetException(new OperationCanceledException("File system operation aborted.")); } internal void RaiseCompleted() { Status = FileSystemHandlerStatus.Completed; + _completionSource.SetResult(Status); } public void Abort() @@ -150,5 +155,10 @@ namespace Tango.FSE.Common.FileSystem Status = FileSystemHandlerStatus.Aborted; _abortAction?.Invoke(); } + + public Task WaitForCompletion() + { + return _completionSource.Task; + } } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/IFileSystemProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/IFileSystemProvider.cs index 169b1f771..cade631fa 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/IFileSystemProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/IFileSystemProvider.cs @@ -60,6 +60,15 @@ namespace Tango.FSE.Common.FileSystem /// Task Upload(String localSourcePath, FileSystemItem remoteFolder); + /// + /// Uploads the specified local file or folder. + /// + /// The local source path. + /// The remote destination path. + /// + /// Could not locate the local file or directory to upload. + Task Upload(String localSourcePath, String remotePath); + /// /// Copies the specified remote file or folder to the specified target remote folder. /// diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/INavigationBlocker.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/INavigationBlocker.cs index 1cb81412c..0a96200ea 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/INavigationBlocker.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/INavigationBlocker.cs @@ -17,5 +17,12 @@ namespace Tango.FSE.Common.Navigation /// /// Task OnNavigateOutRequest(); + + /// + /// Called before the navigation system navigates back from this object. + /// Return false to abort the navigation. + /// + /// + Task OnNavigateBackRequest(); } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/INavigationManager.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/INavigationManager.cs index f22a2f931..e80d3e1f1 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/INavigationManager.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/INavigationManager.cs @@ -86,12 +86,6 @@ namespace Tango.FSE.Common.Navigation /// The view path. Task NavigateTo(bool pushToHistory = true, params String[] viewPath) where T : IFSEModule; - /// - /// Navigates to the specified module and view by full path (e.g Jobs.JobsView). - /// - /// The full path. - Task NavigateTo(String fullPath, bool pushToHistory = true, Action onNavigating = null, Action onNavigated = null); - /// /// Navigates to the specified module and view with the specified object and expecting a return parameter. /// The view must be of type INavigationResultProvider. @@ -121,5 +115,12 @@ namespace Tango.FSE.Common.Navigation /// Clears the navigation back history except the specified view type. /// void ClearHistoryExcept(); + + /// + /// Deletes the specified history item. + /// + /// The type of the module. + /// The type of the view. + void DeleteHistoryItem() where TModule : IFSEModule; } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteUpgrade/IRemoteUpgradeManager.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteUpgrade/IRemoteUpgradeManager.cs index 20bc9b3db..4d2389dc6 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteUpgrade/IRemoteUpgradeManager.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteUpgrade/IRemoteUpgradeManager.cs @@ -34,5 +34,12 @@ namespace Tango.FSE.Common.RemoteUpgrade /// The file path. /// Task CreateTfpFile(TangoVersion tangoVersion, String targetFilePath); + + /// + /// Performs a remote application upgrade using the specified .tup file. + /// + /// The .tup file. + /// + Task PerformRemoteApplicationUpgrade(String tupFile); } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/FileSystem/DefaultFileSystemProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/FileSystem/DefaultFileSystemProvider.cs index 3ab27fe1e..49dc35f72 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/FileSystem/DefaultFileSystemProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/FileSystem/DefaultFileSystemProvider.cs @@ -530,8 +530,21 @@ namespace Tango.FSE.UI.FileSystem /// Could not locate the local file or directory to upload. public Task Upload(String localSourcePath, FileSystemItem remoteFolder) { - String operationId = String.Empty; String destination = Path.Combine(remoteFolder.Path, Path.GetFileName(localSourcePath)); + return Upload(localSourcePath, destination); + } + + /// + /// Uploads the specified local file or folder. + /// + /// The local source path. + /// The remote destination path. + /// + /// Could not locate the local file or directory to upload. + public Task Upload(String localSourcePath, String remotePath) + { + String operationId = String.Empty; + String destination = remotePath; bool isFolder = false; bool aborted = false; @@ -539,13 +552,13 @@ namespace Tango.FSE.UI.FileSystem if (Directory.Exists(localSourcePath)) { - LogManager.Log($"Uploading local folder '{localSourcePath}' to remote path '{remoteFolder.Path}'..."); + LogManager.Log($"Uploading local folder '{localSourcePath}' to remote path '{destination}'..."); sourceItem = new FolderItem() { Path = localSourcePath }; isFolder = true; } else if (File.Exists(localSourcePath)) { - LogManager.Log($"Uploading local file '{localSourcePath}' to remote path '{remoteFolder.Path}'..."); + LogManager.Log($"Uploading local file '{localSourcePath}' to remote path '{destination}'..."); sourceItem = new FileItem() { Path = localSourcePath }; isFolder = false; } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Navigation/DefaultNavigationManager.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Navigation/DefaultNavigationManager.cs index fc196b239..0013986fe 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Navigation/DefaultNavigationManager.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Navigation/DefaultNavigationManager.cs @@ -44,7 +44,6 @@ namespace Tango.FSE.UI.Navigation private Object _currentVM; private String _lastFullPath; private bool _preventHistory; - private bool _navigating_back; private Stack _navigationHistory; @@ -116,6 +115,7 @@ namespace Tango.FSE.UI.Navigation if (view == NavigationView.Home) { _navigationHistory.Clear(); + RaisePropertyChanged(nameof(CanNavigateBack)); _lastFullPath = null; var firstModule = _moduleLoader.UserModules.SingleOrDefault(x => x.Name == "Internal Module"); @@ -233,7 +233,7 @@ namespace Tango.FSE.UI.Navigation /// Navigates to the specified module and view by full path (e.g Jobs.JobsView). /// /// The full path. - public async Task NavigateTo(String fullPath, bool pushToHistory = true, Action onNavigating = null, Action onNavigated = null) + private async Task NavigateTo(String fullPath, bool pushToHistory = true, Action onNavigating = null, Action onNavigated = null, bool navigatingBack = false) { try { @@ -253,22 +253,37 @@ namespace Tango.FSE.UI.Navigation if (path.Length == 1 && path[0] == CurrentModule.Name) return true; - LogManager.Log($"Navigating to: {fullPath}..."); - var fromVM = _currentVM; if (_currentVM != null && _currentVM is INavigationBlocker) { - if (!await (_currentVM as INavigationBlocker).OnNavigateOutRequest()) + if (navigatingBack) + { + if (!await (_currentVM as INavigationBlocker).OnNavigateBackRequest()) + { + return false; + } + } + else { - return false; + if (!await (_currentVM as INavigationBlocker).OnNavigateOutRequest()) + { + return false; + } } } + LogManager.Log($"Navigating to: {fullPath}..."); + if (pushToHistory && _lastFullPath != null && !_preventHistory) { - _navigationHistory.Push(_lastFullPath); + if (_navigationHistory.Count == 0 || _navigationHistory.Peek() != _lastFullPath) + { + _navigationHistory.Push(_lastFullPath); + } RaisePropertyChanged(nameof(CanNavigateBack)); + + DistinctNavigationHistory(); } _lastFullPath = fullPath; @@ -376,7 +391,8 @@ namespace Tango.FSE.UI.Navigation } catch (Exception ex) { - await _notificationProvider.ShowError($"Error navigating to '{fullPath}'."); + LogManager.Log(ex, $"Error navigating to '{fullPath}'."); + _notificationProvider.PushErrorReportingSnackbar(ex, "Navigation Error", $"Error navigating to '{fullPath}'."); return false; } } @@ -479,25 +495,34 @@ namespace Tango.FSE.UI.Navigation { LogManager.Log("Navigating back..."); - _navigating_back = true; + if (_navigationHistory.Count > 0) + { + while (_navigationHistory.Peek() == _lastFullPath) + { + _navigationHistory.Pop(); + } + } + + RaisePropertyChanged(nameof(CanNavigateBack)); if (_navigationHistory.Count > 0) { String first = _navigationHistory.Pop(); _preventHistory = true; - if (await NavigateTo(first)) + if (await NavigateTo(first, true, null, null, true)) { RaisePropertyChanged(nameof(CanNavigateBack)); _preventHistory = false; - _navigating_back = false; return true; } else { - _navigationHistory.Push(first); + if (_navigationHistory.Count == 0 || _navigationHistory.Peek() != first) + { + _navigationHistory.Push(first); + } _preventHistory = false; - _navigating_back = false; RaisePropertyChanged(nameof(CanNavigateBack)); return false; } @@ -507,7 +532,6 @@ namespace Tango.FSE.UI.Navigation await NavigateTo(NavigationView.Home); RaisePropertyChanged(nameof(CanNavigateBack)); _preventHistory = false; - _navigating_back = false; return true; } } @@ -532,6 +556,7 @@ namespace Tango.FSE.UI.Navigation var history_list = _navigationHistory.ToList(); history_list = history_list.Where(x => x.Contains(typeof(T).Name)).Distinct().ToList(); + history_list.Reverse(); _navigationHistory.Clear(); foreach (var item in history_list) @@ -578,5 +603,33 @@ namespace Tango.FSE.UI.Navigation awaiter.Action(); } } + + public void DeleteHistoryItem() where TModule : IFSEModule + { + var history_list = _navigationHistory.ToList(); + history_list = history_list.Where(x => x != typeof(TModule).Name + "." + typeof(TView).Name).ToList(); + history_list.Reverse(); + _navigationHistory.Clear(); + + foreach (var item in history_list) + { + _navigationHistory.Push(item); + } + } + + private void DistinctNavigationHistory() + { + var history_list = _navigationHistory.Distinct().ToList(); + history_list = history_list.ToList(); + history_list.Reverse(); + _navigationHistory.Clear(); + + foreach (var item in history_list) + { + _navigationHistory.Push(item); + } + + RaisePropertyChanged(nameof(CanNavigateBack)); + } } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/RemoteUpgrade/DefaultRemoteUpgradeManager.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/RemoteUpgrade/DefaultRemoteUpgradeManager.cs index 83cf6ecf7..eb57717cb 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/RemoteUpgrade/DefaultRemoteUpgradeManager.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/RemoteUpgrade/DefaultRemoteUpgradeManager.cs @@ -14,14 +14,17 @@ using Tango.Core.DB; using Tango.Core.DI; using Tango.Core.ExtensionMethods; using Tango.Core.Threading; +using Tango.FileSystem; using Tango.FSE.BL.Web; using Tango.FSE.Common; using Tango.FSE.Common.Authentication; using Tango.FSE.Common.Connection; +using Tango.FSE.Common.FileSystem; using Tango.FSE.Common.MachineUpdates; using Tango.FSE.Common.RemoteUpgrade; using Tango.FSE.Web.Messages; using Tango.PPC.Common.Publish; +using Tango.PPC.Shared.RemoteUpgrade; using Tango.PPC.Shared.Updates; using Tango.SQLExaminer; using Tango.Transport; @@ -39,6 +42,7 @@ namespace Tango.FSE.UI.RemoteUpgrade private IMachineProvider MachineProvider { get; set; } private FSEWebClient WebClient { get; set; } private IAuthenticationProvider AuthenticationProvider { get; set; } + private IFileSystemProvider FileSystemProvider { get; set; } /// /// Initializes a new instance of the class. @@ -46,11 +50,12 @@ namespace Tango.FSE.UI.RemoteUpgrade /// The authentication provider. /// The machine provider. /// The web client. - public DefaultRemoteUpgradeManager(IAuthenticationProvider authenticationProvider, IMachineProvider machineProvider, FSEWebClient webClient) + public DefaultRemoteUpgradeManager(IAuthenticationProvider authenticationProvider, IMachineProvider machineProvider, FSEWebClient webClient, IFileSystemProvider fileSystemProvider) { AuthenticationProvider = authenticationProvider; MachineProvider = machineProvider; WebClient = webClient; + FileSystemProvider = fileSystemProvider; } /// @@ -388,5 +393,97 @@ namespace Tango.FSE.UI.RemoteUpgrade return Task.FromResult(handler); } + + /// + /// Performs a remote application upgrade using the specified .tup file. + /// + /// The .tup file. + /// + public Task PerformRemoteApplicationUpgrade(string tupFile) + { + RemoteUpgradeHandler handler = new RemoteUpgradeHandler(() => { }); + + ThreadFactory.StartNew(() => + { + try + { + Thread.Sleep(100); + + LogManager.Log($"Starting remote application upgrade for the currently connected machine '{MachineProvider.Machine.SerialNumber}'..."); + + handler.UpdateProgress("Validating machine connection state..."); + LogManager.Log("Validating machine connection state..."); + + if (!MachineProvider.IsConnected) + { + throw new InvalidOperationException("Machine is disconnected."); + } + + if (!MachineProvider.ConnectionType.IsRemote()) + { + throw new InvalidOperationException("The current machine connection does not support remote application upgrade."); + } + + if (!File.Exists(tupFile)) + { + throw new FileNotFoundException("Could not locate the specified package file."); + } + + handler.UpdateProgress("Uploading application package file..."); + + LogManager.Log("Retrieving remote temporary folder..."); + var remoteTempFolder = FileSystemProvider.GetFolder("%temp%").Result as FileSystemItem; + var remoteTempFile = Path.Combine(remoteTempFolder.Path, Path.GetTempFileName()); + + LogManager.Log("Uploading tup file to remote machine..."); + var uploadHandler = FileSystemProvider.Upload(tupFile, remoteTempFile).Result; + uploadHandler.PropertyChanged += (_, __) => + { + handler.UpdateProgress("Uploading application package file...", false, uploadHandler.Position, uploadHandler.Length); + }; + var status = uploadHandler.WaitForCompletion().Result; + LogManager.Log("Tup upload completed successfully. Sending remote upgrade request..."); + + TaskCompletionSource completionSource = new TaskCompletionSource(); + + MachineProvider.MachineOperator.SendGenericContinuousRequest(new StartRemoteApplicationRemoteUpgradeRequest() + { + RemoteTupFilePath = remoteTempFile, + SetupFirmware = true, + SetupFPGA = true + }, new TransportContinuousRequestConfig() + { + ContinuousTimeout = TimeSpan.FromSeconds(30), + Timeout = TimeSpan.FromSeconds(10) + }).Subscribe((response) => + { + //Response.. + handler.Message = response.Message; + handler.IsIndeterminate = response.IsIndeterminate; + handler.Progress = response.Progress; + handler.Maximum = response.Maximum; + }, (ex) => + { + //Failed + completionSource.SetException(ex); + }, () => + { + //Completed + completionSource.SetResult(true); + }); + + var waitForCompletion = completionSource.Task.Result; + + handler.RaiseCompleted(); + } + catch (Exception ex) + { + handler.UpdateProgress($"Remote application upgrade failed. {ex.Message}", false, 0, 100); + handler.RaiseFailed(ex); + } + }); + + return Task.FromResult(handler); + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs index 9a12552bc..2dfea3ff3 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs @@ -35,6 +35,8 @@ using Tango.PPC.Common.ExternalBridge; using Tango.Integration.ExternalBridge; using Tango.BL.DTO; using Tango.PPC.Shared.Updates; +using Tango.PPC.Shared.RemoteUpgrade; +using Tango.Core.Threading; namespace Tango.PPC.Common.MachineUpdate { diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationRemoteUpgradeRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationRemoteUpgradeRequest.cs new file mode 100644 index 000000000..035e08775 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationRemoteUpgradeRequest.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.RemoteUpgrade +{ + public class StartRemoteApplicationRemoteUpgradeRequest + { + public String RemoteTupFilePath { get; set; } + public bool SetupFirmware { get; set; } = true; + public bool SetupFPGA { get; set; } = true; + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationRemoteUpgradeResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationRemoteUpgradeResponse.cs new file mode 100644 index 000000000..ce8010793 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationRemoteUpgradeResponse.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.RemoteUpgrade +{ + public class StartRemoteApplicationRemoteUpgradeResponse + { + public String Message { get; set; } + public bool IsIndeterminate { get; set; } + public double Progress { get; set; } + public double Maximum { get; set; } + + public StartRemoteApplicationRemoteUpgradeResponse() + { + Message = "Initializing..."; + IsIndeterminate = true; + Maximum = 100; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj index 96c18129a..04012cf7b 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj @@ -80,6 +80,8 @@ Settings.settings True + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MachineUpdateViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MachineUpdateViewVM.cs index 3942a1b84..8a8b87c97 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MachineUpdateViewVM.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MachineUpdateViewVM.cs @@ -5,24 +5,29 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using Tango.BL; using Tango.Core.Commands; using Tango.Core.ExtensionMethods; using Tango.Core.Helpers; +using Tango.Core.Threading; using Tango.Explorer; +using Tango.Integration.ExternalBridge; using Tango.PMR.FirmwareUpgrade; using Tango.PPC.Common; +using Tango.PPC.Common.ExternalBridge; using Tango.PPC.Common.MachineUpdate; using Tango.PPC.Common.Publish; using Tango.PPC.Common.Web; +using Tango.PPC.Shared.RemoteUpgrade; using Tango.PPC.UI.Dialogs; using Tango.PPC.UI.Notifications.NotificationItems; using Tango.PPC.UI.ViewsContracts; namespace Tango.PPC.UI.ViewModels { - public class MachineUpdateViewVM : PPCViewModel + public class MachineUpdateViewVM : PPCViewModel, IExternalBridgeRequestHandler { public enum MachineUpdateView { @@ -114,9 +119,10 @@ namespace Tango.PPC.UI.ViewModels #region Constructors - public MachineUpdateViewVM(IMachineUpdateManager machineUpdateManager) + public MachineUpdateViewVM(IMachineUpdateManager machineUpdateManager, IPPCExternalBridgeService externalBridge) { MachineUpdateManager = machineUpdateManager; + externalBridge.RegisterRequestHandler(this); CompleteCommand = new RelayCommand(CompleteUpdate); UpdateCommand = new RelayCommand(Update); @@ -491,7 +497,7 @@ namespace Tango.PPC.UI.ViewModels LogManager.Log("Firmware upgrade from package completed."); _update_result = new MachineUpdateResult() { - RequiresBinariesUpdate = false, + RequiresBinariesUpdate = false, }; await NavigateTo(MachineUpdateView.UpdateCompletedView); } @@ -540,5 +546,103 @@ namespace Tango.PPC.UI.ViewModels } #endregion + + #region External Bridge Handler + + [ExternalBridgeRequestHandlerMethod(typeof(StartRemoteApplicationRemoteUpgradeRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnStartRemoteApplicationRemoteUpgradeRequest(StartRemoteApplicationRemoteUpgradeRequest request, String token, ExternalBridgeReceiver receiver) + { + await receiver.SendGenericResponse(new StartRemoteApplicationRemoteUpgradeResponse(), token); + + bool stopReporting = false; + + try + { + ThreadFactory.StartNew(async () => + { + while (!stopReporting) + { + if (MachineUpdateManager.Status != null) + { + try + { + await receiver.SendGenericResponse(new StartRemoteApplicationRemoteUpgradeResponse() + { + Message = MachineUpdateManager.Status.Message, + IsIndeterminate = MachineUpdateManager.Status.IsIntermediate, + Maximum = MachineUpdateManager.Status.Total, + Progress = MachineUpdateManager.Status.Progress + }, token); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error sending remote upgrade progress."); + } + } + + Thread.Sleep(500); + } + }); + + InvokeUI(() => + { + NavigationManager.NavigateTo(Common.Navigation.NavigationView.MachineUpdateView); + NavigateTo(MachineUpdateView.UpdateProgressView); + }); + + LogManager.Log("Starting machine update from package..."); + + try + { + _update_result = await MachineUpdateManager.UpdateFromTUP(request.RemoteTupFilePath, request.SetupFirmware, request.SetupFPGA); + LogManager.Log("Machine update from package completed."); + + InvokeUI(() => + { + NavigateTo(MachineUpdateView.UpdateCompletedView); + }); + } + catch (Exception ex) + { + LogManager.Log(ex, "Machine update from package failed."); + FailedError = ex.FlattenMessage(); + + InvokeUI(() => + { + NavigateTo(MachineUpdateView.UpdateFailedFromPackageView); + }); + } + + await receiver.SendGenericResponse(new StartRemoteApplicationRemoteUpgradeResponse() + { + IsIndeterminate = false, + Maximum = 100, + Progress = 100, + Message = "Completed" + }, token, new Transport.TransportResponseConfig() + { + Completed = true + }); + } + catch (Exception ex) + { + await receiver.SendErrorResponse(ex, token); + } + finally + { + try + { + File.Delete(request.RemoteTupFilePath); + } + catch { } + } + } + + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) + { + + } + + #endregion } } -- cgit v1.3.1