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. --- .../CefInstaller.cs | 1 + .../Tango.PPC.Packages.CefInstaller.csproj | 5 + .../Console/DefaultConsoleEngineService.cs | 78 +++-- .../Console/IConsoleEngineService.cs | 7 +- .../FileSystem/DefaultFileSystemService.cs | 383 +++++++++------------ .../FileSystem/FileSystemOperation.cs | 51 +++ .../FileSystem/FileSystemOperationMode.cs | 14 + .../FileSystem/IFileSystemService.cs | 10 +- .../PPC/Tango.PPC.Common/IPPCService.cs | 36 ++ .../MachineUpdate/MachineUpdateManager.cs | 29 +- .../Performance/DefaultPerformanceService.cs | 26 +- .../Performance/IPerformanceService.cs | 4 +- .../RemoteDesktop/DefaultRemoteDesktopService.cs | 91 ++--- .../RemoteDesktop/IRemoteDesktopService.cs | 12 +- .../RemoteDesktop/RemoteDesktopClient.cs | 20 ++ .../SystemInfo/DefaultSystemInfoService.cs | 57 ++- .../SystemInfo/ISystemInfoService.cs | 8 +- .../PPC/Tango.PPC.Common/Tango.PPC.Common.csproj | 6 +- .../SamplePostPackage.cs | 1 + .../Tango.PPC.Packages.SamplePostPackage.csproj | 5 + .../SamplePrePackage.cs | 1 + .../Tango.PPC.Packages.SamplePrePackage.csproj | 5 + 22 files changed, 477 insertions(+), 373 deletions(-) create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperation.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperationMode.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/IPPCService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/RemoteDesktopClient.cs (limited to 'Software/Visual_Studio/PPC') diff --git a/Software/Visual_Studio/PPC/Packages/Tango.PPC.Packages.CefInstaller/CefInstaller.cs b/Software/Visual_Studio/PPC/Packages/Tango.PPC.Packages.CefInstaller/CefInstaller.cs index b302bd1d4..a4ea5dc4f 100644 --- a/Software/Visual_Studio/PPC/Packages/Tango.PPC.Packages.CefInstaller/CefInstaller.cs +++ b/Software/Visual_Studio/PPC/Packages/Tango.PPC.Packages.CefInstaller/CefInstaller.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Tango.Core; using Tango.Core.Helpers; using Tango.PPC.Common.UpdatePackages; +using Tango.PPC.Shared.Updates; using Tango.Transport.Web; namespace Tango.PPC.Packages.CefInstaller diff --git a/Software/Visual_Studio/PPC/Packages/Tango.PPC.Packages.CefInstaller/Tango.PPC.Packages.CefInstaller.csproj b/Software/Visual_Studio/PPC/Packages/Tango.PPC.Packages.CefInstaller/Tango.PPC.Packages.CefInstaller.csproj index 9ade464ea..8e7ec8253 100644 --- a/Software/Visual_Studio/PPC/Packages/Tango.PPC.Packages.CefInstaller/Tango.PPC.Packages.CefInstaller.csproj +++ b/Software/Visual_Studio/PPC/Packages/Tango.PPC.Packages.CefInstaller/Tango.PPC.Packages.CefInstaller.csproj @@ -67,6 +67,11 @@ Tango.PPC.Common False + + {208c8bd8-72c6-4e3c-acaa-351091a2acc7} + Tango.PPC.Shared + False + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Console/DefaultConsoleEngineService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Console/DefaultConsoleEngineService.cs index 4a9ee468a..94b677b18 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Console/DefaultConsoleEngineService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Console/DefaultConsoleEngineService.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading.Tasks; using Tango.Console; using Tango.Console.Network; +using Tango.Core; using Tango.Core.DI; using Tango.Integration.ExternalBridge; using Tango.PPC.Common.ExternalBridge; @@ -12,19 +13,40 @@ using Tango.Transport; namespace Tango.PPC.Common.Console { + /// + /// Represents the default implementation + /// which listens to incoming console request by registering as a external bridge request handler. + /// + /// + /// [TangoCreateWhenRegistered] - public class DefaultConsoleEngineService : IConsoleEngineService, IExternalBridgeRequestHandler + public class DefaultConsoleEngineService : ExtendedObject, IConsoleEngineService, IExternalBridgeRequestHandler { + /// + /// Gets or sets a value indicating whether this is enabled. + /// public bool Enabled { get; set; } = true; + /// + /// Initializes a new instance of the class. + /// + /// The external bridge service instance. public DefaultConsoleEngineService(IPPCExternalBridgeService externalBridge) { externalBridge.RegisterRequestHandler(this); } - [ExternalBridgeRequestHandlerMethod(typeof(GetCurrentDirectoryRequest))] - public async void OnGetCurrentDirectoryRequest(GetCurrentDirectoryRequest request, String token, ITransporter transporter) + /// + /// Handles requests. + /// + /// The request. + /// The token. + /// The transporter. + [ExternalBridgeRequestHandlerMethod(typeof(GetCurrentDirectoryRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnGetCurrentDirectoryRequest(GetCurrentDirectoryRequest request, String token, ITransporter transporter) { + this.ThrowIfDisabled(); + await transporter.SendGenericResponse(new GetCurrentDirectoryResponse() { CurrentDirectory = Environment.CurrentDirectory, @@ -32,35 +54,39 @@ namespace Tango.PPC.Common.Console }, token); } - [ExternalBridgeRequestHandlerMethod(typeof(ConsoleCommandRequest))] - public async void OnConsoleCommandRequest(ConsoleCommandRequest request, String token, ITransporter transporter) + /// + /// Handles requests. + /// + /// The request. + /// The token. + /// The transporter. + [ExternalBridgeRequestHandlerMethod(typeof(ConsoleCommandRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnConsoleCommandRequest(ConsoleCommandRequest request, String token, ITransporter transporter) { - if (Enabled) + this.ThrowIfDisabled(); + + LogManager.Log($"{nameof(ConsoleCommandRequest)} received with command '{request.Command}'. Executing..."); + + ConsoleExecutionEngine engine = new ConsoleExecutionEngine(); + var result = await engine.Execute(request); + + LogManager.Log("Console command executed successfully."); + + await transporter.SendGenericResponse(new ConsoleCommandResponse() { - try - { - ConsoleExecutionEngine engine = new ConsoleExecutionEngine(); - var result = await engine.Execute(request); - await transporter.SendGenericResponse(new ConsoleCommandResponse() - { - Output = result.Output, - Suggestions = result.Suggestions, - WorkingFolder = result.WorkingFolder - }, token, new TransportResponseConfig() - { - Immediate = true, - }); - } - catch (Exception ex) - { - await transporter.SendErrorResponse(ex, token); - } - } + Output = result.Output, + Suggestions = result.Suggestions, + WorkingFolder = result.WorkingFolder + }, token); } + /// + /// Called when any of the external bridge clients (receivers) has disconnected. + /// + /// The receiver. public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) { - + //Do nothing. } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Console/IConsoleEngineService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Console/IConsoleEngineService.cs index 612ff302b..18edb3629 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Console/IConsoleEngineService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Console/IConsoleEngineService.cs @@ -6,8 +6,11 @@ using System.Threading.Tasks; namespace Tango.PPC.Common.Console { - public interface IConsoleEngineService + /// + /// Represents a command prompt console service which listens for incoming console requests. + /// + public interface IConsoleEngineService : IPPCService { - bool Enabled { get; set; } + } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs index a7f77855a..02975a2b3 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs @@ -18,31 +18,15 @@ using Tango.WebRTC; namespace Tango.PPC.Common.FileSystem { + /// + /// Represents the default implementation. + /// + /// + /// + /// [TangoCreateWhenRegistered] public class DefaultFileSystemService : ExtendedObject, IFileSystemService, IExternalBridgeRequestHandler { - private enum FileSystemOperationMode - { - Upload, - Download - } - - private class FileSystemOperation - { - public FileSystemOperationMode Mode { get; set; } - public String Id { get; set; } - public String Path { get; set; } - public bool IsPathTempZip { get; set; } - public String UploadPostPath { get; set; } - - public FileSystemOperation(FileSystemOperationMode mode, String path) - { - Mode = mode; - Id = Guid.NewGuid().ToString(); - Path = path; - } - } - private FileSystemManager _manager; private Dictionary _operations; private Dictionary _webRtcClients; @@ -58,9 +42,11 @@ namespace Tango.PPC.Common.FileSystem externalBridge.RegisterRequestHandler(this); } - [ExternalBridgeRequestHandlerMethod(typeof(InitWebRtcRequest))] - public async void OnInitWebRtcRequest(InitWebRtcRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(InitWebRtcRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnInitWebRtcRequest(InitWebRtcRequest request, String token, ExternalBridgeReceiver receiver) { + this.ThrowIfDisabled(); + try { if (!EnableWebRTC) @@ -69,15 +55,18 @@ namespace Tango.PPC.Common.FileSystem return; } + LogManager.Log("Initializing WebRTC channel for file system service."); + if (_webRtcClients.ContainsKey(receiver)) { _webRtcClients[receiver].Dispose(); } + LogManager.Log("Initializing WebRTC transport adapter on 'Passive' mode."); var webRtcAdapter = new WebRtcTransportAdapter(receiver, WebRtcTransportAdapterMode.Passive, request.DataChannelName); webRtcAdapter.Ready += (x, e) => { - LogManager.Log("File System via WebRTC is ready."); + LogManager.Log("The file system service WebRTC channel is ready."); }; BasicTransporter webRtcTransporter = new BasicTransporter(webRtcAdapter); @@ -87,199 +76,171 @@ namespace Tango.PPC.Common.FileSystem webRtcTransporter.RegisterRequestHandler(WebRtcChunkDownloadRequestReceived); webRtcTransporter.RegisterRequestHandler(WebRtcChunkUploadRequestReceived); await webRtcTransporter.Connect(); + + LogManager.Log("Sending WebRTC initialization response..."); + await receiver.SendGenericResponse(new InitWebRtcResponse(), token); _webRtcClients[receiver] = webRtcTransporter; } catch (Exception ex) { + LogManager.Log(ex, "Error initializing WebRTC channel for file system service."); await receiver.SendErrorResponse(ex, token); } } - private void WebRtcChunkDownloadRequestReceived(ITransporter transporter, ChunkDownloadRequest request, string token) + private async void WebRtcChunkDownloadRequestReceived(ITransporter transporter, ChunkDownloadRequest request, string token) { - OnChunkDownloadRequest(request, token, transporter); + await OnChunkDownloadRequest(request, token, transporter); } - private void WebRtcChunkUploadRequestReceived(ITransporter transporter, ChunkUploadRequest request, string token) + private async void WebRtcChunkUploadRequestReceived(ITransporter transporter, ChunkUploadRequest request, string token) { - OnChunkUploadRequest(request, token, transporter); + await OnChunkUploadRequest(request, token, transporter); } - [ExternalBridgeRequestHandlerMethod(typeof(GetFileSystemItemRequest))] - public async void OnGetFileSystemItemRequest(GetFileSystemItemRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(GetFileSystemItemRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnGetFileSystemItemRequest(GetFileSystemItemRequest request, String token, ExternalBridgeReceiver receiver) { - try - { - FileSystemItemDTO dto = _manager.GetFolder(request); - await receiver.SendGenericResponse(new GetFileSystemItemResponse() { FileSystemItem = dto }, token); - } - catch (Exception ex) - { - await receiver.SendErrorResponse(ex, token); - } + this.ThrowIfDisabled(); + + FileSystemItemDTO dto = _manager.GetFolder(request); + await receiver.SendGenericResponse(new GetFileSystemItemResponse() { FileSystemItem = dto }, token); } - [ExternalBridgeRequestHandlerMethod(typeof(FileUploadRequest))] - public async void OnFileUploadRequest(FileUploadRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(FileUploadRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnFileUploadRequest(FileUploadRequest request, String token, ExternalBridgeReceiver receiver) { - try - { - var tempFile = TemporaryManager.CreateFile(); - using (var stream = new FileStream(tempFile, FileMode.Create)) { } + this.ThrowIfDisabled(); - FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Upload, tempFile) { UploadPostPath = request.Path }; - _operations.Add(operation.Id, operation); + var tempFile = TemporaryManager.CreateFile(); + using (var stream = new FileStream(tempFile, FileMode.Create)) { } - await receiver.SendGenericResponse(new FileUploadResponse() { OperationId = operation.Id }, token); - } - catch (Exception ex) - { - await receiver.SendErrorResponse(ex, token); - } + FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Upload, tempFile) { UploadPostPath = request.Path }; + _operations.Add(operation.Id, operation); + + await receiver.SendGenericResponse(new FileUploadResponse() { OperationId = operation.Id }, token); } - [ExternalBridgeRequestHandlerMethod(typeof(FolderUploadRequest))] - public async void OnFolderUploadRequest(FolderUploadRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(FolderUploadRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnFolderUploadRequest(FolderUploadRequest request, String token, ExternalBridgeReceiver receiver) { - try - { - var tempFile = TemporaryManager.CreateFile(); - using (var stream = new FileStream(tempFile, FileMode.Create)) { } + this.ThrowIfDisabled(); - FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Upload, tempFile) { UploadPostPath = request.Path, IsPathTempZip = true }; - _operations.Add(operation.Id, operation); + var tempFile = TemporaryManager.CreateFile(); + using (var stream = new FileStream(tempFile, FileMode.Create)) { } - await receiver.SendGenericResponse(new FolderUploadResponse() { OperationId = operation.Id }, token); - } - catch (Exception ex) - { - await receiver.SendErrorResponse(ex, token); - } + FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Upload, tempFile) { UploadPostPath = request.Path, IsPathTempZip = true }; + _operations.Add(operation.Id, operation); + + await receiver.SendGenericResponse(new FolderUploadResponse() { OperationId = operation.Id }, token); } - [ExternalBridgeRequestHandlerMethod(typeof(FileDownloadRequest))] - public async void OnFileDownloadRequest(FileDownloadRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(FileDownloadRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnFileDownloadRequest(FileDownloadRequest request, String token, ExternalBridgeReceiver receiver) { - try + this.ThrowIfDisabled(); + + if (!File.Exists(request.Path)) { - if (!File.Exists(request.Path)) - { - await receiver.SendErrorResponse(new FileNotFoundException("Could not find the specified file."), token); - return; - } + throw new FileNotFoundException("Could not find the specified file."); + } - FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Download, request.Path); + FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Download, request.Path); - _operations.Add(operation.Id, operation); + _operations.Add(operation.Id, operation); - await receiver.SendGenericResponse(new FileDownloadResponse() - { - OperationId = operation.Id, - Length = new FileInfo(request.Path).Length - }, token); - } - catch (Exception ex) + await receiver.SendGenericResponse(new FileDownloadResponse() { - await receiver.SendErrorResponse(ex, token); - } + OperationId = operation.Id, + Length = new FileInfo(request.Path).Length + }, token); } - [ExternalBridgeRequestHandlerMethod(typeof(FolderDownloadRequest))] - public async void OnFolderDownloadRequest(FolderDownloadRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(FolderDownloadRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnFolderDownloadRequest(FolderDownloadRequest request, String token, ExternalBridgeReceiver receiver) { - try + this.ThrowIfDisabled(); + + if (!Directory.Exists(request.Path)) { - if (!Directory.Exists(request.Path)) - { - await receiver.SendErrorResponse(new FileNotFoundException("Could not find the specified directory."), token); - return; - } + throw new FileNotFoundException("Could not find the specified directory."); + } - var tempFile = TemporaryManager.CreateImaginaryFile(); + var tempFile = TemporaryManager.CreateImaginaryFile(); - ZipFile.CreateFromDirectory(request.Path, tempFile); + ZipFile.CreateFromDirectory(request.Path, tempFile); - FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Download, tempFile); - operation.IsPathTempZip = true; + FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Download, tempFile); + operation.IsPathTempZip = true; - _operations.Add(operation.Id, operation); + _operations.Add(operation.Id, operation); - await receiver.SendGenericResponse(new FolderDownloadResponse() - { - OperationId = operation.Id, - Length = new FileInfo(tempFile).Length - }, token); - } - catch (Exception ex) + await receiver.SendGenericResponse(new FolderDownloadResponse() { - await receiver.SendErrorResponse(ex, token); - } + OperationId = operation.Id, + Length = new FileInfo(tempFile).Length + }, token); } [ExternalBridgeRequestHandlerMethod(typeof(ChunkUploadRequest))] - public async void OnChunkUploadRequest(ChunkUploadRequest request, String token, ITransporter receiver) + public async Task OnChunkUploadRequest(ChunkUploadRequest request, String token, ITransporter receiver) { - try + this.ThrowIfDisabled(); + + FileSystemOperation operation; + _operations.TryGetValue(request.OperationId, out operation); + + if (operation == null) { - FileSystemOperation operation; - _operations.TryGetValue(request.OperationId, out operation); + throw new ArgumentException("Invalid operation id."); + } - if (operation == null) - { - await receiver.SendErrorResponse(new ArgumentException("Invalid operation id."), token); - return; - } + using (var stream = new FileStream(operation.Path, FileMode.Append)) + { + stream.Write(request.Data, 0, request.Data.Length); + } - using (var stream = new FileStream(operation.Path, FileMode.Append)) + if (request.IsCompleted) + { + if (!operation.IsPathTempZip) { - stream.Write(request.Data, 0, request.Data.Length); + File.Copy(operation.Path, operation.UploadPostPath, true); + try + { + File.Delete(operation.Path); + } + catch { } } - - if (request.IsCompleted) + else { - if (!operation.IsPathTempZip) + using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile(operation.Path)) { - File.Copy(operation.Path, operation.UploadPostPath, true); - try - { - File.Delete(operation.Path); - } - catch { } + zip.ExtractAll(operation.UploadPostPath, Ionic.Zip.ExtractExistingFileAction.OverwriteSilently); } - else - { - using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile(operation.Path)) - { - zip.ExtractAll(operation.UploadPostPath, Ionic.Zip.ExtractExistingFileAction.OverwriteSilently); - } - try - { - File.Delete(operation.Path); - } - catch { } + try + { + File.Delete(operation.Path); } + catch { } } - - await receiver.SendGenericResponse(new ChunkUploadResponse(), token, new TransportResponseConfig() { Priority = QueuePriority.Low }); - } - catch (Exception ex) - { - await receiver.SendErrorResponse(ex, token); } + + await receiver.SendGenericResponse(new ChunkUploadResponse(), token, new TransportResponseConfig() { Priority = QueuePriority.Low }); } [ExternalBridgeRequestHandlerMethod(typeof(ChunkDownloadRequest))] - public async void OnChunkDownloadRequest(ChunkDownloadRequest request, String token, ITransporter receiver) + public async Task OnChunkDownloadRequest(ChunkDownloadRequest request, String token, ITransporter receiver) { + this.ThrowIfDisabled(); + FileSystemOperation operation; _operations.TryGetValue(request.OperationId, out operation); if (operation == null) { - await receiver.SendErrorResponse(new ArgumentException("Invalid operation id."), token); - return; + throw new ArgumentException("Invalid operation id."); } FileStream stream = null; @@ -307,7 +268,7 @@ namespace Tango.PPC.Common.FileSystem catch (Exception ex) { stream?.Dispose(); - await receiver.SendErrorResponse(ex, token); + throw ex; } finally { @@ -325,111 +286,78 @@ namespace Tango.PPC.Common.FileSystem } } - [ExternalBridgeRequestHandlerMethod(typeof(AbortOperationRequest))] - public async void OnAbortOperationRequest(AbortOperationRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(AbortOperationRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnAbortOperationRequest(AbortOperationRequest request, String token, ExternalBridgeReceiver receiver) { + this.ThrowIfDisabled(); + FileSystemOperation operation; _operations.TryGetValue(request.OperationId, out operation); if (operation == null) { - await receiver.SendErrorResponse(new ArgumentException("Invalid operation id."), token); - return; + throw new ArgumentException("Invalid operation id."); } - try + if (operation.Mode == FileSystemOperationMode.Upload) { - if (operation.Mode == FileSystemOperationMode.Upload) + if (File.Exists(operation.Path)) { - if (File.Exists(operation.Path)) - { - File.Delete(operation.Path); - } + File.Delete(operation.Path); } - else if (operation.IsPathTempZip) - { - if (File.Exists(operation.Path)) - { - File.Delete(operation.Path); - } - } - - await receiver.SendGenericResponse(new AbortOperationResponse(), token); } - catch (Exception ex) + else if (operation.IsPathTempZip) { - await receiver.SendErrorResponse(ex, token); + if (File.Exists(operation.Path)) + { + File.Delete(operation.Path); + } } + + await receiver.SendGenericResponse(new AbortOperationResponse(), token); } - [ExternalBridgeRequestHandlerMethod(typeof(MoveRequest))] - public async void OnMoveRequest(MoveRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(MoveRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnMoveRequest(MoveRequest request, String token, ExternalBridgeReceiver receiver) { - try - { - _manager.Move(request); - await receiver.SendGenericResponse(new MoveResponse(), token); - } - catch (Exception ex) - { - await receiver.SendErrorResponse(ex, token); - } + this.ThrowIfDisabled(); + + _manager.Move(request); + await receiver.SendGenericResponse(new MoveResponse(), token); } - [ExternalBridgeRequestHandlerMethod(typeof(CopyRequest))] - public async void OnCopyRequest(CopyRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(CopyRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnCopyRequest(CopyRequest request, String token, ExternalBridgeReceiver receiver) { - try - { - _manager.Copy(request); - await receiver.SendGenericResponse(new CopyResponse(), token); - } - catch (Exception ex) - { - await receiver.SendErrorResponse(ex, token); - } + this.ThrowIfDisabled(); + + _manager.Copy(request); + await receiver.SendGenericResponse(new CopyResponse(), token); } - [ExternalBridgeRequestHandlerMethod(typeof(DeleteRequest))] - public async void OnDeleteRequest(DeleteRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(DeleteRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnDeleteRequest(DeleteRequest request, String token, ExternalBridgeReceiver receiver) { - try - { - _manager.Delete(request.Path); - await receiver.SendGenericResponse(new DeleteResponse(), token); - } - catch (Exception ex) - { - await receiver.SendErrorResponse(ex, token); - } + this.ThrowIfDisabled(); + + _manager.Delete(request.Path); + await receiver.SendGenericResponse(new DeleteResponse(), token); } - [ExternalBridgeRequestHandlerMethod(typeof(CreateFolderRequest))] - public async void OnCreateFolderRequest(CreateFolderRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(CreateFolderRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnCreateFolderRequest(CreateFolderRequest request, String token, ExternalBridgeReceiver receiver) { - try - { - var dto = _manager.CreateFolder(request.Path, request.FolderName); - await receiver.SendGenericResponse(new CreateFolderResponse() { FolderItem = dto }, token); - } - catch (Exception ex) - { - await receiver.SendErrorResponse(ex, token); - } + this.ThrowIfDisabled(); + + var dto = _manager.CreateFolder(request.Path, request.FolderName); + await receiver.SendGenericResponse(new CreateFolderResponse() { FolderItem = dto }, token); } - [ExternalBridgeRequestHandlerMethod(typeof(PerformDiskSpaceOptimizationRequest))] - public async void OnPerformDiskSpaceOptimizationRequest(PerformDiskSpaceOptimizationRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(PerformDiskSpaceOptimizationRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnPerformDiskSpaceOptimizationRequest(PerformDiskSpaceOptimizationRequest request, String token, ExternalBridgeReceiver receiver) { - try - { - var deletedBytes = _manager.PerformDiskSpaceOptimization(); - await receiver.SendGenericResponse(new PerformDiskSpaceOptimizationResponse() { DeletedBytes = deletedBytes }, token); - } - catch (Exception ex) - { - await receiver.SendErrorResponse(ex, token); - } + var deletedBytes = _manager.PerformDiskSpaceOptimization(); + await receiver.SendGenericResponse(new PerformDiskSpaceOptimizationResponse() { DeletedBytes = deletedBytes }, token); } public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) @@ -438,13 +366,14 @@ namespace Tango.PPC.Common.FileSystem { try { + LogManager.Log("External bridge receiver disconnected. Disposing file system service WebRTC channel..."); var webRtcTransporter = _webRtcClients[receiver]; _webRtcClients.Remove(receiver); webRtcTransporter.Dispose(); } catch (Exception ex) { - LogManager.Log(ex, "Error disposing the WebRTC transporter."); + LogManager.Log(ex, "Error disposing the WebRTC channel."); } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperation.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperation.cs new file mode 100644 index 000000000..9fba7a874 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperation.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.FileSystem +{ + /// + /// Represents an active file system file/folder download/upload operation + /// + public class FileSystemOperation + { + /// + /// Gets or sets the operation mode. + /// + public FileSystemOperationMode Mode { get; set; } + + /// + /// Gets or sets the operation identifier. + /// + public String Id { get; set; } + + /// + /// Gets or sets the path for the operation. + /// + public String Path { get; set; } + + /// + /// Should be set to true when the is a temporary zip file when performing download of a folder. + /// + public bool IsPathTempZip { get; set; } + + /// + /// Gets or sets the actual path to extract the zip file when uploading folder. + /// + public String UploadPostPath { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The mode. + /// The path. + public FileSystemOperation(FileSystemOperationMode mode, String path) + { + Mode = mode; + Id = Guid.NewGuid().ToString(); + Path = path; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperationMode.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperationMode.cs new file mode 100644 index 000000000..e28843bce --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperationMode.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.FileSystem +{ + public enum FileSystemOperationMode + { + Upload, + Download + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/IFileSystemService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/IFileSystemService.cs index 6cf3321a3..7a80db9c7 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/IFileSystemService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/IFileSystemService.cs @@ -6,9 +6,15 @@ using System.Threading.Tasks; namespace Tango.PPC.Common.FileSystem { - public interface IFileSystemService + /// + /// Represents a PPC file system remote service. + /// + /// + public interface IFileSystemService : IPPCService { - bool Enabled { get; set; } + /// + /// Gets or sets a value indicating whether to enable the WebRTC transport channel. + /// bool EnableWebRTC { get; set; } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/IPPCService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/IPPCService.cs new file mode 100644 index 000000000..5dfe5335c --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/IPPCService.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Common; + +namespace Tango.PPC.Common +{ + /// + /// Represents a PPC remoting service. + /// + public interface IPPCService + { + /// + /// Gets or sets a value indicating whether this is enabled. + /// + bool Enabled { get; set; } + } +} + +public static class ExtensionMethods +{ + /// + /// Throws an exception is the service is disabled. + /// + /// The service. + /// + public static void ThrowIfDisabled(this IPPCService service) + { + if (!service.Enabled) + { + throw new NotSupportedException($"The {service.GetType().Name} is currently disabled. Could not perform the requested action."); + } + } +} 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); } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/DefaultPerformanceService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/DefaultPerformanceService.cs index d327f6b00..59236f667 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/DefaultPerformanceService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/DefaultPerformanceService.cs @@ -96,26 +96,18 @@ namespace Tango.PPC.Common.Performance externalBridge.RegisterRequestHandler(this); } - [ExternalBridgeRequestHandlerMethod(typeof(StartPerformanceUpdatesRequest))] - public async void OnStartPerformanceUpdatesRequest(StartPerformanceUpdatesRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(StartPerformanceUpdatesRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnStartPerformanceUpdatesRequest(StartPerformanceUpdatesRequest request, String token, ExternalBridgeReceiver receiver) { - if (Enabled) - { - try - { - if (!_clients.Exists(x => x.Receiver == receiver)) - { - _clients.Add(new PerformanceClient() { Receiver = receiver, Token = token }); - OnReceiversChanged(); - } + this.ThrowIfDisabled(); - await receiver.SendGenericResponse(new StartPerformanceUpdatesResponse() { Package = _package }, token); - } - catch (Exception ex) - { - LogManager.Log(ex, "Error sending performance package."); - } + if (!_clients.Exists(x => x.Receiver == receiver)) + { + _clients.Add(new PerformanceClient() { Receiver = receiver, Token = token }); + OnReceiversChanged(); } + + await receiver.SendGenericResponse(new StartPerformanceUpdatesResponse() { Package = _package }, token); } public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/IPerformanceService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/IPerformanceService.cs index c3bfd1543..29e69aee2 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/IPerformanceService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/IPerformanceService.cs @@ -7,8 +7,8 @@ using Tango.Integration.ExternalBridge; namespace Tango.PPC.Common.Performance { - public interface IPerformanceService : IExternalBridgeRequestHandler + public interface IPerformanceService : IPPCService, IExternalBridgeRequestHandler { - bool Enabled { get; set; } + } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/DefaultRemoteDesktopService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/DefaultRemoteDesktopService.cs index 849befc27..7ba020174 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/DefaultRemoteDesktopService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/DefaultRemoteDesktopService.cs @@ -10,6 +10,7 @@ using System.Windows.Input; using Tango.Core; using Tango.Core.DI; using Tango.Integration.ExternalBridge; +using Tango.Logging; using Tango.PPC.Common.Application; using Tango.PPC.Common.ExternalBridge; using Tango.PPC.Common.OS; @@ -30,15 +31,6 @@ namespace Tango.PPC.Common.RemoteDesktop [TangoCreateWhenRegistered] public class DefaultRemoteDesktopService : ExtendedObject, IRemoteDesktopService, IExternalBridgeRequestHandler { - private class RemoteDesktopClient - { - public String Token { get; set; } - public ExternalBridgeReceiver Receiver { get; set; } - public bool InitialPacketSent { get; set; } - public WebRtcClient WebRtcClient { get; set; } - public bool IsWebRtcReady { get; set; } - } - private RemoteDesktopPacket _initialPacket; private RasterScreenCaptureEngine _engine; private PPCSettings _settings; @@ -47,14 +39,24 @@ namespace Tango.PPC.Common.RemoteDesktop private IOperationSystemManager _osManager; private IPPCApplicationManager _appManager; + /// + /// Gets or sets a value indicating whether this is enabled. + /// + public bool Enabled { get; set; } = true; private bool _isStarted; + /// + /// Gets a value indicating whether the remote desktop service has started. + /// public bool IsStarted { get { return _isStarted; } private set { _isStarted = value; RaisePropertyChangedAuto(); } } + /// + /// Gets a value indicating whether there is any active remote desktop session with a remote peer. + /// public bool InSession { get @@ -63,6 +65,12 @@ namespace Tango.PPC.Common.RemoteDesktop } } + /// + /// Initializes a new instance of the class. + /// + /// The application manager. + /// The external bridge. + /// The os manager. public DefaultRemoteDesktopService(IPPCApplicationManager applicationManager, IPPCExternalBridgeService externalBridge, IOperationSystemManager osManager) { _osManager = osManager; @@ -74,6 +82,8 @@ namespace Tango.PPC.Common.RemoteDesktop }; _settings = SettingsManager.Default.GetOrCreate(); + Enabled = _settings.EnableRemoteDesktop; + applicationManager.ApplicationReady += ApplicationManager_ApplicationReady; externalBridge.RegisterRequestHandler(this); @@ -118,14 +128,10 @@ namespace Tango.PPC.Common.RemoteDesktop _engine.Comparer.MaxDifferencesThrow = _engine.CaptureRegion.Width * _engine.CaptureRegion.Height / 2; } - [ExternalBridgeRequestHandlerMethod(typeof(StartRemoteDesktopSessionRequest))] - public async void OnStartRemoteDesktopSessionRequestReceived(StartRemoteDesktopSessionRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(StartRemoteDesktopSessionRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnStartRemoteDesktopSessionRequestReceived(StartRemoteDesktopSessionRequest request, String token, ExternalBridgeReceiver receiver) { - if (!_settings.EnableRemoteDesktop) - { - await receiver.SendErrorResponse(new AuthenticationException("Remote desktop is disabled on this machine."), token); - return; - } + this.ThrowIfDisabled(); var client = _clients.SingleOrDefault(x => x.Receiver == receiver); @@ -146,19 +152,17 @@ namespace Tango.PPC.Common.RemoteDesktop FrameRate = _engine.FrameRate }, token); - if (_settings.EnableRemoteDesktop) + + if (!_engine.IsStarted) { - if (!_engine.IsStarted) - { - _engine.Start(); - } + _engine.Start(); } RaisePropertyChanged(nameof(InSession)); } - [ExternalBridgeRequestHandlerMethod(typeof(WebRtcIceCandidateRequest))] - public async void OnWebRtcIceCandidateRequestReceived(WebRtcIceCandidateRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(WebRtcIceCandidateRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnWebRtcIceCandidateRequestReceived(WebRtcIceCandidateRequest request, String token, ExternalBridgeReceiver receiver) { var client = _clients.SingleOrDefault(x => x.Receiver == receiver); @@ -171,13 +175,13 @@ namespace Tango.PPC.Common.RemoteDesktop } catch (Exception ex) { - LogManager.Log($"Error adding WebRTC ice candidate received from the remote connection.\n{ex.FlattenMessage()}"); + LogManager.Log(ex, "Error adding WebRTC ice candidate received from the remote connection."); } } } - [ExternalBridgeRequestHandlerMethod(typeof(WebRtcOfferRequest))] - public async void OnWebRtcOfferRequestReceived(WebRtcOfferRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(WebRtcOfferRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnWebRtcOfferRequestReceived(WebRtcOfferRequest request, String token, ExternalBridgeReceiver receiver) { var client = _clients.SingleOrDefault(x => x.Receiver == receiver); @@ -196,7 +200,7 @@ namespace Tango.PPC.Common.RemoteDesktop } catch (Exception ex) { - LogManager.Log(ex, $"Error sending ice candidate to remote peer.\n{ex.FlattenMessage()}"); + LogManager.Log(ex, "Error sending ice candidate to remote peer."); } }; client.WebRtcClient.Ready += (x, e) => @@ -219,18 +223,18 @@ namespace Tango.PPC.Common.RemoteDesktop } catch (Exception ex) { - LogManager.Log($"Error initializing the web RTC client.\n{ex.FlattenMessage()}"); + throw LogManager.Log(ex, "Error initializing the WebRTC client."); } } catch (Exception ex) { - LogManager.Log($"Error responding to WebRTC offer request.\n{ex.FlattenMessage()}"); + throw LogManager.Log(ex, "Error responding to WebRTC offer request."); } } } - [ExternalBridgeRequestHandlerMethod(typeof(StopRemoteDesktopSessionRequest))] - public async void OnStopRemoteDesktopSessionRequestReceived(StopRemoteDesktopSessionRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(StopRemoteDesktopSessionRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnStopRemoteDesktopSessionRequestReceived(StopRemoteDesktopSessionRequest request, String token, ExternalBridgeReceiver receiver) { var client = _clients.SingleOrDefault(x => x.Receiver == receiver); @@ -260,7 +264,7 @@ namespace Tango.PPC.Common.RemoteDesktop } [ExternalBridgeRequestHandlerMethod(typeof(MouseStateRequest))] - public async void OnMouseStateRequestReceived(MouseStateRequest request, String token, ExternalBridgeReceiver receiver) + public async Task OnMouseStateRequestReceived(MouseStateRequest request, String token, ExternalBridgeReceiver receiver) { MouseController.SetCursorPosition((int)request.Location.X, (int)request.Location.Y); @@ -292,7 +296,7 @@ namespace Tango.PPC.Common.RemoteDesktop } [ExternalBridgeRequestHandlerMethod(typeof(KeyboardStateRequest))] - public async void OnKeyboardStateRequestReceived(KeyboardStateRequest request, String token, ExternalBridgeReceiver receiver) + public async Task OnKeyboardStateRequestReceived(KeyboardStateRequest request, String token, ExternalBridgeReceiver receiver) { if (request.EventType == KeyboardEventType.Down) { @@ -309,8 +313,8 @@ namespace Tango.PPC.Common.RemoteDesktop } } - [ExternalBridgeRequestHandlerMethod(typeof(RemoteDesktopCommandRequest))] - public async void OnRemoteDesktopCommandRequest(RemoteDesktopCommandRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(RemoteDesktopCommandRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnRemoteDesktopCommandRequest(RemoteDesktopCommandRequest request, String token, ExternalBridgeReceiver receiver) { switch (request.Command) { @@ -346,7 +350,7 @@ namespace Tango.PPC.Common.RemoteDesktop } catch (Exception ex) { - Debug.WriteLine(ex); + LogManager.Log(ex, LogCategory.Debug, "Error pushing remote desktop frame via WebRTC channel."); } } @@ -382,7 +386,6 @@ namespace Tango.PPC.Common.RemoteDesktop if (!e.Frame.DifferenceAvailable) { - Debug.WriteLine("Using Jpeg..."); packet = new RemoteDesktopPacket() { Bitmap = e.Frame.ToEncoder().ToArray(30) @@ -403,7 +406,7 @@ namespace Tango.PPC.Common.RemoteDesktop diffFrame.Dispose(); } - Debug.WriteLine($"Bitmap Size: {packet.Bitmap.Length / 1000} kb"); + Debug.WriteLine($"Remote Desktop Bitmap Size: {packet.Bitmap.Length / 1000} kb"); foreach (var client in _clients.ToList().Where(x => x.InitialPacketSent)) { @@ -429,7 +432,7 @@ namespace Tango.PPC.Common.RemoteDesktop e.Frame.Dispose(); } - private void WebRtcClient_TextMessageReceived(object sender, DataMessageReceivedEventArgs e) + private async void WebRtcClient_TextMessageReceived(object sender, DataMessageReceivedEventArgs e) { try { @@ -437,16 +440,16 @@ namespace Tango.PPC.Common.RemoteDesktop if (request.GetType() == typeof(MouseStateRequest)) { - OnMouseStateRequestReceived(request as MouseStateRequest, null, null); + await OnMouseStateRequestReceived(request as MouseStateRequest, null, null); } else if (request.GetType() == typeof(KeyboardStateRequest)) { - OnKeyboardStateRequestReceived(request as KeyboardStateRequest, null, null); + await OnKeyboardStateRequestReceived(request as KeyboardStateRequest, null, null); } } catch (Exception ex) { - LogManager.Log(ex, "Error deserializing incoming from message on the WebRTC data Channel."); + LogManager.Log(ex, "Error deserializing incoming message on the WebRTC data Channel."); } } @@ -456,6 +459,8 @@ namespace Tango.PPC.Common.RemoteDesktop if (client != null) { + LogManager.Log("Remote desktop client disconnected. Disposing WebRTC channel..."); + _clients.Remove(client); try @@ -467,7 +472,7 @@ namespace Tango.PPC.Common.RemoteDesktop } catch (Exception ex) { - LogManager.Log($"Error disposing the WebRTC client.\n{ex.FlattenMessage()}"); + LogManager.Log(ex, "Error disposing the WebRTC channel."); } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/IRemoteDesktopService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/IRemoteDesktopService.cs index 5760b94dc..5e4a801d7 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/IRemoteDesktopService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/IRemoteDesktopService.cs @@ -6,9 +6,19 @@ using System.Threading.Tasks; namespace Tango.PPC.Common.RemoteDesktop { - public interface IRemoteDesktopService + /// + /// Represents a PPC remote desktop service. + /// + public interface IRemoteDesktopService : IPPCService { + /// + /// Gets a value indicating whether the remote desktop service has started. + /// bool IsStarted { get; } + + /// + /// Gets a value indicating whether there is any active remote desktop session with a remote peer. + /// bool InSession { get; } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/RemoteDesktopClient.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/RemoteDesktopClient.cs new file mode 100644 index 000000000..f0f0a87de --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/RemoteDesktopClient.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Integration.ExternalBridge; +using Tango.WebRTC; + +namespace Tango.PPC.Common.RemoteDesktop +{ + public class RemoteDesktopClient + { + public String Token { get; set; } + public ExternalBridgeReceiver Receiver { get; set; } + public bool InitialPacketSent { get; set; } + public WebRtcClient WebRtcClient { get; set; } + public bool IsWebRtcReady { get; set; } + } + +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/DefaultSystemInfoService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/DefaultSystemInfoService.cs index ef8e31bce..f80a8be1e 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/DefaultSystemInfoService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/DefaultSystemInfoService.cs @@ -33,30 +33,28 @@ namespace Tango.PPC.Common.SystemInfo externalBridge.RegisterRequestHandler(this); } - [ExternalBridgeRequestHandlerMethod(typeof(GetMachineInformationRequest))] - public async void OnGetMachineInformationRequest(GetMachineInformationRequest request, String token, ExternalBridgeReceiver receiver) + [ExternalBridgeRequestHandlerMethod(typeof(GetMachineInformationRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnGetMachineInformationRequest(GetMachineInformationRequest request, String token, ExternalBridgeReceiver receiver) { - try + if (response == null) { - if (response == null) - { - //Get the networks that are currently connected to - var connectedNetwork = NetworkListManager.GetNetworks(NetworkConnectivityLevels.Connected).FirstOrDefault(); + //Get the networks that are currently connected to + var connectedNetwork = NetworkListManager.GetNetworks(NetworkConnectivityLevels.Connected).FirstOrDefault(); - var settings = SettingsManager.Default.GetOrCreate(); + var settings = SettingsManager.Default.GetOrCreate(); - List system = new List(); + List system = new List(); - if (!Debugger.IsAttached) - { - system = SystemObjectsCollection.Create(); - } + if (!Debugger.IsAttached) + { + system = SystemObjectsCollection.Create(); + } - //Add custom information.. - system.Insert(0, new SystemObjectsCollection() - { - Name = "Application", - Objects = new List() + //Add custom information.. + system.Insert(0, new SystemObjectsCollection() + { + Name = "Application", + Objects = new List() { new SystemObject() { @@ -112,23 +110,18 @@ namespace Tango.PPC.Common.SystemInfo }.OrderBy(x => x.Name).ToList(), }, }, - }); + }); - response = new GetMachineInformationResponse() + response = new GetMachineInformationResponse() + { + Package = new InformationPackage() { - Package = new InformationPackage() - { - System = system, - } - }; - } - - await receiver.SendGenericResponse(response, token); - } - catch (Exception ex) - { - LogManager.Log(ex, "Error sending system information."); + System = system, + } + }; } + + await receiver.SendGenericResponse(response, token); } public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/ISystemInfoService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/ISystemInfoService.cs index 0cc493891..47ea7bd4b 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/ISystemInfoService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/ISystemInfoService.cs @@ -6,8 +6,12 @@ using System.Threading.Tasks; namespace Tango.PPC.Common.SystemInfo { - public interface ISystemInfoService + /// + /// Represents a PPC system information service. + /// + /// + public interface ISystemInfoService : IPPCService { - bool Enabled { get; set; } + } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj b/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj index 9575b7137..e97fd9d32 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj @@ -156,11 +156,14 @@ + + + @@ -169,6 +172,7 @@ + @@ -456,7 +460,7 @@ - + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/SamplePostPackage.cs b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/SamplePostPackage.cs index 53af736c9..f6fb2c935 100644 --- a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/SamplePostPackage.cs +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/SamplePostPackage.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading.Tasks; using Tango.Core; using Tango.PPC.Common.UpdatePackages; +using Tango.PPC.Shared.Updates; namespace Tango.PPC.Packages.SamplePostPackage { diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/Tango.PPC.Packages.SamplePostPackage.csproj b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/Tango.PPC.Packages.SamplePostPackage.csproj index f06fdd5cf..d528c5c14 100644 --- a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/Tango.PPC.Packages.SamplePostPackage.csproj +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/Tango.PPC.Packages.SamplePostPackage.csproj @@ -60,6 +60,11 @@ Tango.PPC.Common False + + {208c8bd8-72c6-4e3c-acaa-351091a2acc7} + Tango.PPC.Shared + False + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/SamplePrePackage.cs b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/SamplePrePackage.cs index 5aa811e85..1913d3f28 100644 --- a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/SamplePrePackage.cs +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/SamplePrePackage.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading.Tasks; using Tango.Core; using Tango.PPC.Common.UpdatePackages; +using Tango.PPC.Shared.Updates; namespace Tango.PPC.Packages.SamplePrePackage { diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/Tango.PPC.Packages.SamplePrePackage.csproj b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/Tango.PPC.Packages.SamplePrePackage.csproj index b4397d253..4437a05c4 100644 --- a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/Tango.PPC.Packages.SamplePrePackage.csproj +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/Tango.PPC.Packages.SamplePrePackage.csproj @@ -60,6 +60,11 @@ Tango.PPC.Common False + + {208c8bd8-72c6-4e3c-acaa-351091a2acc7} + Tango.PPC.Shared + False + \ No newline at end of file -- cgit v1.3.1 From efe8812d48fe783c3c8871da0c54b7ef916b4998 Mon Sep 17 00:00:00 2001 From: Roy Ben Shabat Date: Thu, 9 Apr 2020 04:04:23 +0300 Subject: Added application information to login response. Several improvements and fixed. --- .../Integration/ApplicationInformation.proto | 10 ++ .../Integration/ExternalBridgeLoginResponse.proto | 2 + .../Connectivity/DefaultConnectivityProvider.cs | 6 +- .../Visual_Studio/FSE/Tango.FSE.BL/DataResolver.cs | 9 +- .../FSE/Tango.FSE.BL/Tango.FSE.BL.csproj | 4 + .../FSE/Tango.FSE.Common/FSEViewModel.cs | 7 + .../Tango.FSE.UI/Panes/ConnectedMachinePane.xaml | 2 + .../FSE/Tango.FSE.UI/Views/LayoutView.xaml | 17 ++ .../ViewModels/ExternalBridgeViewVM.cs | 3 + .../ExternalBridgeClientConnectedEventArgs.cs | 7 + .../ExternalBridge/ExternalBridgeReceiver.cs | 3 +- .../ExternalBridgeReceiverLoginRequestEventArgs.cs | 8 +- .../ExternalBridge/ExternalBridgeService.cs | 2 +- .../ExternalBridge/ExternalBridgeTcpClient.cs | 12 ++ .../Integration/ApplicationInformation.cs | 188 +++++++++++++++++++++ .../Integration/ExternalBridgeLoginResponse.cs | 52 +++++- Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj | 3 +- 17 files changed, 317 insertions(+), 18 deletions(-) create mode 100644 Software/PMR/Messages/Integration/ApplicationInformation.proto create mode 100644 Software/Visual_Studio/Tango.PMR/Integration/ApplicationInformation.cs (limited to 'Software/Visual_Studio/PPC') diff --git a/Software/PMR/Messages/Integration/ApplicationInformation.proto b/Software/PMR/Messages/Integration/ApplicationInformation.proto new file mode 100644 index 000000000..7dd05daa0 --- /dev/null +++ b/Software/PMR/Messages/Integration/ApplicationInformation.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; + +package Tango.PMR.Integration; +option java_package = "com.twine.tango.pmr.integration"; + +message ApplicationInformation +{ + string Version = 1; + string StartupDate = 2; +} \ No newline at end of file diff --git a/Software/PMR/Messages/Integration/ExternalBridgeLoginResponse.proto b/Software/PMR/Messages/Integration/ExternalBridgeLoginResponse.proto index 481646244..d75e8b51e 100644 --- a/Software/PMR/Messages/Integration/ExternalBridgeLoginResponse.proto +++ b/Software/PMR/Messages/Integration/ExternalBridgeLoginResponse.proto @@ -1,6 +1,7 @@ syntax = "proto3"; import "DeviceInformation.proto"; +import "ApplicationInformation.proto"; package Tango.PMR.Integration; option java_package = "com.twine.tango.pmr.integration"; @@ -10,4 +11,5 @@ message ExternalBridgeLoginResponse bool Authenticated = 1; string SerialNumber = 2; PMR.Connection.DeviceInformation DeviceInformation = 3; + ApplicationInformation ApplicationInformation = 4; } \ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/Connectivity/DefaultConnectivityProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/Connectivity/DefaultConnectivityProvider.cs index fc5405022..8b51d85c4 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/Connectivity/DefaultConnectivityProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/Connectivity/DefaultConnectivityProvider.cs @@ -35,7 +35,11 @@ namespace Tango.FSE.BL.Connectivity public bool IsOnline { get { return _isOnline; } - set { _isOnline = value; RaisePropertyChangedAuto(); } + set + { + _isOnline = value; + RaisePropertyChanged(nameof(IsOnline)); + } } /// diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/DataResolver.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/DataResolver.cs index e59cc74bc..f1d1dd88a 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/DataResolver.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/DataResolver.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.Core; +using Tango.Core.DI; using Tango.FSE.BL.Connectivity; using Tango.Logging; @@ -17,7 +18,7 @@ namespace Tango.FSE.BL /// public class DataResolver : ExtendedObject where T : class { - private IConnectivityProvider _connectivity; + private static IConnectivityProvider _connectivity; private Func _onlineAction; private Func _diskCacheAction; private Func _memoryCacheAction; @@ -32,7 +33,11 @@ namespace Tango.FSE.BL /// private DataResolver() { - _connectivity = new DefaultConnectivityProvider(); + if (_connectivity == null) + { + _connectivity = TangoIOC.Default.GetInstance(); + } + _nodes = new List() { DataResolverNode.Online }; _throwOnError = true; } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/Tango.FSE.BL.csproj b/Software/Visual_Studio/FSE/Tango.FSE.BL/Tango.FSE.BL.csproj index 86f58e7ef..6e9863095 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/Tango.FSE.BL.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/Tango.FSE.BL.csproj @@ -44,18 +44,22 @@ ..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + + + + ..\..\packages\Z.EntityFramework.Extensions.4.0.58\lib\net45\Z.EntityFramework.Extensions.dll diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs index bae284bfe..b3d867349 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs @@ -31,6 +31,7 @@ using Tango.FSE.Common.SystemInfo; using Tango.Settings; using Tango.SharedUI; using static Tango.SharedUI.Controls.NavigationControl; +using Tango.FSE.BL.Connectivity; namespace Tango.FSE.Common { @@ -132,6 +133,12 @@ namespace Tango.FSE.Common [TangoInject] public IMachineUpdatesProvider MachineUpdatesProvider { get; set; } + /// + /// Gets or sets the connectivity provider. + /// + [TangoInject] + public IConnectivityProvider ConnectivityProvider { get; set; } + /// /// Gets or sets the FSE service. /// diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/ConnectedMachinePane.xaml b/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/ConnectedMachinePane.xaml index 0e01ab255..e5791f23c 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/ConnectedMachinePane.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/ConnectedMachinePane.xaml @@ -48,6 +48,8 @@ + + FPGA Version 1: diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Views/LayoutView.xaml b/Software/Visual_Studio/FSE/Tango.FSE.UI/Views/LayoutView.xaml index 1c3cec748..42e2c7af8 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Views/LayoutView.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Views/LayoutView.xaml @@ -92,6 +92,23 @@ + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/ExternalBridgeViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/ExternalBridgeViewVM.cs index 66b982ffe..4b7d8978e 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/ExternalBridgeViewVM.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/ExternalBridgeViewVM.cs @@ -139,6 +139,9 @@ namespace Tango.PPC.UI.ViewModels if (!e.Request.Intent.RequiresPassword() || e.Request.Password == Settings.ExternalBridgePassword) { + e.ApplicationInformation.Version = ApplicationManager.Version.ToString(); + e.ApplicationInformation.StartupDate = ApplicationManager.StartUpDate.ToUniversalTime().ToString(); + e.Confirmed = true; Connection = e; diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeClientConnectedEventArgs.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeClientConnectedEventArgs.cs index 176dae4b3..7130845cc 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeClientConnectedEventArgs.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeClientConnectedEventArgs.cs @@ -13,6 +13,13 @@ namespace Tango.Integration.ExternalBridge public String Address { get; set; } + public ApplicationInformation ApplicationInformation { get; set; } + public bool Confirmed { get; set; } + + public ExternalBridgeClientConnectedEventArgs() + { + ApplicationInformation = new ApplicationInformation(); + } } } diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiver.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiver.cs index 400f58c77..0b63f0be2 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiver.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiver.cs @@ -254,7 +254,7 @@ namespace Tango.Integration.ExternalBridge LogManager.Log($"External bridge login attempt:\nIntent: {request.Message.Intent}\nMessage:\n{request.Message.ToJsonString()}"); - ExternalBridgeReceiverLoginRequestEventArgs args = new ExternalBridgeReceiverLoginRequestEventArgs((machine, deviceInfo) => + ExternalBridgeReceiverLoginRequestEventArgs args = new ExternalBridgeReceiverLoginRequestEventArgs((machine, deviceInfo, applicationInfo) => { //Confirm LogManager.Log("External bridge client has logged-in successfully."); @@ -266,6 +266,7 @@ namespace Tango.Integration.ExternalBridge response.Authenticated = true; response.SerialNumber = machine.SerialNumber; response.DeviceInformation = deviceInfo; + response.ApplicationInformation = applicationInfo; SendResponse(response, container.Token); diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverLoginRequestEventArgs.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverLoginRequestEventArgs.cs index b5c1ec458..1ea33dbce 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverLoginRequestEventArgs.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverLoginRequestEventArgs.cs @@ -11,10 +11,10 @@ namespace Tango.Integration.ExternalBridge { public class ExternalBridgeReceiverLoginRequestEventArgs : EventArgs { - private Action _confirm; + private Action _confirm; private Action _decline; - public ExternalBridgeReceiverLoginRequestEventArgs(Action confirm, Action decline) + public ExternalBridgeReceiverLoginRequestEventArgs(Action confirm, Action decline) { _confirm = confirm; _decline = decline; @@ -24,9 +24,9 @@ namespace Tango.Integration.ExternalBridge public String Address { get; set; } - public void Confirm(Machine machine, DeviceInformation deviceInformation) + public void Confirm(Machine machine, DeviceInformation deviceInformation, ApplicationInformation applicationInformation) { - _confirm(machine, deviceInformation); + _confirm(machine, deviceInformation, applicationInformation); } public void Decline(String reason) diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs index de708a33c..456a5d5a5 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs @@ -384,7 +384,7 @@ namespace Tango.Integration.ExternalBridge if (args.Confirmed) { - e.Confirm(Machine, MachineOperator.DeviceInformation); + e.Confirm(Machine, MachineOperator.DeviceInformation, args.ApplicationInformation); HasSessions = true; if (request.Intent == ExternalBridgeLoginIntent.FullControl) diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeTcpClient.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeTcpClient.cs index 9ba2166eb..850adff2d 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeTcpClient.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeTcpClient.cs @@ -86,6 +86,16 @@ namespace Tango.Integration.ExternalBridge /// public ExternalBridgeLoginRequest LoginRequest { get; set; } + private ApplicationInformation _applicationInformation; + /// + /// Gets or sets the remote application information (PPC). + /// + public ApplicationInformation ApplicationInformation + { + get { return _applicationInformation; } + private set { _applicationInformation = value; RaisePropertyChangedAuto(); } + } + #endregion /// @@ -124,6 +134,8 @@ namespace Tango.Integration.ExternalBridge var response = await SendRequest(login, new TransportRequestConfig() { ShouldLog = true }); + ApplicationInformation = response.Message.ApplicationInformation; + SessionLogger.CreateSession(); DeviceInformation = response.Message.DeviceInformation; diff --git a/Software/Visual_Studio/Tango.PMR/Integration/ApplicationInformation.cs b/Software/Visual_Studio/Tango.PMR/Integration/ApplicationInformation.cs new file mode 100644 index 000000000..d637539f5 --- /dev/null +++ b/Software/Visual_Studio/Tango.PMR/Integration/ApplicationInformation.cs @@ -0,0 +1,188 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: ApplicationInformation.proto +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace Tango.PMR.Integration { + + /// Holder for reflection information generated from ApplicationInformation.proto + public static partial class ApplicationInformationReflection { + + #region Descriptor + /// File descriptor for ApplicationInformation.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static ApplicationInformationReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "ChxBcHBsaWNhdGlvbkluZm9ybWF0aW9uLnByb3RvEhVUYW5nby5QTVIuSW50", + "ZWdyYXRpb24iPgoWQXBwbGljYXRpb25JbmZvcm1hdGlvbhIPCgdWZXJzaW9u", + "GAEgASgJEhMKC1N0YXJ0dXBEYXRlGAIgASgJQiEKH2NvbS50d2luZS50YW5n", + "by5wbXIuaW50ZWdyYXRpb25iBnByb3RvMw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Integration.ApplicationInformation), global::Tango.PMR.Integration.ApplicationInformation.Parser, new[]{ "Version", "StartupDate" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class ApplicationInformation : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ApplicationInformation()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::Tango.PMR.Integration.ApplicationInformationReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationInformation() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationInformation(ApplicationInformation other) : this() { + version_ = other.version_; + startupDate_ = other.startupDate_; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationInformation Clone() { + return new ApplicationInformation(this); + } + + /// Field number for the "Version" field. + public const int VersionFieldNumber = 1; + private string version_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Version { + get { return version_; } + set { + version_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "StartupDate" field. + public const int StartupDateFieldNumber = 2; + private string startupDate_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string StartupDate { + get { return startupDate_; } + set { + startupDate_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ApplicationInformation); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ApplicationInformation other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Version != other.Version) return false; + if (StartupDate != other.StartupDate) return false; + return true; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Version.Length != 0) hash ^= Version.GetHashCode(); + if (StartupDate.Length != 0) hash ^= StartupDate.GetHashCode(); + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Version.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Version); + } + if (StartupDate.Length != 0) { + output.WriteRawTag(18); + output.WriteString(StartupDate); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Version.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Version); + } + if (StartupDate.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(StartupDate); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ApplicationInformation other) { + if (other == null) { + return; + } + if (other.Version.Length != 0) { + Version = other.Version; + } + if (other.StartupDate.Length != 0) { + StartupDate = other.StartupDate; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: { + Version = input.ReadString(); + break; + } + case 18: { + StartupDate = input.ReadString(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/Software/Visual_Studio/Tango.PMR/Integration/ExternalBridgeLoginResponse.cs b/Software/Visual_Studio/Tango.PMR/Integration/ExternalBridgeLoginResponse.cs index 17eb9de93..aa573e47e 100644 --- a/Software/Visual_Studio/Tango.PMR/Integration/ExternalBridgeLoginResponse.cs +++ b/Software/Visual_Studio/Tango.PMR/Integration/ExternalBridgeLoginResponse.cs @@ -23,16 +23,18 @@ namespace Tango.PMR.Integration { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "CiFFeHRlcm5hbEJyaWRnZUxvZ2luUmVzcG9uc2UucHJvdG8SFVRhbmdvLlBN", - "Ui5JbnRlZ3JhdGlvbhoXRGV2aWNlSW5mb3JtYXRpb24ucHJvdG8ijgEKG0V4", - "dGVybmFsQnJpZGdlTG9naW5SZXNwb25zZRIVCg1BdXRoZW50aWNhdGVkGAEg", - "ASgIEhQKDFNlcmlhbE51bWJlchgCIAEoCRJCChFEZXZpY2VJbmZvcm1hdGlv", - "bhgDIAEoCzInLlRhbmdvLlBNUi5Db25uZWN0aW9uLkRldmljZUluZm9ybWF0", - "aW9uQiEKH2NvbS50d2luZS50YW5nby5wbXIuaW50ZWdyYXRpb25iBnByb3Rv", - "Mw==")); + "Ui5JbnRlZ3JhdGlvbhoXRGV2aWNlSW5mb3JtYXRpb24ucHJvdG8aHEFwcGxp", + "Y2F0aW9uSW5mb3JtYXRpb24ucHJvdG8i3QEKG0V4dGVybmFsQnJpZGdlTG9n", + "aW5SZXNwb25zZRIVCg1BdXRoZW50aWNhdGVkGAEgASgIEhQKDFNlcmlhbE51", + "bWJlchgCIAEoCRJCChFEZXZpY2VJbmZvcm1hdGlvbhgDIAEoCzInLlRhbmdv", + "LlBNUi5Db25uZWN0aW9uLkRldmljZUluZm9ybWF0aW9uEk0KFkFwcGxpY2F0", + "aW9uSW5mb3JtYXRpb24YBCABKAsyLS5UYW5nby5QTVIuSW50ZWdyYXRpb24u", + "QXBwbGljYXRpb25JbmZvcm1hdGlvbkIhCh9jb20udHdpbmUudGFuZ28ucG1y", + "LmludGVncmF0aW9uYgZwcm90bzM=")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, - new pbr::FileDescriptor[] { global::Tango.PMR.Connection.DeviceInformationReflection.Descriptor, }, + new pbr::FileDescriptor[] { global::Tango.PMR.Connection.DeviceInformationReflection.Descriptor, global::Tango.PMR.Integration.ApplicationInformationReflection.Descriptor, }, new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { - new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Integration.ExternalBridgeLoginResponse), global::Tango.PMR.Integration.ExternalBridgeLoginResponse.Parser, new[]{ "Authenticated", "SerialNumber", "DeviceInformation" }, null, null, null) + new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Integration.ExternalBridgeLoginResponse), global::Tango.PMR.Integration.ExternalBridgeLoginResponse.Parser, new[]{ "Authenticated", "SerialNumber", "DeviceInformation", "ApplicationInformation" }, null, null, null) })); } #endregion @@ -66,6 +68,7 @@ namespace Tango.PMR.Integration { authenticated_ = other.authenticated_; serialNumber_ = other.serialNumber_; DeviceInformation = other.deviceInformation_ != null ? other.DeviceInformation.Clone() : null; + ApplicationInformation = other.applicationInformation_ != null ? other.ApplicationInformation.Clone() : null; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] @@ -106,6 +109,17 @@ namespace Tango.PMR.Integration { } } + /// Field number for the "ApplicationInformation" field. + public const int ApplicationInformationFieldNumber = 4; + private global::Tango.PMR.Integration.ApplicationInformation applicationInformation_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Tango.PMR.Integration.ApplicationInformation ApplicationInformation { + get { return applicationInformation_; } + set { + applicationInformation_ = value; + } + } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ExternalBridgeLoginResponse); @@ -122,6 +136,7 @@ namespace Tango.PMR.Integration { if (Authenticated != other.Authenticated) return false; if (SerialNumber != other.SerialNumber) return false; if (!object.Equals(DeviceInformation, other.DeviceInformation)) return false; + if (!object.Equals(ApplicationInformation, other.ApplicationInformation)) return false; return true; } @@ -131,6 +146,7 @@ namespace Tango.PMR.Integration { if (Authenticated != false) hash ^= Authenticated.GetHashCode(); if (SerialNumber.Length != 0) hash ^= SerialNumber.GetHashCode(); if (deviceInformation_ != null) hash ^= DeviceInformation.GetHashCode(); + if (applicationInformation_ != null) hash ^= ApplicationInformation.GetHashCode(); return hash; } @@ -153,6 +169,10 @@ namespace Tango.PMR.Integration { output.WriteRawTag(26); output.WriteMessage(DeviceInformation); } + if (applicationInformation_ != null) { + output.WriteRawTag(34); + output.WriteMessage(ApplicationInformation); + } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] @@ -167,6 +187,9 @@ namespace Tango.PMR.Integration { if (deviceInformation_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(DeviceInformation); } + if (applicationInformation_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ApplicationInformation); + } return size; } @@ -187,6 +210,12 @@ namespace Tango.PMR.Integration { } DeviceInformation.MergeFrom(other.DeviceInformation); } + if (other.applicationInformation_ != null) { + if (applicationInformation_ == null) { + applicationInformation_ = new global::Tango.PMR.Integration.ApplicationInformation(); + } + ApplicationInformation.MergeFrom(other.ApplicationInformation); + } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] @@ -212,6 +241,13 @@ namespace Tango.PMR.Integration { input.ReadMessage(deviceInformation_); break; } + case 34: { + if (applicationInformation_ == null) { + applicationInformation_ = new global::Tango.PMR.Integration.ApplicationInformation(); + } + input.ReadMessage(applicationInformation_); + break; + } } } } diff --git a/Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj b/Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj index ce5e8f1e1..8c84db721 100644 --- a/Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj +++ b/Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj @@ -204,6 +204,7 @@ + @@ -330,7 +331,7 @@ - + \ No newline at end of file -- cgit v1.3.1 From b4682a3abfe299c19b24752b2fb1ce2477611ec3 Mon Sep 17 00:00:00 2001 From: Roy Ben Shabat Date: Fri, 10 Apr 2020 15:06:42 +0300 Subject: Implemented FSE/PPC Logs. --- .../Tango.FSE.PPCConsole.csproj | 8 + .../Tango.FSE.PPCConsole/ViewModelLocator.cs | 9 + .../Tango.FSE.PPCConsole/ViewModels/LogsViewVM.cs | 288 +++++++++++++++++++++ .../Tango.FSE.PPCConsole/ViewModels/MainViewVM.cs | 1 + .../Tango.FSE.PPCConsole/Views/LogsView.xaml | 225 ++++++++++++++++ .../Tango.FSE.PPCConsole/Views/LogsView.xaml.cs | 28 ++ .../Tango.FSE.PPCConsole/Views/MainView.xaml | 5 +- .../Tango.FSE.PPCConsole/Views/UpdatesView.xaml | 2 +- .../Dialogs/ApplicationLogItemView.xaml | 4 +- .../Dialogs/FirmwareLogItemView.xaml | 39 +++ .../Dialogs/FirmwareLogItemView.xaml.cs | 28 ++ .../Dialogs/FirmwareLogItemViewVM.cs | 21 ++ .../Dialogs/MachineLogItemView.xaml | 39 --- .../Dialogs/MachineLogItemView.xaml.cs | 28 -- .../Dialogs/MachineLogItemViewVM.cs | 21 -- .../Tango.FSE.Common/Logging/ILoggingProvider.cs | 37 ++- .../Tango.FSE.Common/Logging/RemoteLogFileModel.cs | 128 +++++++++ .../Logging/RemoteLogFileStatus.cs | 19 ++ .../FSE/Tango.FSE.Common/Tango.FSE.Common.csproj | 10 +- .../Connection/DefaultMachineProvider.cs | 5 +- .../Tango.FSE.UI/Logging/DefaultLoggingProvider.cs | 89 ++++++- .../FSE/Tango.FSE.UI/Panes/LogViewerPane.xaml | 12 +- .../FSE/Tango.FSE.UI/Panes/LogViewerPaneVM.cs | 84 +++--- .../FSE/Tango.FSE.UI/ViewModelLocator.cs | 2 +- .../FileSystem/DefaultFileSystemService.cs | 46 ++++ .../Tango.PPC.Shared/Logs/GetLogFilesRequest.cs | 13 + .../Tango.PPC.Shared/Logs/GetLogFilesResponse.cs | 18 ++ .../PPC/Tango.PPC.Shared/Logs/RemoteLogFile.cs | 17 ++ .../PPC/Tango.PPC.Shared/Logs/RemoteLogFileType.cs | 14 + .../PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj | 4 + .../Tango.FileSystem/FileSystemItem.cs | 3 + .../Tango.FileSystem/FileSystemManager.cs | 2 + .../Tango.FileSystem/Network/FileSystemItemDTO.cs | 2 + .../Logging/EmbeddedLogFileParser.cs | 7 + .../Tango.Logging/ApplicationLogFileParser.cs | 7 + .../Visual_Studio/Tango.Logging/ILogFileParser.cs | 2 + Software/Visual_Studio/Tango.Logging/LogFile.cs | 1 - .../Visual_Studio/Tango.Logging/LogItemBase.cs | 8 + .../Tango.SharedUI/Components/BindingProxy.cs | 31 +++ .../Converters/StringToOneLineConverter.cs | 4 +- .../Tango.SharedUI/Tango.SharedUI.csproj | 3 +- 41 files changed, 1156 insertions(+), 158 deletions(-) create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/LogsViewVM.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/LogsView.xaml create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/LogsView.xaml.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemView.xaml create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemView.xaml.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemViewVM.cs delete mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemView.xaml delete mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemView.xaml.cs delete mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemViewVM.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/RemoteLogFileModel.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/RemoteLogFileStatus.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFile.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFileType.cs create mode 100644 Software/Visual_Studio/Tango.SharedUI/Components/BindingProxy.cs (limited to 'Software/Visual_Studio/PPC') diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj index 783dfa9fe..287273015 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj @@ -113,10 +113,14 @@ + + + LogsView.xaml + UpdatesView.xaml @@ -252,6 +256,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + MSBuild:Compile Designer diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModelLocator.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModelLocator.cs index 4faa72e8e..a3b800b22 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModelLocator.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModelLocator.cs @@ -18,6 +18,7 @@ namespace Tango.FSE.PPCConsole TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); + TangoIOC.Default.Register(); } public static MainViewVM MainViewVM @@ -67,5 +68,13 @@ namespace Tango.FSE.PPCConsole return TangoIOC.Default.GetInstance(); } } + + public static LogsViewVM LogsViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/LogsViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/LogsViewVM.cs new file mode 100644 index 000000000..52955e18a --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/LogsViewVM.cs @@ -0,0 +1,288 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using Tango.Core; +using Tango.Core.Commands; +using Tango.Core.Helpers; +using Tango.FSE.Common; +using Tango.FSE.Common.Connection; +using Tango.FSE.Common.Dialogs; +using Tango.FSE.Common.FileSystem; +using Tango.FSE.Common.Logging; +using Tango.Logging; +using Tango.PPC.Shared.Logs; +using Tango.SharedUI.Components; +using static Tango.SharedUI.Controls.NavigationControl; + +namespace Tango.FSE.PPCConsole.ViewModels +{ + public class LogsViewVM : FSEViewModel, INavigationViewModel + { + private bool _loaded; + + private List> _logFiles; + /// + /// Gets or sets the remote log files. + /// + public List> LogFiles + { + get { return _logFiles; } + set { _logFiles = value; RaisePropertyChangedAuto(); } + } + + private RemoteLogFileModel _selectedLogFile; + /// + /// Gets or sets the selected remote log file. + /// + public RemoteLogFileModel SelectedLogFile + { + get { return _selectedLogFile; } + set { _selectedLogFile = value; RaisePropertyChangedAuto(); OnSelectedLogFileChanged(); } + } + + /// + /// Gets or sets the application logs. + /// + public ObservableCollection ApplicationLogs { get; set; } + + /// + /// Gets or sets the application logs view. + /// + public ICollectionView ApplicationLogsView { get; set; } + + /// + /// Gets or sets the selected application logs categories. + /// + public SelectedObjectCollection SelectedApplicationLogsCategories { get; set; } + + private String _applicationLogsFilter; + /// + /// Gets or sets the application logs filter. + /// + public String ApplicationLogsFilter + { + get { return _applicationLogsFilter; } + set { _applicationLogsFilter = value; RaisePropertyChangedAuto(); ApplicationLogsView.Refresh(); } + } + + /// + /// Opens the detailed application log dialog. + /// + public RelayCommand OpenApplicationLogItemCommand { get; set; } + + /// + /// Exports the selected log file to local disk. + /// + public RelayCommand ExportLogFileCommand { get; set; } + + /// + /// Exports all the downloaded log files to disk. + /// + public RelayCommand ExportAllDownloadedLogFilesCommand { get; set; } + + /// + /// Downloads all the available log files. + /// + public RelayCommand DownloadAllLogFilesCommand { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public LogsViewVM() + { + ApplicationLogs = new ObservableCollection(); + ApplicationLogsView = CollectionViewSource.GetDefaultView(ApplicationLogs); + ApplicationLogsView.Filter = FilterApplicationLogs; + SelectedApplicationLogsCategories = new SelectedObjectCollection(new ObservableCollection() + { + LogCategory.Info, + LogCategory.Warning, + LogCategory.Error, + LogCategory.Critical, + }, new ObservableCollection() + { + LogCategory.Info, + LogCategory.Warning, + LogCategory.Error, + LogCategory.Critical, + }); + + SelectedApplicationLogsCategories.SynchedSource.CollectionChanged += (_, __) => ApplicationLogsView.Refresh(); + + OpenApplicationLogItemCommand = new RelayCommand(OpenApplicationLogItem); + + ExportLogFileCommand = new RelayCommand(ExportSelectedLogFile); + ExportAllDownloadedLogFilesCommand = new RelayCommand(ExportAllDownloadedLogFiles); + DownloadAllLogFilesCommand = new RelayCommand(DownloadAllLogFiles); + } + + public override void OnApplicationStarted() + { + base.OnApplicationStarted(); + MachineProvider.MachineConnected += MachineProvider_MachineConnected; + } + + private void MachineProvider_MachineConnected(object sender, MachineConnectedEventArgs e) + { + if (e.DifferentFromPrevious) + { + _loaded = false; + + if (MachineProvider.ConnectionType.IsRemote() && IsVisible) + { + LoadLogFiles(); + } + } + } + + public override void OnNavigatedTo() + { + base.OnNavigatedTo(); + + if (!_loaded) + { + LoadLogFiles(); + } + } + + private async void LoadLogFiles() + { + if (!MachineProvider.ConnectionType.IsRemote() || !IsFree) return; + + try + { + IsFree = false; + var logFiles = await LoggingProvider.GetApplicationLogFiles(); + LogFiles = logFiles.Select(x => + { + + var model = new RemoteLogFileModel(new ApplicationLogFileParser()); + model.RemoteLogFile = x; + model.DownloadCompleted += OnRemoteLogFileDownloadCompleted; + return model; + + }).ToList(); + SelectedLogFile = LogFiles.FirstOrDefault(); + _loaded = true; + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading log files."); + } + finally + { + IsFree = true; + } + } + + private void OnRemoteLogFileDownloadCompleted(object sender, EventArgs e) + { + if (SelectedLogFile == sender) + { + OnSelectedLogFileChanged(); + } + } + + private void OnSelectedLogFileChanged() + { + if (SelectedLogFile == null) return; + + InvokeUI(() => + { + ApplicationLogs.Clear(); + foreach (var logItem in SelectedLogFile.LogItems) + { + ApplicationLogs.Add(logItem); + } + + ApplicationLogsView.Refresh(); + }); + } + + private async void OpenApplicationLogItem(LogItemBase logItem) + { + await NotificationProvider.ShowDialog(new ApplicationLogItemViewVM() { LogItem = logItem }); + } + + private bool FilterApplicationLogs(object obj) + { + var log = obj as LogItemBase; + return SelectedApplicationLogsCategories.SynchedSource.Contains(log.Category) && (String.IsNullOrWhiteSpace(ApplicationLogsFilter) || log.Message.ToLower().Contains(ApplicationLogsFilter.ToLower())); + } + + private async void ExportSelectedLogFile() + { + if (SelectedLogFile != null && SelectedLogFile.Status == RemoteLogFileStatus.Downloaded) + { + var result = await StorageProvider.SaveFile("Export Log File", "Application Log Files|*.log", SelectedLogFile.RemoteLogFile.Name, ".log"); + if (result) + { + using (NotificationProvider.PushTaskItem("Exporting log file...")) + { + try + { + File.Copy(SelectedLogFile.TemporaryFile, result.SelectedItem, true); + await NotificationProvider.ShowSuccess("Log file exported successfully."); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error exporting application log file."); + await NotificationProvider.ShowError($"Could not export the log file.\n{ex.FlattenMessage()}"); + } + } + } + } + } + + private async void ExportAllDownloadedLogFiles() + { + var result = await StorageProvider.SelectFolder("Export Log Files"); + if (result) + { + var toExport = LogFiles.Where(x => x.Status == RemoteLogFileStatus.Downloaded).ToList(); + var count = toExport.Count; + + using (var task = NotificationProvider.PushTaskItem("Exporting log files...")) + { + foreach (var logFile in toExport.ToList()) + { + try + { + await Task.Delay(500); + File.Copy(logFile.TemporaryFile, Path.Combine(result.SelectedItem, logFile.RemoteLogFile.Name), true); + toExport.Remove(logFile); + task.UpdateProgress("Exporting log files...", count - toExport.Count, count, false); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error exporting application log file '{logFile.RemoteLogFile.Name}'."); + await NotificationProvider.ShowError($"Could not export '{logFile.RemoteLogFile.Name}'.\n{ex.FlattenMessage()}"); + } + } + } + + await NotificationProvider.ShowSuccess($"Successfully exported {count - toExport.Count} out of {count} log files."); + } + } + + private async void DownloadAllLogFiles() + { + var toDownload = LogFiles.Where(x => x.Status == RemoteLogFileStatus.None); + var totalSize = FileHelper.GetFriendlyFileSize(toDownload.Select(x => x.RemoteLogFile.Length).Sum()); + + if (await NotificationProvider.ShowWarningQuestion($"Are you sure you wish to download the entire history of log files?\nTotal size: {totalSize}", "DOWNLOAD", "CANCEL")) + { + foreach (var logFile in toDownload) + { + logFile.DownloadLogFile(); + } + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MainViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MainViewVM.cs index e18a75ef6..f4614ccf1 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MainViewVM.cs @@ -20,6 +20,7 @@ namespace Tango.FSE.PPCConsole.ViewModels MonitoringView, FileSystemView, UpdatesView, + LogsView, } private NavigationView _selectedView; diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/LogsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/LogsView.xaml new file mode 100644 index 000000000..81258e971 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/LogsView.xaml @@ -0,0 +1,225 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Download this log file from the remote machine in order to display its content + DOWNLOAD + + + + + + + + Error occurred while trying to download this log file + TRY AGAIN + + + + + + + + Downloading log file, please wait... + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/LogsView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/LogsView.xaml.cs new file mode 100644 index 000000000..d08f18326 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/LogsView.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.PPCConsole.Views +{ + /// + /// Interaction logic for LogsView.xaml + /// + public partial class LogsView : UserControl + { + public LogsView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MainView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MainView.xaml index 1efc0516f..b8932be95 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MainView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MainView.xaml @@ -29,19 +29,20 @@ - + + - + diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/UpdatesView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/UpdatesView.xaml index 037fa6d96..8a8e6546e 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/UpdatesView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/UpdatesView.xaml @@ -60,7 +60,7 @@ - + diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/ApplicationLogItemView.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/ApplicationLogItemView.xaml index 844bdc992..6abda9b6d 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/ApplicationLogItemView.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/ApplicationLogItemView.xaml @@ -11,14 +11,14 @@ - + - + diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemView.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemView.xaml new file mode 100644 index 000000000..49d67f205 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemView.xaml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemView.xaml.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemView.xaml.cs new file mode 100644 index 000000000..6e7556c40 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemView.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.Common.Dialogs +{ + /// + /// Interaction logic for ApplicationLogItemView.xaml + /// + public partial class FirmwareLogItemView : UserControl + { + public FirmwareLogItemView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemViewVM.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemViewVM.cs new file mode 100644 index 000000000..1ee76e381 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemViewVM.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Integration.Logging; + +namespace Tango.FSE.Common.Dialogs +{ + public class FirmwareLogItemViewVM : FSEDialogViewVM + { + public EmbeddedLogItem LogItem { get; set; } + + public FirmwareLogItemViewVM() + { + CanClose = false; + OKText = "CLOSE"; + HasDefault = true; + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemView.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemView.xaml deleted file mode 100644 index 776e6d893..000000000 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemView.xaml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemView.xaml.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemView.xaml.cs deleted file mode 100644 index 97103c34e..000000000 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemView.xaml.cs +++ /dev/null @@ -1,28 +0,0 @@ -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.Common.Dialogs -{ - /// - /// Interaction logic for ApplicationLogItemView.xaml - /// - public partial class MachineLogItemView : UserControl - { - public MachineLogItemView() - { - InitializeComponent(); - } - } -} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemViewVM.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemViewVM.cs deleted file mode 100644 index 2ac7a7b3a..000000000 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemViewVM.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.Integration.Logging; - -namespace Tango.FSE.Common.Dialogs -{ - public class MachineLogItemViewVM : FSEDialogViewVM - { - public EmbeddedLogItem LogItem { get; set; } - - public MachineLogItemViewVM() - { - CanClose = false; - OKText = "CLOSE"; - HasDefault = true; - } - } -} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/ILoggingProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/ILoggingProvider.cs index d49f8b21d..68c288e60 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/ILoggingProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/ILoggingProvider.cs @@ -1,10 +1,13 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; +using Tango.FSE.Common.FileSystem; using Tango.Integration.Logging; using Tango.Logging; +using Tango.PPC.Shared.Logs; namespace Tango.FSE.Common.Logging { @@ -13,14 +16,44 @@ namespace Tango.FSE.Common.Logging /// public interface ILoggingProvider { + /// + /// Gets the last retrieved history of the application log files. + /// + ObservableCollection ApplicationLogFiles { get; } + + /// + /// Gets the last retrieved history of the embedded firmware log files. + /// + ObservableCollection FirmwareLogFiles { get; } + + /// + /// Gets the history of application log files. + /// + /// + Task> GetApplicationLogFiles(); + + /// + /// Gets the history of the embedded firmware log files. + /// + /// + Task> GetFirmwareLogFiles(); + + /// + /// Downloads the specified remote log file. + /// + /// The log file. + /// Target folder. + /// + Task DownloadLogFile(RemoteLogFile logFile, String targetFolder); + /// /// Occurs when a new PPC application log is available. /// event EventHandler ApplicationLogAvailable; /// - /// Occurs when a new embedded log is available. + /// Occurs when a new embedded firmware log is available. /// - event EventHandler EmbeddedLogAvailable; + event EventHandler FirmwareLogAvailable; } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/RemoteLogFileModel.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/RemoteLogFileModel.cs new file mode 100644 index 000000000..cf71ed270 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/RemoteLogFileModel.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using Tango.Core; +using Tango.Core.Commands; +using Tango.Core.DI; +using Tango.FSE.Common.FileSystem; +using Tango.Logging; +using Tango.PPC.Shared.Logs; +using Tango.SharedUI.Components; + +namespace Tango.FSE.Common.Logging +{ + /// + /// Represents a remote log file model. + /// + /// + /// + public class RemoteLogFileModel : ExtendedObject where T : LogItemBase + { + private ILogFileParser _parser; + + /// + /// Occurs when the remote log file has downloaded successfully. + /// + public event EventHandler DownloadCompleted; + + [TangoInject] + private ILoggingProvider LoggingProvider { get; set; } + + /// + /// Gets or sets the remote log file. + /// + public RemoteLogFile RemoteLogFile { get; set; } + + /// + /// Gets the duration of the remote log file. + /// + public TimeSpan Duration + { + get { return RemoteLogFile.DateModified - RemoteLogFile.DateCreated; } + } + + private RemoteLogFileStatus _status; + /// + /// Gets or sets the remote log file status. + /// + public RemoteLogFileStatus Status + { + get { return _status; } + set { _status = value; RaisePropertyChangedAuto(); } + } + + private FileSystemHandler _handler; + /// + /// Gets or sets the remote log file download handler. + /// + public FileSystemHandler Handler + { + get { return _handler; } + set { _handler = value; RaisePropertyChangedAuto(); } + } + + /// + /// Gets or sets the temporary file (where the actual log file is stored locally). + /// + public String TemporaryFile { get; set; } + + private ObservableCollection _logItems; + /// + /// Gets or sets the log items. + /// + public ObservableCollection LogItems + { + get { return _logItems; } + set { _logItems = value; RaisePropertyChangedAuto(); } + } + + /// + /// Gets or sets the download command. + /// + public RelayCommand DownloadCommand { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The parser. + public RemoteLogFileModel(ILogFileParser parser) + { + TangoIOC.Default.Inject(this); + _parser = parser; + LogItems = new ObservableCollection(); + DownloadCommand = new RelayCommand(DownloadLogFile); + } + + /// + /// Downloads the log file. + /// + public async void DownloadLogFile() + { + if (Status == RemoteLogFileStatus.None || Status == RemoteLogFileStatus.Failed) + { + Status = RemoteLogFileStatus.Downloading; + String tempLogFile = TemporaryManager.CreateImaginaryFile(".log"); + Handler = await LoggingProvider.DownloadLogFile(RemoteLogFile, tempLogFile); + Handler.StatusChanged += (x, status) => + { + if (status == FileSystemHandlerStatus.Completed) + { + TemporaryFile = tempLogFile; + LogItems = new ObservableCollection(_parser.Parse(tempLogFile, RemoteLogFile.DateCreated.ToLocalTime())); + Status = RemoteLogFileStatus.Downloaded; + DownloadCompleted?.Invoke(this, new EventArgs()); + } + else if (status == FileSystemHandlerStatus.Failed) + { + Status = RemoteLogFileStatus.Failed; + } + }; + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/RemoteLogFileStatus.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/RemoteLogFileStatus.cs new file mode 100644 index 000000000..25f3f4eac --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/RemoteLogFileStatus.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Common.Logging +{ + /// + /// Represents the remote log file statuses. + /// + public enum RemoteLogFileStatus + { + None, + Downloading, + Downloaded, + Failed, + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj index 7134dbcbb..1581bd25b 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj @@ -108,14 +108,14 @@ - - MachineLogItemView.xaml + + FirmwareLogItemView.xaml ApplicationLogItemView.xaml - + @@ -132,6 +132,8 @@ + + @@ -194,7 +196,7 @@ Designer MSBuild:Compile - + MSBuild:Compile Designer diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Connection/DefaultMachineProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Connection/DefaultMachineProvider.cs index 3a43e71f0..4837fd100 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Connection/DefaultMachineProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Connection/DefaultMachineProvider.cs @@ -457,11 +457,12 @@ namespace Tango.FSE.UI.Connection MachineOperator.RequestTimeout = TimeSpan.FromSeconds(5); MachineOperator.ContinuousRequestTimeout = TimeSpan.FromSeconds(5); - if (MachineOperator is ExternalBridgeTcpClient) + if (ConnectionType.IsRemote()) { - ExternalBridgeTcpClient tcpClient = MachineOperator as ExternalBridgeTcpClient; + ExternalBridgeTcpClient tcpClient = MachineOperator.As(); tcpClient.EnableApplicationLogs = true; tcpClient.InjectApplicationLogsToDefaultLogManager = false; + tcpClient.LogEmbeddedDebuggingToFile = false; } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Logging/DefaultLoggingProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Logging/DefaultLoggingProvider.cs index b3a2d4051..4570589b6 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Logging/DefaultLoggingProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Logging/DefaultLoggingProvider.cs @@ -1,13 +1,19 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using Tango.Core; +using Tango.FileSystem; using Tango.FSE.Common.Connection; +using Tango.FSE.Common.FileSystem; using Tango.FSE.Common.Logging; using Tango.Integration.ExternalBridge; using Tango.Integration.Logging; using Tango.Logging; +using Tango.PPC.Shared.Logs; namespace Tango.FSE.UI.Logging { @@ -15,8 +21,11 @@ namespace Tango.FSE.UI.Logging /// Represents the default implementation. /// /// - public class DefaultLoggingProvider : ILoggingProvider + public class DefaultLoggingProvider : ExtendedObject, ILoggingProvider { + private IFileSystemProvider _fileSystemProvider; + private IMachineProvider _machineProvider; + /// /// Occurs when a new PPC application log is available. /// @@ -25,14 +34,30 @@ namespace Tango.FSE.UI.Logging /// /// Occurs when a new embedded log is available. /// - public event EventHandler EmbeddedLogAvailable; + public event EventHandler FirmwareLogAvailable; + + /// + /// Gets the last retrieved history of the application log files. + /// + public ObservableCollection ApplicationLogFiles { get; private set; } + + /// + /// Gets the last retrieved history of the embedded firmware log files. + /// + public ObservableCollection FirmwareLogFiles { get; private set; } /// /// Initializes a new instance of the class. /// /// The machine provider. - public DefaultLoggingProvider(IMachineProvider machineProvider) + public DefaultLoggingProvider(IMachineProvider machineProvider, IFileSystemProvider fileSystemProvider) { + ApplicationLogFiles = new ObservableCollection(); + FirmwareLogFiles = new ObservableCollection(); + + _machineProvider = machineProvider; + _fileSystemProvider = fileSystemProvider; + if (machineProvider.MachineOperator is ExternalBridgeTcpClient) { (machineProvider.MachineOperator as ExternalBridgeTcpClient).ApplicationLogAvailable += DefaultLoggingProvider_ApplicationLogAvailable; @@ -41,6 +66,62 @@ namespace Tango.FSE.UI.Logging machineProvider.MachineOperator.DebugLogAvailable += MachineOperator_DebugLogAvailable; } + /// + /// Gets the history of application log files. + /// + /// + public async Task> GetApplicationLogFiles() + { + var response = await _machineProvider.MachineOperator.SendGenericRequest(new GetLogFilesRequest() { LogFileType = RemoteLogFileType.Application }); + + ApplicationLogFiles.Clear(); + + foreach (var item in response.LogFiles) + { + ApplicationLogFiles.Add(item); + } + + return response.LogFiles; + } + + /// + /// Gets the history of the embedded firmware log files. + /// + /// + public async Task> GetFirmwareLogFiles() + { + var response = await _machineProvider.MachineOperator.SendGenericRequest(new GetLogFilesRequest() { LogFileType = RemoteLogFileType.Firmware }); + + FirmwareLogFiles.Clear(); + + foreach (var item in response.LogFiles) + { + FirmwareLogFiles.Add(item); + } + + return response.LogFiles; + } + + /// + /// Downloads the specified remote log file. + /// + /// The log file. + /// Target local folder. + /// + public async Task DownloadLogFile(RemoteLogFile logFile, String targetFolder) + { + var tempFolder = TemporaryManager.CreateFolder(); + var handler = await _fileSystemProvider.Download(new FileItem() { Path = logFile.Path }, tempFolder); + handler.StatusChanged += (x, status) => + { + if (status == FileSystemHandlerStatus.Completed) + { + File.Move(Path.Combine(tempFolder, logFile.Name), targetFolder); + } + }; + return handler; + } + private void DefaultLoggingProvider_ApplicationLogAvailable(object sender, LogItemBase log) { ApplicationLogAvailable?.Invoke(this, log); @@ -48,7 +129,7 @@ namespace Tango.FSE.UI.Logging private void MachineOperator_DebugLogAvailable(object sender, PMR.Debugging.StartDebugLogResponse log) { - EmbeddedLogAvailable?.Invoke(this, new EmbeddedLogItem(log) { TimeStamp = DateTime.Now}); + FirmwareLogAvailable?.Invoke(this, new EmbeddedLogItem(log) { TimeStamp = DateTime.Now }); } } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/LogViewerPane.xaml b/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/LogViewerPane.xaml index d3ece6db1..50faea56c 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/LogViewerPane.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/LogViewerPane.xaml @@ -97,14 +97,14 @@ - MACHINE LOGS + FIRMWARE LOGS - - + + - + @@ -125,13 +125,13 @@ - + - + diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/LogViewerPaneVM.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/LogViewerPaneVM.cs index 1a4083f28..cb0ea0229 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/LogViewerPaneVM.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/LogViewerPaneVM.cs @@ -23,7 +23,7 @@ namespace Tango.FSE.UI.Panes public class LogViewerPaneVM : FSEViewModel { private List _pausedApplicationLogs; - private List _pausedMachineLogs; + private List _pausedFirmwareLogs; /// /// Gets or sets the application logs. @@ -31,9 +31,9 @@ namespace Tango.FSE.UI.Panes public ObservableCollection ApplicationLogs { get; set; } /// - /// Gets or sets the machine logs. + /// Gets or sets the firmware logs. /// - public ObservableCollection MachineLogs { get; set; } + public ObservableCollection FirmwareLogs { get; set; } /// /// Gets or sets the application logs view. @@ -41,9 +41,9 @@ namespace Tango.FSE.UI.Panes public ICollectionView ApplicationLogsView { get; set; } /// - /// Gets or sets the machine logs view. + /// Gets or sets the firmware logs view. /// - public ICollectionView MachineLogsView { get; set; } + public ICollectionView FirmwareLogsView { get; set; } /// /// Gets or sets the selected application logs categories. @@ -51,9 +51,9 @@ namespace Tango.FSE.UI.Panes public SelectedObjectCollection SelectedApplicationLogsCategories { get; set; } /// - /// Gets or sets the selected machine logs categories. + /// Gets or sets the selected firmware logs categories. /// - public SelectedObjectCollection SelectedMachineLogsCategories { get; set; } + public SelectedObjectCollection SelectedFirmwareLogsCategories { get; set; } /// /// Gets or sets a value indicating whether to pause the insertion of application logs. @@ -61,9 +61,9 @@ namespace Tango.FSE.UI.Panes public bool ApplicationLogsPaused { get; set; } /// - /// Gets or sets a value indicating whether to pause the insertion of machine logs. + /// Gets or sets a value indicating whether to pause the insertion of firmware logs. /// - public bool MachineLogsPaused { get; set; } + public bool FirmwareLogsPaused { get; set; } private String _applicationLogsFilter; /// @@ -75,14 +75,14 @@ namespace Tango.FSE.UI.Panes set { _applicationLogsFilter = value; RaisePropertyChangedAuto(); ApplicationLogsView.Refresh(); } } - private String _machineLogsFilter; + private String _firmwareLogsFilter; /// - /// Gets or sets the machine logs filter. + /// Gets or sets the firmware logs filter. /// - public String MachineLogsFilter + public String FirmwareLogsFilter { - get { return _machineLogsFilter; } - set { _machineLogsFilter = value; RaisePropertyChangedAuto(); MachineLogsView.Refresh(); } + get { return _firmwareLogsFilter; } + set { _firmwareLogsFilter = value; RaisePropertyChangedAuto(); FirmwareLogsView.Refresh(); } } /// @@ -91,9 +91,9 @@ namespace Tango.FSE.UI.Panes public RelayCommand ClearApplicationLogsCommand { get; set; } /// - /// Clears the machine logs. + /// Clears the firmware logs. /// - public RelayCommand ClearMachineLogsCommand { get; set; } + public RelayCommand ClearFirmwareLogsCommand { get; set; } /// /// Opens the detailed application log dialog. @@ -101,9 +101,9 @@ namespace Tango.FSE.UI.Panes public RelayCommand OpenApplicationLogItemCommand { get; set; } /// - /// Opens the detailed machine log dialog. + /// Opens the detailed firmware log dialog. /// - public RelayCommand OpenMachineLogItemCommand { get; set; } + public RelayCommand OpenFirmareLogItemCommand { get; set; } /// /// Initializes a new instance of the class. @@ -111,15 +111,15 @@ namespace Tango.FSE.UI.Panes public LogViewerPaneVM() { _pausedApplicationLogs = new List(); - _pausedMachineLogs = new List(); + _pausedFirmwareLogs = new List(); ApplicationLogs = new ObservableCollection(); - MachineLogs = new ObservableCollection(); + FirmwareLogs = new ObservableCollection(); ApplicationLogsView = CollectionViewSource.GetDefaultView(ApplicationLogs); - MachineLogsView = CollectionViewSource.GetDefaultView(MachineLogs); + FirmwareLogsView = CollectionViewSource.GetDefaultView(FirmwareLogs); ApplicationLogsView.Filter = FilterApplicationLogs; - MachineLogsView.Filter = FilterMachineLogs; + FirmwareLogsView.Filter = FilterFirmwareLogs; SelectedApplicationLogsCategories = new SelectedObjectCollection(new ObservableCollection() { @@ -135,7 +135,7 @@ namespace Tango.FSE.UI.Panes LogCategory.Critical, }); - SelectedMachineLogsCategories = new SelectedObjectCollection(new ObservableCollection() + SelectedFirmwareLogsCategories = new SelectedObjectCollection(new ObservableCollection() { LogCategory.Info, LogCategory.Warning, @@ -152,18 +152,18 @@ namespace Tango.FSE.UI.Panes }); SelectedApplicationLogsCategories.SynchedSource.CollectionChanged += (_, __) => ApplicationLogsView.Refresh(); - SelectedMachineLogsCategories.SynchedSource.CollectionChanged += (_, __) => MachineLogsView.Refresh(); + SelectedFirmwareLogsCategories.SynchedSource.CollectionChanged += (_, __) => FirmwareLogsView.Refresh(); ClearApplicationLogsCommand = new RelayCommand(ClearApplicationLogs); - ClearMachineLogsCommand = new RelayCommand(ClearMachineLogs); + ClearFirmwareLogsCommand = new RelayCommand(ClearFirmwareLogs); TangoIOC.Default.Inject(this); LoggingProvider.ApplicationLogAvailable += LoggingProvider_ApplicationLogAvailable; - LoggingProvider.EmbeddedLogAvailable += LoggingProvider_EmbeddedLogAvailable; + LoggingProvider.FirmwareLogAvailable += LoggingProvider_FirmwareLogAvailable; OpenApplicationLogItemCommand = new RelayCommand(OpenApplicationLogItem); - OpenMachineLogItemCommand = new RelayCommand(OpenMachineLogItem); + OpenFirmareLogItemCommand = new RelayCommand(OpenFirmwareLogItem); } private async void OpenApplicationLogItem(LogItemBase logItem) @@ -171,9 +171,9 @@ namespace Tango.FSE.UI.Panes await NotificationProvider.ShowDialog(new ApplicationLogItemViewVM() { LogItem = logItem }); } - private async void OpenMachineLogItem(EmbeddedLogItem logItem) + private async void OpenFirmwareLogItem(EmbeddedLogItem logItem) { - await NotificationProvider.ShowDialog(new MachineLogItemViewVM() { LogItem = logItem }); + await NotificationProvider.ShowDialog(new FirmwareLogItemViewVM() { LogItem = logItem }); } private bool FilterApplicationLogs(object obj) @@ -182,10 +182,10 @@ namespace Tango.FSE.UI.Panes return SelectedApplicationLogsCategories.SynchedSource.Contains(log.Category) && (String.IsNullOrWhiteSpace(ApplicationLogsFilter) || log.Message.ToLower().Contains(ApplicationLogsFilter.ToLower())); } - private bool FilterMachineLogs(object obj) + private bool FilterFirmwareLogs(object obj) { var log = obj as EmbeddedLogItem; - return SelectedMachineLogsCategories.SynchedSource.Contains(log.Category) && (String.IsNullOrWhiteSpace(MachineLogsFilter) || log.Message.ToLower().Contains(MachineLogsFilter.ToLower())); + return SelectedFirmwareLogsCategories.SynchedSource.Contains(log.Category) && (String.IsNullOrWhiteSpace(FirmwareLogsFilter) || log.Message.ToLower().Contains(FirmwareLogsFilter.ToLower())); } private void ClearApplicationLogs() @@ -194,10 +194,10 @@ namespace Tango.FSE.UI.Panes ApplicationLogs.Clear(); } - private void ClearMachineLogs() + private void ClearFirmwareLogs() { - _pausedMachineLogs.Clear(); - MachineLogs.Clear(); + _pausedFirmwareLogs.Clear(); + FirmwareLogs.Clear(); } private void LoggingProvider_ApplicationLogAvailable(object sender, LogItemBase logItem) @@ -225,27 +225,27 @@ namespace Tango.FSE.UI.Panes } } - private void LoggingProvider_EmbeddedLogAvailable(object sender, EmbeddedLogItem logItem) + private void LoggingProvider_FirmwareLogAvailable(object sender, EmbeddedLogItem logItem) { - if (MachineLogsPaused) + if (FirmwareLogsPaused) { - _pausedMachineLogs.Add(logItem); + _pausedFirmwareLogs.Add(logItem); } else { InvokeUI(() => { - if (_pausedMachineLogs.Count > 0) + if (_pausedFirmwareLogs.Count > 0) { - foreach (var pausedItem in _pausedMachineLogs) + foreach (var pausedItem in _pausedFirmwareLogs) { - MachineLogs.Insert(0, pausedItem); + FirmwareLogs.Insert(0, pausedItem); } - _pausedMachineLogs.Clear(); + _pausedFirmwareLogs.Clear(); } - MachineLogs.Insert(0, logItem); + FirmwareLogs.Insert(0, logItem); }); } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs index 5d5463d1b..f89c2010f 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs @@ -93,8 +93,8 @@ namespace Tango.FSE.UI TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); - TangoIOC.Default.Register(); TangoIOC.Default.Register(); + TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs index 02975a2b3..86506abcf 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs @@ -11,7 +11,10 @@ using Tango.Core.IO; using Tango.FileSystem; using Tango.FileSystem.Network; using Tango.Integration.ExternalBridge; +using Tango.Integration.Operation; +using Tango.Logging; using Tango.PPC.Common.ExternalBridge; +using Tango.PPC.Shared.Logs; using Tango.Transport; using Tango.Transport.Transporters; using Tango.WebRTC; @@ -360,6 +363,49 @@ namespace Tango.PPC.Common.FileSystem await receiver.SendGenericResponse(new PerformDiskSpaceOptimizationResponse() { DeletedBytes = deletedBytes }, token); } + [ExternalBridgeRequestHandlerMethod(typeof(GetLogFilesRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnGetLogFilesRequest(GetLogFilesRequest request, String token, ExternalBridgeReceiver receiver) + { + FolderItem folder = null; + + if (request.LogFileType == RemoteLogFileType.Application) + { + var fileLogger = LogManager.RegisteredLoggers.SingleOrDefault(x => x.GetType() == typeof(FileLogger)) as FileLogger; + + if (fileLogger == null) + { + throw new InvalidOperationException("Could not locate the application file logger."); + } + + folder = await _manager.GetFolder(fileLogger.Folder, false, "*.log") as FolderItem; + } + else + { + if (MachineOperator.EmbeddedLogsFolder == null) + { + throw new InvalidOperationException("The firmware file logger folder could not be read."); + } + + folder = await _manager.GetFolder(MachineOperator.EmbeddedLogsFolder, false, "*.log") as FolderItem; + } + + GetLogFilesResponse response = new GetLogFilesResponse(); + + foreach (var file in folder.Items.OfType().OrderByDescending(x => x.DateCreated).DistinctBy(x => x.Name)) + { + response.LogFiles.Add(new RemoteLogFile() + { + DateModified = file.DateModified, + DateCreated = file.DateCreated, + Name = file.Name, + Path = file.Path, + Length = new FileInfo(file.Path).Length + }); + } + + await receiver.SendGenericResponse(response, token); + } + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) { if (_webRtcClients.ContainsKey(receiver)) diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesRequest.cs new file mode 100644 index 000000000..bb5d21837 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesRequest.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Logs +{ + public class GetLogFilesRequest + { + public RemoteLogFileType LogFileType { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesResponse.cs new file mode 100644 index 000000000..cf5d59726 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesResponse.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Logs +{ + public class GetLogFilesResponse + { + public List LogFiles { get; set; } + + public GetLogFilesResponse() + { + LogFiles = new List(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFile.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFile.cs new file mode 100644 index 000000000..fc2ba88c4 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFile.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Logs +{ + public class RemoteLogFile + { + public String Name { get; set; } + public DateTime DateModified { get; set; } + public DateTime DateCreated { get; set; } + public String Path { get; set; } + public long Length { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFileType.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFileType.cs new file mode 100644 index 000000000..958b4c195 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFileType.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Logs +{ + public enum RemoteLogFileType + { + Application, + Firmware + } +} 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 2ae1c7575..96c18129a 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 @@ -60,6 +60,10 @@ + + + + diff --git a/Software/Visual_Studio/Tango.FileSystem/FileSystemItem.cs b/Software/Visual_Studio/Tango.FileSystem/FileSystemItem.cs index c8b2fce32..558251f3c 100644 --- a/Software/Visual_Studio/Tango.FileSystem/FileSystemItem.cs +++ b/Software/Visual_Studio/Tango.FileSystem/FileSystemItem.cs @@ -25,6 +25,8 @@ namespace Tango.FileSystem public DateTime DateModified { get; set; } + public DateTime DateCreated { get; set; } + public long Size { get; set; } public String Name @@ -75,6 +77,7 @@ namespace Tango.FileSystem } item.DateModified = dto.DateModified; + item.DateCreated = dto.DateCreated; item.Path = dto.Path; item.Size = dto.Size; item.Type = dto.Type; diff --git a/Software/Visual_Studio/Tango.FileSystem/FileSystemManager.cs b/Software/Visual_Studio/Tango.FileSystem/FileSystemManager.cs index c08304ca8..dc8efa7dd 100644 --- a/Software/Visual_Studio/Tango.FileSystem/FileSystemManager.cs +++ b/Software/Visual_Studio/Tango.FileSystem/FileSystemManager.cs @@ -71,6 +71,7 @@ namespace Tango.FileSystem Path = directory, Type = FileSystemItemType.Folder, DateModified = Directory.GetLastWriteTimeUtc(directory), + DateCreated = Directory.GetCreationTimeUtc(directory), }); } @@ -83,6 +84,7 @@ namespace Tango.FileSystem Path = file, Type = FileSystemItemType.File, DateModified = File.GetLastWriteTimeUtc(file), + DateCreated = File.GetCreationTimeUtc(file), Size = new FileInfo(file).Length }); } diff --git a/Software/Visual_Studio/Tango.FileSystem/Network/FileSystemItemDTO.cs b/Software/Visual_Studio/Tango.FileSystem/Network/FileSystemItemDTO.cs index 900ba0628..43467f227 100644 --- a/Software/Visual_Studio/Tango.FileSystem/Network/FileSystemItemDTO.cs +++ b/Software/Visual_Studio/Tango.FileSystem/Network/FileSystemItemDTO.cs @@ -19,6 +19,8 @@ namespace Tango.FileSystem.Network public DateTime DateModified { get; set; } + public DateTime DateCreated { get; set; } + public long Size { get; set; } public bool IsRoot { get; set; } diff --git a/Software/Visual_Studio/Tango.Integration/Logging/EmbeddedLogFileParser.cs b/Software/Visual_Studio/Tango.Integration/Logging/EmbeddedLogFileParser.cs index 72e55bbfd..bfe1cebcc 100644 --- a/Software/Visual_Studio/Tango.Integration/Logging/EmbeddedLogFileParser.cs +++ b/Software/Visual_Studio/Tango.Integration/Logging/EmbeddedLogFileParser.cs @@ -115,5 +115,12 @@ namespace Tango.Integration.Logging } } } + + public List Parse(string file, DateTime fileDate) + { + List logs = new List(); + Parse(file, fileDate, ref logs); + return logs; + } } } diff --git a/Software/Visual_Studio/Tango.Logging/ApplicationLogFileParser.cs b/Software/Visual_Studio/Tango.Logging/ApplicationLogFileParser.cs index 85f82d04e..1530c4d27 100644 --- a/Software/Visual_Studio/Tango.Logging/ApplicationLogFileParser.cs +++ b/Software/Visual_Studio/Tango.Logging/ApplicationLogFileParser.cs @@ -75,6 +75,13 @@ namespace Tango.Logging return logItems; } + public List Parse(String file, DateTime fileDate) + { + List logs = new List(); + Parse(file, fileDate, ref logs); + return logs; + } + private void Parse(string file, DateTime datetime, ref List logItems) { String text = File.ReadAllText(file); diff --git a/Software/Visual_Studio/Tango.Logging/ILogFileParser.cs b/Software/Visual_Studio/Tango.Logging/ILogFileParser.cs index bc43c7cd0..64b4c7206 100644 --- a/Software/Visual_Studio/Tango.Logging/ILogFileParser.cs +++ b/Software/Visual_Studio/Tango.Logging/ILogFileParser.cs @@ -10,6 +10,8 @@ namespace Tango.Logging { List Parse(LogFile logFile); + List Parse(String file, DateTime fileDate); + List GetLogFiles(); } } diff --git a/Software/Visual_Studio/Tango.Logging/LogFile.cs b/Software/Visual_Studio/Tango.Logging/LogFile.cs index c86ec1792..f727b96f4 100644 --- a/Software/Visual_Studio/Tango.Logging/LogFile.cs +++ b/Software/Visual_Studio/Tango.Logging/LogFile.cs @@ -28,7 +28,6 @@ namespace Tango.Logging /// public bool PartOfSet { get; set; } - /// /// Gets or sets the start index of the set. /// diff --git a/Software/Visual_Studio/Tango.Logging/LogItemBase.cs b/Software/Visual_Studio/Tango.Logging/LogItemBase.cs index f89b73b40..01d520f6a 100644 --- a/Software/Visual_Studio/Tango.Logging/LogItemBase.cs +++ b/Software/Visual_Studio/Tango.Logging/LogItemBase.cs @@ -46,6 +46,14 @@ namespace Tango.Logging get { return GetRelativeCallerFilePath(); } } + /// + /// Gets the name of the caller file class. + /// + public String ClassName + { + get { return RelativeCallerFile.Split('\\').LastOrDefault()?.Split('.').FirstOrDefault(); } + } + /// /// Gets or sets the caller line number. /// diff --git a/Software/Visual_Studio/Tango.SharedUI/Components/BindingProxy.cs b/Software/Visual_Studio/Tango.SharedUI/Components/BindingProxy.cs new file mode 100644 index 000000000..e13436900 --- /dev/null +++ b/Software/Visual_Studio/Tango.SharedUI/Components/BindingProxy.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace Tango.SharedUI.Components +{ + public class BindingProxy : Freezable + { + #region Overrides of Freezable + + protected override Freezable CreateInstanceCore() + { + return new BindingProxy(); + } + + #endregion + + public object Data + { + get { return (object)GetValue(DataProperty); } + set { SetValue(DataProperty, value); } + } + + public static readonly DependencyProperty DataProperty = + DependencyProperty.Register("Data", typeof(object), + typeof(BindingProxy)); + } +} diff --git a/Software/Visual_Studio/Tango.SharedUI/Converters/StringToOneLineConverter.cs b/Software/Visual_Studio/Tango.SharedUI/Converters/StringToOneLineConverter.cs index d130ebaaf..e1255ef13 100644 --- a/Software/Visual_Studio/Tango.SharedUI/Converters/StringToOneLineConverter.cs +++ b/Software/Visual_Studio/Tango.SharedUI/Converters/StringToOneLineConverter.cs @@ -15,11 +15,11 @@ namespace Tango.SharedUI.Converters if (value != null) { string str = value.ToString(); - int newLineIndex = str.IndexOf(Environment.NewLine); + int newLineIndex = str.IndexOf("\n"); if (newLineIndex == -1) { - newLineIndex = str.IndexOf("\n"); + newLineIndex = str.IndexOf(Environment.NewLine); } string firstline = str; diff --git a/Software/Visual_Studio/Tango.SharedUI/Tango.SharedUI.csproj b/Software/Visual_Studio/Tango.SharedUI/Tango.SharedUI.csproj index 000a4e5d7..a649d0c1a 100644 --- a/Software/Visual_Studio/Tango.SharedUI/Tango.SharedUI.csproj +++ b/Software/Visual_Studio/Tango.SharedUI/Tango.SharedUI.csproj @@ -67,6 +67,7 @@ + @@ -255,7 +256,7 @@ - + \ No newline at end of file -- 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') 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 From 8f738753289dcb7118162122c5404d2a02b305f7 Mon Sep 17 00:00:00 2001 From: Roy Ben Shabat Date: Tue, 14 Apr 2020 06:23:25 +0300 Subject: FSE Tup/Tfp & WaitForReconnection. --- .../ViewModels/FileSystemViewVM.cs | 13 +- .../FSE/Modules/Tango.FSE.Upgrade/App.xaml | 2 + .../Tango.FSE.Upgrade/Images/flash_drive.png | Bin 0 -> 1005 bytes .../Tango.FSE.Upgrade/Images/upgrade_remotely.png | Bin 0 -> 1514 bytes .../Navigation/RemoteUpgradeNavigationManager.cs | 19 ++ .../Navigation/RemoteUpgradeView.cs | 17 ++ .../Tango.FSE.Upgrade/RemoteUpgradeViewModel.cs | 15 + .../Tango.FSE.Upgrade/Tango.FSE.Upgrade.csproj | 11 + .../Modules/Tango.FSE.Upgrade/Themes/Generic.xaml | 17 ++ .../Modules/Tango.FSE.Upgrade/ViewModelLocator.cs | 3 + .../ApplicationUpgradeGeneratedViewVM.cs | 136 +++++++-- .../ViewModels/ApplicationUpgradeViewVM.cs | 91 +++--- .../ViewModels/FirmwareUpgradeGeneratedViewVM.cs | 227 ++++++++++++++- .../ViewModels/FirmwareUpgradeViewVM.cs | 92 +++--- .../Tango.FSE.Upgrade/ViewModels/MainViewVM.cs | 19 +- .../Tango.FSE.Upgrade/ViewModels/WelcomeViewVM.cs | 41 +-- .../Views/ApplicationUpgradeGeneratedView.xaml | 94 ++++--- .../Views/ApplicationUpgradeView.xaml | 79 +++--- .../Views/FirmwareUpgradeGeneratedView.xaml | 64 ++++- .../Views/FirmwareUpgradeView.xaml | 103 +++---- .../Modules/Tango.FSE.Upgrade/Views/MainView.xaml | 17 +- .../Tango.FSE.Upgrade/Views/MainView.xaml.cs | 3 + .../Tango.FSE.Upgrade/Views/WelcomeView.xaml | 78 +++-- .../Tango.FSE.BL/Services/TangoVersionsService.cs | 85 ++++++ .../Connection/IMachineProvider.cs | 9 + .../FSE/Tango.FSE.Common/Images/arrow_right.png | Bin 0 -> 827 bytes .../IModularNavigationNavigationManager.cs | 18 ++ .../Navigation/ModularNavigationFSEViewModel.cs | 15 + .../Navigation/ModularNavigationManager.cs | 158 +++++++++++ .../RemoteUpgrade/IRemoteUpgradeManager.cs | 7 + .../RemoteUpgrade/RemoteUpgradeHandler.cs | 5 + .../FSE/Tango.FSE.Common/Resources/Images.xaml | 1 + .../FSE/Tango.FSE.Common/Resources/Styles.xaml | 20 ++ .../Tango.FSE.Common/Storage/IStorageProvider.cs | 7 + .../FSE/Tango.FSE.Common/Tango.FSE.Common.csproj | 7 +- .../Visual_Studio/FSE/Tango.FSE.UI/App.xaml.cs | 59 ++-- .../Connection/DefaultMachineProvider.cs | 86 +++++- .../Dialogs/MachineWaitForConnectionView.xaml | 45 +++ .../Dialogs/MachineWaitForConnectionView.xaml.cs | 28 ++ .../Dialogs/MachineWaitForConnectionViewVM.cs | 86 ++++++ .../Tango.FSE.UI/Modules/DefaultFSEModuleLoader.cs | 13 + .../Navigation/DefaultNavigationManager.cs | 1 - .../RemoteUpgrade/DefaultRemoteUpgradeManager.cs | 313 +++++++++++++++++---- .../Tango.FSE.UI/Storage/DefaultStorageProvider.cs | 22 ++ .../FSE/Tango.FSE.UI/Tango.FSE.UI.csproj | 8 + .../StartRemoteApplicationRemoteUpgradeRequest.cs | 15 - .../StartRemoteApplicationRemoteUpgradeResponse.cs | 23 -- .../StartRemoteApplicationUpgradeRequest.cs | 15 + .../StartRemoteApplicationUpgradeResponse.cs | 23 ++ .../StartRemoteFirmwareUpgradeRequest.cs | 13 + .../StartRemoteFirmwareUpgradeResponse.cs | 23 ++ .../PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj | 6 +- .../Tango.PPC.UI/ViewModels/MachineUpdateViewVM.cs | 131 ++++++++- Software/Visual_Studio/Tango.Core/DI/TangoIOC.cs | 14 + .../VersionPackageDescriptorExtensions.cs | 2 +- .../Visual_Studio/Tango.SharedUI/DialogViewVM.cs | 17 ++ 56 files changed, 1931 insertions(+), 485 deletions(-) create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Images/flash_drive.png create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Images/upgrade_remotely.png create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Navigation/RemoteUpgradeNavigationManager.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Navigation/RemoteUpgradeView.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/RemoteUpgradeViewModel.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Themes/Generic.xaml create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Images/arrow_right.png create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/IModularNavigationNavigationManager.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/ModularNavigationFSEViewModel.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/ModularNavigationManager.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.UI/Dialogs/MachineWaitForConnectionView.xaml create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.UI/Dialogs/MachineWaitForConnectionView.xaml.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.UI/Dialogs/MachineWaitForConnectionViewVM.cs delete mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationRemoteUpgradeRequest.cs delete mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationRemoteUpgradeResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationUpgradeRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationUpgradeResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteFirmwareUpgradeRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteFirmwareUpgradeResponse.cs (limited to 'Software/Visual_Studio/PPC') diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/FileSystemViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/FileSystemViewVM.cs index 6dea5c146..4ed6629b5 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/FileSystemViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/FileSystemViewVM.cs @@ -377,20 +377,9 @@ namespace Tango.FSE.PPCConsole.ViewModels private async void OpenFileSystemHandlerDestination(FileSystemHandler handler) { - String destination = String.Empty; - if (handler.Type == FileSystemHandlerType.FileDownload || handler.Type == FileSystemHandlerType.FolderDownload) { - if (File.Exists(handler.Destination) || Directory.Exists(handler.Destination)) - { - destination = handler.Destination; - Process.Start("explorer.exe", string.Format("/select,\"{0}\"", destination)); - } - else - { - destination = Path.GetDirectoryName(handler.Destination); - Process.Start("explorer.exe", destination); - } + await StorageProvider.ShowInExplorer(handler.Destination); } else { diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/App.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/App.xaml index 4a079ca2b..82b6fac3a 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/App.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/App.xaml @@ -10,6 +10,8 @@ + + diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Images/flash_drive.png b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Images/flash_drive.png new file mode 100644 index 000000000..af5e22a3c Binary files /dev/null and b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Images/flash_drive.png differ diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Images/upgrade_remotely.png b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Images/upgrade_remotely.png new file mode 100644 index 000000000..1b60afb24 Binary files /dev/null and b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Images/upgrade_remotely.png differ diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Navigation/RemoteUpgradeNavigationManager.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Navigation/RemoteUpgradeNavigationManager.cs new file mode 100644 index 000000000..7fccff816 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Navigation/RemoteUpgradeNavigationManager.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.FSE.Common.Navigation; +using Tango.FSE.Upgrade.Views; +using Tango.SharedUI.Controls; + +namespace Tango.FSE.Upgrade.Navigation +{ + public class RemoteUpgradeNavigationManager : ModularNavigationManager + { + public RemoteUpgradeNavigationManager(FrameworkElement navigationControlParent) : base(navigationControlParent) + { + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Navigation/RemoteUpgradeView.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Navigation/RemoteUpgradeView.cs new file mode 100644 index 000000000..059d717f5 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Navigation/RemoteUpgradeView.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Upgrade.Navigation +{ + public enum RemoteUpgradeView + { + WelcomeView, + ApplicationUpgradeView, + ApplicationUpgradeGeneratedView, + FirmwareUpgradeView, + FirmwareUpgradeGeneratedView + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/RemoteUpgradeViewModel.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/RemoteUpgradeViewModel.cs new file mode 100644 index 000000000..074fc5f87 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/RemoteUpgradeViewModel.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.FSE.Common.Navigation; +using Tango.FSE.Upgrade.Navigation; + +namespace Tango.FSE.Upgrade +{ + public class RemoteUpgradeViewModel : ModularNavigationFSEViewModel + { + + } +} 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 fd8b99820..a3acc4b19 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 @@ -78,6 +78,9 @@ + + + @@ -181,6 +184,10 @@ MSBuild:Compile Designer + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -226,6 +233,10 @@ + + + + diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Themes/Generic.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Themes/Generic.xaml new file mode 100644 index 000000000..0bf1f9ffc --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Themes/Generic.xaml @@ -0,0 +1,17 @@ + + + + + \ No newline at end of file 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 1c6999c6d..1ccb2330c 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModelLocator.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModelLocator.cs @@ -4,7 +4,9 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.Core.DI; +using Tango.FSE.Upgrade.Navigation; using Tango.FSE.Upgrade.ViewModels; +using Tango.FSE.Upgrade.Views; namespace Tango.FSE.Upgrade { @@ -12,6 +14,7 @@ namespace Tango.FSE.Upgrade { static ViewModelLocator() { + TangoIOC.Default.Register(new RemoteUpgradeNavigationManager(MainView.Instance)); TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); 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 index f5dbb7270..093937228 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/ApplicationUpgradeGeneratedViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/ApplicationUpgradeGeneratedViewVM.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.BL.Entities; using Tango.Core.Commands; +using Tango.Core.IO; using Tango.FSE.Common; using Tango.FSE.Common.Navigation; using Tango.FSE.Common.RemoteUpgrade; @@ -13,20 +15,28 @@ using static Tango.FSE.Upgrade.ViewModels.ApplicationUpgradeGeneratedViewVM; namespace Tango.FSE.Upgrade.ViewModels { - public class ApplicationUpgradeGeneratedViewVM : FSEViewModel, INavigationObjectReceiver + public class ApplicationUpgradeGeneratedViewVM : RemoteUpgradeViewModel, INavigationObjectReceiver { public class NavigationObject { + public TangoVersion SelectedVersion { get; set; } public Machine SelectedMachine { get; set; } public bool UpgradeNow { get; set; } - public String TupFileLocation { get; set; } + public TemporaryFile TemporaryTupFile { get; set; } } private String _tupFileLocation; public String TupFileLocation { get { return _tupFileLocation; } - set { _tupFileLocation = value; RaisePropertyChangedAuto(); } + set { _tupFileLocation = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private TemporaryFile _temporaryTupFile; + public TemporaryFile TemporaryTupFile + { + get { return _temporaryTupFile; } + set { _temporaryTupFile = value; InvalidateRelayCommands(); } } private bool _canUpgradeNow; @@ -50,6 +60,20 @@ namespace Tango.FSE.Upgrade.ViewModels set { _isUpgradeNow = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } } + private bool _isUpgradeNowSelected; + public bool IsUpgradeNowSelected + { + get { return _isUpgradeNowSelected; } + set { _isUpgradeNowSelected = value; RaisePropertyChangedAuto(); } + } + + private TangoVersion _selectedVersion; + public TangoVersion SelectedVersion + { + get { return _selectedVersion; } + set { _selectedVersion = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + private Machine _selectedMachine; public Machine SelectedMachine { @@ -64,14 +88,23 @@ namespace Tango.FSE.Upgrade.ViewModels set { _handler = value; RaisePropertyChangedAuto(); } } + private bool _isCompleted; + public bool IsCompleted + { + get { return _isCompleted; } + set { _isCompleted = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + public RelayCommand StartUpgradeCommand { get; set; } - public RelayCommand ShowPackageInExplorerCommand { get; set; } + public RelayCommand SaveTupFileCommand { get; set; } + public RelayCommand SelectTupFileLocationCommand { get; set; } public ApplicationUpgradeGeneratedViewVM() { Handler = new RemoteUpgradeHandler(null) { Message = "Ready" }; StartUpgradeCommand = new RelayCommand(StartUpgrade, () => CanUpgradeNow && Handler.Status != RemoteUpgradeHandlerStatus.Completed); - ShowPackageInExplorerCommand = new RelayCommand(ShowPackageInExplorer); + SaveTupFileCommand = new RelayCommand(SaveTupFile, () => TupFileLocation != null); + SelectTupFileLocationCommand = new RelayCommand(SelectTupFileLocation, () => SelectedVersion != null && SelectedMachine != null); } public override void OnApplicationStarted() @@ -81,15 +114,26 @@ namespace Tango.FSE.Upgrade.ViewModels MachineProvider.MachineDisconnected += (_, __) => InvalidateCanUpgradeNow(); } + private async void SelectTupFileLocation() + { + String fileName = $"{SelectedMachine.SerialNumber}_Update_{DateTime.Now.Date.ToFileName()}_v{SelectedVersion.Version}.tup"; + var result = await StorageProvider.SaveFile("Select update package location", "Tango Update Package|*.tup", fileName, ".tup"); + if (result) + { + TupFileLocation = result.SelectedItem; + } + } + private void InvalidateCanUpgradeNow() { CanUpgradeNowError = null; - if (!IsUpgradeNow) return; + if (!IsUpgradeNowSelected) return; if (SelectedMachine == null) { CanUpgradeNow = false; + IsUpgradeNowSelected = false; CanUpgradeNowError = "Target machine not specified."; return; } @@ -97,6 +141,7 @@ namespace Tango.FSE.Upgrade.ViewModels if (!MachineProvider.IsConnected) { CanUpgradeNow = false; + IsUpgradeNowSelected = false; CanUpgradeNowError = "The selected machine is not currently connected."; return; } @@ -104,6 +149,7 @@ namespace Tango.FSE.Upgrade.ViewModels if (MachineProvider.Machine.Guid != SelectedMachine.Guid) { CanUpgradeNow = false; + IsUpgradeNowSelected = false; CanUpgradeNowError = "The selected machine is different from the one currently connected."; return; } @@ -111,6 +157,7 @@ namespace Tango.FSE.Upgrade.ViewModels if (!MachineProvider.ConnectionType.IsRemote()) { CanUpgradeNow = false; + IsUpgradeNowSelected = false; CanUpgradeNowError = "The current machine connection type does not support remote upgrade."; return; } @@ -123,16 +170,10 @@ namespace Tango.FSE.Upgrade.ViewModels try { IsFree = false; - Handler = await RemoteUpgradeManager.PerformRemoteApplicationUpgrade(TupFileLocation); + Handler = await RemoteUpgradeManager.PerformRemoteApplicationUpgrade(TemporaryTupFile); await Handler.WaitForCompletion(); - await Task.Delay(5000); - InvalidateRelayCommands(); - await NotificationProvider.ShowSuccess("Remote upgrade completed successfully!"); - - if (IsVisible) - { - await NavigationManager.NavigateTo(nameof(WelcomeView), false); - } + IsCompleted = true; + await MachineProvider.DisconnectAndWaitForReconnection(TimeSpan.FromSeconds(20), TimeSpan.FromMinutes(1)); } catch (OperationCanceledException) { @@ -140,43 +181,78 @@ namespace Tango.FSE.Upgrade.ViewModels } 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()}"); + LogManager.Log(ex, "Error occurred while executing remote application upgrade."); } finally { + await TemporaryTupFile.DeleteAsync(); IsFree = true; + InvalidateRelayCommands(); } } - private void ShowPackageInExplorer() + private async void SaveTupFile() { - throw new NotImplementedException(); + try + { + File.Copy(TemporaryTupFile, TupFileLocation, true); + TemporaryTupFile.Delete(); + IsCompleted = true; + await NotificationProvider.ShowSuccess("Application upgrade package saved successfully."); + await ModularNavigationManager.NavigateBack(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error copying temporary tup file to selected location."); + await NotificationProvider.ShowError($"Error occurred while trying to save the application package file.\n{ex.FlattenMessage()}"); + } } public void OnNavigatedToWithObject(NavigationObject obj) { + SelectedVersion = obj.SelectedVersion; SelectedMachine = obj.SelectedMachine; IsUpgradeNow = obj.UpgradeNow; - TupFileLocation = obj.TupFileLocation; + IsUpgradeNowSelected = IsUpgradeNow; + TemporaryTupFile = obj.TemporaryTupFile; InvalidateCanUpgradeNow(); + InvalidateRelayCommands(); } - public override Task OnNavigateBackRequest() + public override void OnBeforeNavigatedTo() { - if (IsFree) - { - return base.OnNavigateBackRequest(); - } - else + base.OnBeforeNavigatedTo(); + Handler = new RemoteUpgradeHandler(null) { Message = "Ready" }; + IsCompleted = false; + SelectedVersion = null; + SelectedMachine = null; + IsUpgradeNow = false; + IsUpgradeNowSelected = false; + TemporaryTupFile = null; + InvalidateCanUpgradeNow(); + InvalidateRelayCommands(); + } + + public async override Task OnNavigateBackRequest() + { + if (!IsCompleted) { - Task.Delay(100).ContinueWith((x) => + var abort = await NotificationProvider.ShowWarningQuestion("Are you sure you want to abort the upgrade operation?"); + + if (Handler.CanAbort) + { + Handler.Abort(); + } + else { - NavigationManager.NavigateTo(NavigationView.Home); - }, TaskScheduler.FromCurrentSynchronizationContext()); + await NotificationProvider.ShowWarning("Cannot abort the operation at this stage."); + return false; + } - return Task.FromResult(false); + return abort; } + + return true; } } } 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 f7dae41e7..acad83d25 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 @@ -13,7 +13,7 @@ using Tango.FSE.Upgrade.Views; namespace Tango.FSE.Upgrade.ViewModels { - public class ApplicationUpgradeViewVM : FSEViewModel, INavigationObjectReceiver + public class ApplicationUpgradeViewVM : RemoteUpgradeViewModel, INavigationObjectReceiver { public enum ApplicationUpgradeMode { @@ -48,13 +48,6 @@ namespace Tango.FSE.Upgrade.ViewModels set { _selectedVersion = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } } - private String _tupFileLocation; - public String TupFileLocation - { - get { return _tupFileLocation; } - set { _tupFileLocation = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } - } - private Machine _selectedMachine; public Machine SelectedMachine { @@ -69,25 +62,11 @@ namespace Tango.FSE.Upgrade.ViewModels set { _handler = value; RaisePropertyChangedAuto(); } } - public RelayCommand SelectTupFileLocationCommand { get; set; } - public RelayCommand GeneratePackageCommand { get; set; } public ApplicationUpgradeViewVM() { - SelectTupFileLocationCommand = new RelayCommand(SelectTupFileLocation, () => SelectedVersion != null && SelectedMachine != null); - GeneratePackageCommand = new RelayCommand(GeneratePackage, () => SelectedVersion != null && SelectedMachine != null && TupFileLocation != null); - Handler = new RemoteUpgradeHandler(null) { Message = "Ready" }; - } - - private async void SelectTupFileLocation() - { - String fileName = $"{SelectedMachine.SerialNumber}_Update_{DateTime.Now.Date.ToFileName()}_v{SelectedVersion.Version}.tup"; - var result = await StorageProvider.SaveFile("Select update package location", "Tango Update Package|*.tup", fileName, ".tup"); - if (result) - { - TupFileLocation = result.SelectedItem; - } + GeneratePackageCommand = new RelayCommand(GeneratePackage, () => SelectedVersion != null && SelectedMachine != null); } private async void GeneratePackage() @@ -95,19 +74,19 @@ namespace Tango.FSE.Upgrade.ViewModels try { IsFree = false; - //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); + + var temporaryTupFile = TemporaryManager.CreateImaginaryFile(".tup"); + + Handler = await RemoteUpgradeManager.CreateTupFile(SelectedVersion, SelectedMachine.SerialNumber, temporaryTupFile); + await Handler.WaitForCompletion(); + + await ModularNavigationManager.NavigateTo(Navigation.RemoteUpgradeView.ApplicationUpgradeGeneratedView, new ApplicationUpgradeGeneratedViewVM.NavigationObject() + { + SelectedVersion = SelectedVersion, + UpgradeNow = UpgradeMode == ApplicationUpgradeMode.ConnectedMachine, + SelectedMachine = SelectedMachine, + TemporaryTupFile = temporaryTupFile + }, false); } catch (OperationCanceledException) { @@ -115,8 +94,7 @@ namespace Tango.FSE.Upgrade.ViewModels } catch (Exception ex) { - LogManager.Log("Error generating remote upgrade package."); - await NotificationProvider.ShowError($"Error occurred while trying to generate the update package.\n{ex.FlattenMessage()}"); + LogManager.Log(ex, "Error generating remote upgrade package."); } finally { @@ -143,21 +121,29 @@ namespace Tango.FSE.Upgrade.ViewModels } } - public override Task OnNavigateBackRequest() + public async override Task OnNavigateBackRequest() { - if (IsFree) - { - return base.OnNavigateBackRequest(); - } - else + if (!IsFree) { - Task.Delay(100).ContinueWith((x) => + var abort = await NotificationProvider.ShowWarningQuestion("Are you sure you want to abort the upgrade operation?"); + + if (abort) { - NavigationManager.NavigateTo(NavigationView.Home); - }, TaskScheduler.FromCurrentSynchronizationContext()); + if (Handler.CanAbort) + { + Handler.Abort(); + } + else + { + await NotificationProvider.ShowError("Cannot abort the operation at the this stage."); + return false; + } + } - return Task.FromResult(false); + return abort; } + + return true; } public void OnNavigatedToWithObject(NavigationObject obj) @@ -165,5 +151,14 @@ namespace Tango.FSE.Upgrade.ViewModels SelectedMachine = obj.SelectedMachine; UpgradeMode = obj.ApplicationUpgradeMode; } + + public override void OnBeforeNavigatedTo() + { + base.OnBeforeNavigatedTo(); + Handler = new RemoteUpgradeHandler(null) { Message = "Ready" }; + SelectedMachine = null; + UpgradeMode = ApplicationUpgradeMode.OtherMachine; + InvalidateRelayCommands(); + } } } 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 index 3d190aa01..9537eb7d3 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/FirmwareUpgradeGeneratedViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/FirmwareUpgradeGeneratedViewVM.cs @@ -1,13 +1,238 @@ using System; using System.Collections.Generic; +using System.IO; 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 static Tango.FSE.Upgrade.ViewModels.FirmwareUpgradeGeneratedViewVM; namespace Tango.FSE.Upgrade.ViewModels { - public class FirmwareUpgradeGeneratedViewVM : FSEViewModel + public class FirmwareUpgradeGeneratedViewVM : RemoteUpgradeViewModel, INavigationObjectReceiver { + public class NavigationObject + { + public TangoVersion SelectedVersion { get; set; } + public String TfpFileLocation { get; set; } + public bool IsExistingTfpFile { get; set; } + } + + private bool _isUsingExistingTfp; + public bool IsUsingExistingTfp + { + get { return _isUsingExistingTfp; } + set { _isUsingExistingTfp = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private String _tfpFileLocation; + public String TfpFileLocation + { + get { return _tfpFileLocation; } + set { _tfpFileLocation = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private String _tfpFileLocationToSave; + public String TfpFileLocationToSave + { + get { return _tfpFileLocationToSave; } + set { _tfpFileLocationToSave = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private TangoVersion _selectedVersion; + public TangoVersion SelectedVersion + { + get { return _selectedVersion; } + set { _selectedVersion = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + 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 _isUpgradeNowSelected; + public bool IsUpgradeNowSelected + { + get { return _isUpgradeNowSelected; } + set { _isUpgradeNowSelected = value; RaisePropertyChangedAuto(); } + } + + private RemoteUpgradeHandler _handler; + public RemoteUpgradeHandler Handler + { + get { return _handler; } + set { _handler = value; RaisePropertyChangedAuto(); } + } + + private bool _isCompleted; + public bool IsCompleted + { + get { return _isCompleted; } + set { _isCompleted = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + public RelayCommand StartUpgradeCommand { get; set; } + public RelayCommand SaveTfpFileCommand { get; set; } + public RelayCommand SelectTfpFileLocationCommand { get; set; } + + public FirmwareUpgradeGeneratedViewVM() + { + Handler = new RemoteUpgradeHandler(null) { Message = "Ready" }; + StartUpgradeCommand = new RelayCommand(StartUpgrade, () => CanUpgradeNow && Handler.Status != RemoteUpgradeHandlerStatus.Completed); + SaveTfpFileCommand = new RelayCommand(SaveTfpFile, () => TfpFileLocationToSave != null && !IsUsingExistingTfp); + SelectTfpFileLocationCommand = new RelayCommand(SelectTfpFileLocation, () => SelectedVersion != null); + } + + public override void OnApplicationStarted() + { + base.OnApplicationStarted(); + MachineProvider.MachineConnected += (_, __) => InvalidateCanUpgradeNow(); + MachineProvider.MachineDisconnected += (_, __) => InvalidateCanUpgradeNow(); + } + + private void InvalidateCanUpgradeNow() + { + CanUpgradeNowError = null; + + if (!IsUpgradeNowSelected) return; + + if (!MachineProvider.IsConnected) + { + CanUpgradeNow = false; + IsUpgradeNowSelected = false; + CanUpgradeNowError = "No active machine connection detected for remote upgrade."; + return; + } + + if (!MachineProvider.ConnectionType.IsRemote()) + { + CanUpgradeNow = false; + IsUpgradeNowSelected = false; + CanUpgradeNowError = "The current machine connection type does not support remote upgrade."; + return; + } + + CanUpgradeNow = true; + } + + private async void SaveTfpFile() + { + try + { + File.Copy(TfpFileLocation, TfpFileLocationToSave, true); + try + { + File.Delete(TfpFileLocation); + } + catch { } + IsCompleted = true; + await NotificationProvider.ShowSuccess("Firmware upgrade package saved successfully."); + await ModularNavigationManager.NavigateBack(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error copying temporary tfp file to selected location."); + await NotificationProvider.ShowError($"Error occurred while trying to save the firmware package file.\n{ex.FlattenMessage()}"); + } + } + + private async void StartUpgrade() + { + try + { + IsFree = false; + Handler = await RemoteUpgradeManager.PerformRemoteFirmwareUpgrade(TfpFileLocation); + await Handler.WaitForCompletion(); + IsCompleted = true; + await MachineProvider.DisconnectAndWaitForReconnection(TimeSpan.FromSeconds(20), TimeSpan.FromMinutes(1)); + } + catch (OperationCanceledException) + { + //Aborted... + } + catch (Exception ex) + { + LogManager.Log(ex, "Error occurred while executing remote firmware upgrade."); + } + finally + { + if (!IsUsingExistingTfp) + { + try + { + File.Delete(TfpFileLocation); + } + catch { } + } + + IsFree = true; + InvalidateRelayCommands(); + } + } + + private async void SelectTfpFileLocation() + { + String fileName = $"firmware_package_v{SelectedVersion.FirmwareVersion}.tfp"; + var result = await StorageProvider.SaveFile("Select firmware package location", "Tango Firmware Package|*.tfp", fileName, ".tfp"); + if (result) + { + TfpFileLocationToSave = result.SelectedItem; + } + } + + public override void OnBeforeNavigatedTo() + { + base.OnBeforeNavigatedTo(); + Handler = new RemoteUpgradeHandler(null) { Message = "Ready" }; + IsCompleted = false; + SelectedVersion = null; + IsUpgradeNowSelected = true; + TfpFileLocation = null; + InvalidateCanUpgradeNow(); + InvalidateRelayCommands(); + } + + public void OnNavigatedToWithObject(FirmwareUpgradeGeneratedViewVM.NavigationObject obj) + { + SelectedVersion = obj.SelectedVersion; + TfpFileLocation = obj.TfpFileLocation; + IsUsingExistingTfp = obj.IsExistingTfpFile; + } + + public async override Task OnNavigateBackRequest() + { + if (!IsCompleted) + { + var abort = await NotificationProvider.ShowWarningQuestion("Are you sure you want to abort the upgrade operation?"); + + if (Handler.CanAbort) + { + Handler.Abort(); + } + else + { + await NotificationProvider.ShowWarning("Cannot abort the operation at this stage."); + return false; + } + + return abort; + } + + return true; + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/FirmwareUpgradeViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/FirmwareUpgradeViewVM.cs index 0a2d0fdb3..fd07c7f6e 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/FirmwareUpgradeViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/FirmwareUpgradeViewVM.cs @@ -10,7 +10,7 @@ using Tango.FSE.Common.RemoteUpgrade; namespace Tango.FSE.Upgrade.ViewModels { - public class FirmwareUpgradeViewVM : FSEViewModel + public class FirmwareUpgradeViewVM : RemoteUpgradeViewModel { private List _tangoVersions; public List TangoVersions @@ -26,18 +26,18 @@ namespace Tango.FSE.Upgrade.ViewModels set { _selectedVersion = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } } - private String _tfpFileLocation; - public String TfpFileLocation + private bool _useExistingTfpFile; + public bool UseExistingTfpFile { - get { return _tfpFileLocation; } - set { _tfpFileLocation = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + get { return _useExistingTfpFile; } + set { _useExistingTfpFile = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } } private String _existingTfpFileLocation; public String ExistingTfpFileLocation { get { return _existingTfpFileLocation; } - set { _existingTfpFileLocation = value; RaisePropertyChangedAuto(); } + set { _existingTfpFileLocation = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } } private RemoteUpgradeHandler _handler; @@ -47,25 +47,17 @@ namespace Tango.FSE.Upgrade.ViewModels set { _handler = value; RaisePropertyChangedAuto(); } } - private bool _useExistingTfpFile; - public bool UseExistingTfpFile - { - get { return _useExistingTfpFile; } - set { _useExistingTfpFile = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } - } - - public RelayCommand SelectTfpFileLocationCommand { get; set; } - public RelayCommand SelectExistingTfpFileLocationCommand { get; set; } public RelayCommand GeneratePackageCommand { get; set; } + public RelayCommand ContinueCommand { get; set; } + public FirmwareUpgradeViewVM() { - SelectTfpFileLocationCommand = new RelayCommand(SelectTfpFileLocation, () => SelectedVersion != null); SelectExistingTfpFileLocationCommand = new RelayCommand(SelectExistingTfpFileLocation); - GeneratePackageCommand = new RelayCommand(GeneratePackage, () => SelectedVersion != null && (TfpFileLocation != null || (UseExistingTfpFile && ExistingTfpFileLocation != null))); - Handler = new RemoteUpgradeHandler(null) { Message = "Ready" }; + GeneratePackageCommand = new RelayCommand(GeneratePackage, () => SelectedVersion != null); + ContinueCommand = new RelayCommand(ContinueWithExistingTfpFile, () => ExistingTfpFileLocation != null); } public override void OnBeforeNavigatedTo() @@ -76,16 +68,8 @@ namespace Tango.FSE.Upgrade.ViewModels { UseExistingTfpFile = false; } - } - private async void SelectTfpFileLocation() - { - String fileName = $"firmware_package_v{SelectedVersion.FirmwareVersion}.tfp"; - var result = await StorageProvider.SaveFile("Select firmware package location", "Tango Firmware Package|*.tfp", fileName, ".tfp"); - if (result) - { - TfpFileLocation = result.SelectedItem; - } + Handler = new RemoteUpgradeHandler(null) { Message = "Ready" }; } private async void SelectExistingTfpFileLocation() @@ -105,7 +89,7 @@ namespace Tango.FSE.Upgrade.ViewModels { try { - TangoVersions = (await Services.TangoVersionsService.GetAllTangoVersions()).Take(10).ToList(); + TangoVersions = (await Services.TangoVersionsService.GetAllTangoVersions()).DistinctBy(x => x.FirmwareVersion).Take(10).ToList(); SelectedVersion = TangoVersions.FirstOrDefault(); } catch (Exception ex) @@ -118,32 +102,40 @@ namespace Tango.FSE.Upgrade.ViewModels private async void GeneratePackage() { - if (UseExistingTfpFile) + try { - //Navigate to the firmware completion with the existing tfp file. + IsFree = false; + var tempTfpFile = TemporaryManager.CreateImaginaryFile(".tfp"); + Handler = await RemoteUpgradeManager.CreateTfpFile(SelectedVersion, tempTfpFile); + await Handler.WaitForCompletion(); + await ModularNavigationManager.NavigateTo(Navigation.RemoteUpgradeView.FirmwareUpgradeGeneratedView, new FirmwareUpgradeGeneratedViewVM.NavigationObject() + { + IsExistingTfpFile = false, + TfpFileLocation = tempTfpFile, + SelectedVersion = SelectedVersion, + }, false); } - else + catch (OperationCanceledException) { - try - { - IsFree = false; - Handler = await RemoteUpgradeManager.CreateTfpFile(SelectedVersion, TfpFileLocation); - await Handler.WaitForCompletion(); - } - catch (OperationCanceledException) - { - //Aborted... - } - catch (Exception ex) - { - LogManager.Log("Error generating remote firmware upgrade package."); - await NotificationProvider.ShowError($"Error occurred while trying to generate the firmware upgrade package.\n{ex.FlattenMessage()}"); - } - finally - { - IsFree = true; - } + //Aborted... + } + catch (Exception ex) + { + LogManager.Log(ex, "Error generating remote firmware upgrade package."); + } + finally + { + IsFree = true; } } + + private async void ContinueWithExistingTfpFile() + { + await ModularNavigationManager.NavigateTo(Navigation.RemoteUpgradeView.FirmwareUpgradeGeneratedView, new FirmwareUpgradeGeneratedViewVM.NavigationObject() + { + IsExistingTfpFile = true, + TfpFileLocation = ExistingTfpFileLocation, + }, false); + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/MainViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/MainViewVM.cs index fb067f405..e41021b78 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/MainViewVM.cs @@ -6,15 +6,15 @@ using System.Text; using System.Threading.Tasks; using Tango.FSE.Common; using Tango.FSE.Common.Navigation; +using Tango.FSE.Upgrade.Navigation; using Tango.FSE.Upgrade.Views; using Tango.SharedUI.Helpers; namespace Tango.FSE.Upgrade.ViewModels { - [NavigationContainer] - public class MainViewVM : FSEViewModel + public class MainViewVM : RemoteUpgradeViewModel { - public override void OnApplicationStarted() + public override void OnApplicationReady() { InvokeUI(() => { @@ -30,5 +30,18 @@ namespace Tango.FSE.Upgrade.ViewModels }); }); } + + public async override Task OnNavigateBackRequest() + { + if (ModularNavigationManager.CurrentView == RemoteUpgradeView.WelcomeView) + { + return await base.OnNavigateBackRequest(); + } + else + { + await ModularNavigationManager.NavigateBack(); + return false; + } + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/WelcomeViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/WelcomeViewVM.cs index eebe39707..f69257e45 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/WelcomeViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/WelcomeViewVM.cs @@ -11,7 +11,7 @@ using Tango.FSE.Upgrade.Views; namespace Tango.FSE.Upgrade.ViewModels { - public class WelcomeViewVM : FSEViewModel + public class WelcomeViewVM : RemoteUpgradeViewModel { private Machine _selectedMachine; /// @@ -54,40 +54,47 @@ namespace Tango.FSE.Upgrade.ViewModels public WelcomeViewVM() { IsApplicationUpdate = true; - IsUpdateConnectedMachine = false; + IsUpdateConnectedMachine = true; StartUpgradeCommand = new RelayCommand(StartUpgrade, () => !IsApplicationUpdate || IsUpdateConnectedMachine || SelectedMachine != null); } + public override void OnApplicationStarted() + { + base.OnApplicationStarted(); + MachineProvider.MachineConnected += (_, __) => { if (IsVisible) InvalidateIsUpdateConnectedMachine(); }; + MachineProvider.MachineDisconnected += (_, __) => { if (IsVisible) InvalidateIsUpdateConnectedMachine(); }; + } + + private void InvalidateIsUpdateConnectedMachine() + { + if (IsUpdateConnectedMachine) + { + IsUpdateConnectedMachine = MachineProvider.IsConnected && MachineProvider.ConnectionType.IsRemote(); + } + } + /// /// Called before the navigation system has navigated to this VM view. /// public override void OnBeforeNavigatedTo() { base.OnBeforeNavigatedTo(); - - if (IsUpdateConnectedMachine && !MachineProvider.IsConnected) - { - IsUpdateConnectedMachine = false; - } + InvalidateIsUpdateConnectedMachine(); } private async void StartUpgrade() { if (IsApplicationUpdate) { - await NavigationManager.NavigateWithObject< - UpgradeModule, - ApplicationUpgradeView, - ApplicationUpgradeViewVM.NavigationObject> - (new ApplicationUpgradeViewVM.NavigationObject() - { - ApplicationUpgradeMode = IsUpdateConnectedMachine ? ApplicationUpgradeViewVM.ApplicationUpgradeMode.ConnectedMachine : ApplicationUpgradeViewVM.ApplicationUpgradeMode.OtherMachine, - SelectedMachine = IsUpdateConnectedMachine ? MachineProvider.Machine : SelectedMachine - }); + await ModularNavigationManager.NavigateTo(Navigation.RemoteUpgradeView.ApplicationUpgradeView, new ApplicationUpgradeViewVM.NavigationObject() + { + ApplicationUpgradeMode = IsUpdateConnectedMachine ? ApplicationUpgradeViewVM.ApplicationUpgradeMode.ConnectedMachine : ApplicationUpgradeViewVM.ApplicationUpgradeMode.OtherMachine, + SelectedMachine = IsUpdateConnectedMachine ? MachineProvider.Machine : SelectedMachine + }); } else { - await NavigationManager.NavigateTo(nameof(FirmwareUpgradeView)); + await ModularNavigationManager.NavigateTo(Navigation.RemoteUpgradeView.FirmwareUpgradeView); } } } 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 index d70b496e7..852bdced6 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeGeneratedView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeGeneratedView.xaml @@ -11,59 +11,75 @@ mc:Ignorable="d" d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:ApplicationUpgradeGeneratedViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.ApplicationUpgradeGeneratedViewVM}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> - - Application Upgrade Ready! + + + 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: + + + You have chosen to upgrade the currently connected machine. + press 'upgrade now' to start upgrading remotely. + That is not currently possible due to the following reason: + + + + + + + + + + I want to upgrade the currently connected machine right now. + + + + + + + I will upgrade later using a removable flash drive. + + - + + Select where to save the upgrade package (.tup file) + + + + + + - - - - - - + + + + + + - + - - - - - + diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeView.xaml index 349fa45e4..216d9d85f 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeView.xaml @@ -42,59 +42,54 @@ In case you chose to upgrade the currently connected machine, you will be able to perform the upgrade remotely. - - Select the desired Tango system software version + + + Select the desired Tango system software version - - - - - + + + + + () - - - + + + Application: v - - + + Firmware: v - - - - - - - - - - Select where to save the upgrade package (.tup file) + + + + + + + - - - - + + + - - - - - - - - + + + - - + + + + + + + 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 index 08bb74b6b..d3b151c27 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeGeneratedView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeGeneratedView.xaml @@ -10,7 +10,67 @@ xmlns:local="clr-namespace:Tango.FSE.Upgrade.Views" mc:Ignorable="d" d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:FirmwareUpgradeGeneratedViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.FirmwareUpgradeGeneratedViewVM}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> - - + + + + Firmware Upgrade Ready! + + + Your machine firmware upgrade is ready. + + + + + + + + I want to upgrade the currently connected machine right now. + + + + + + + I will upgrade later using a removable flash drive. + + + + + Select where to save the firmware package (.tfp file) + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeView.xaml index b899b4e04..527b70445 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeView.xaml @@ -12,17 +12,6 @@ mc:Ignorable="d" d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:FirmwareUpgradeViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.FirmwareUpgradeViewVM}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> - - - - Firmware Upgrade @@ -49,34 +38,25 @@ - + Select the desired firmware version - - - - - + + + + + () - - - + + + Firmware: v - - - - - - - - - - Select where to save the firmware package (.tfp file) - - - - - + + + + + + @@ -96,46 +76,33 @@ + - - - - - - - - - - - - + + - - + + + + + + + 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 efc9913ea..57363eed8 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 @@ -10,6 +10,17 @@ mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}" Background="{StaticResource FSE_PrimaryBackgroundBrush}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> + + + + @@ -27,10 +38,10 @@ @@ -47,7 +58,7 @@ - + diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/MainView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/MainView.xaml.cs index 867fb27c7..17442332b 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/MainView.xaml.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/MainView.xaml.cs @@ -20,8 +20,11 @@ namespace Tango.FSE.Upgrade.Views /// public partial class MainView : UserControl { + public static MainView Instance { get; set; } + public MainView() { + Instance = this; InitializeComponent(); } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/WelcomeView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/WelcomeView.xaml index 111d19b29..e82173419 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/WelcomeView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/WelcomeView.xaml @@ -11,55 +11,47 @@ mc:Ignorable="d" d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:WelcomeViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.WelcomeViewVM}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> - + - Please select the desired upgrade operation and press 'continue'. + + Please select the desired upgrade operation and press 'continue'. - - - - - I want to upgrade a machine's application and firmware version. - - + + + + + I want to upgrade a machine's application and firmware versions. (recommended) + + - - Please specify the target machine for this upgrade. - Upgrade the currently connected machine. - Upgrade a different machine. - - - - + + Please specify the target machine for this upgrade. + Upgrade the currently connected machine. + Upgrade a different machine. + + + + - - - - I want to upgrade a machine's firmware version. - - + + + + I want to upgrade a machine's firmware version. + + + + - - - - - + + - - + - + diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TangoVersionsService.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TangoVersionsService.cs index ed0a2a356..89a0e14ec 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TangoVersionsService.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TangoVersionsService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -95,5 +96,89 @@ namespace Tango.FSE.BL.Services }) .BuildExecuteAsync(); } + + public Task UploadCachedTupFile(TangoVersion version, String tupFilePath) + { + return Task.Factory.StartNew(() => + { + using (var cache = DiskCache.CreateContext()) + { + cache.FileStorage.Upload(CreateCachedTangoVersionFileName(version), tupFilePath); + } + }); + } + + public Task UploadCachedTfpFile(TangoVersion version, String tfpFilePath) + { + return Task.Factory.StartNew(() => + { + using (var cache = DiskCache.CreateContext()) + { + cache.FileStorage.Upload(CreateCachedFirmwareVersionFileName(version), tfpFilePath); + } + }); + } + + public Task DownloadCachedTupFile(TangoVersion version, String outputFilePath) + { + return Task.Factory.StartNew(() => + { + using (var cache = DiskCache.CreateContext()) + { + var file = cache.FileStorage.FindById(CreateCachedTangoVersionFileName(version)); + + if (file == null) + { + throw new KeyNotFoundException("The specified version cache could not be found."); + } + + file.SaveAs(outputFilePath, true); + } + }); + } + + public Task DownloadCachedTfpFile(TangoVersion version, String outputFilePath) + { + return Task.Factory.StartNew(() => + { + using (var cache = DiskCache.CreateContext()) + { + var file = cache.FileStorage.FindById(CreateCachedFirmwareVersionFileName(version)); + + if (file == null) + { + throw new KeyNotFoundException("The specified version cache could not be found."); + } + + file.SaveAs(outputFilePath, true); + } + }); + } + + public bool IsCachedTupFileExists(TangoVersion version) + { + using (var cache = DiskCache.CreateContext()) + { + return cache.FileStorage.FindById(CreateCachedTangoVersionFileName(version)) != null; + } + } + + public bool IsCachedTfpFileExists(TangoVersion version) + { + using (var cache = DiskCache.CreateContext()) + { + return cache.FileStorage.FindById(CreateCachedFirmwareVersionFileName(version)) != null; + } + } + + private String CreateCachedTangoVersionFileName(TangoVersion version) + { + return $"$/TangoVersions/application_package_v{version.Version}.tup"; + } + + private String CreateCachedFirmwareVersionFileName(TangoVersion version) + { + return $"$/TangoVersions/firmware_package_v{version.FirmwareVersion}.tfp"; + } } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Connection/IMachineProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Connection/IMachineProvider.cs index 6f3495a13..6f9d85fd5 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Connection/IMachineProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Connection/IMachineProvider.cs @@ -72,5 +72,14 @@ namespace Tango.FSE.Common.Connection /// /// Task DisconnectMachine(); + + /// + /// Disconnects the currently connected machine and displays a "waiting for reconnection dialog" with a timeout. + /// Useful when doing remote application restart. + /// + /// The amount of time to wait before starting reconnection attempts. + /// The timeout for when to drop the reconnection attempt. + /// + Task DisconnectAndWaitForReconnection(TimeSpan beginDelay, TimeSpan timeout); } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Images/arrow_right.png b/Software/Visual_Studio/FSE/Tango.FSE.Common/Images/arrow_right.png new file mode 100644 index 000000000..cdcc0e7cd Binary files /dev/null and b/Software/Visual_Studio/FSE/Tango.FSE.Common/Images/arrow_right.png differ diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/IModularNavigationNavigationManager.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/IModularNavigationNavigationManager.cs new file mode 100644 index 000000000..4ef0f7024 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/IModularNavigationNavigationManager.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Common.Navigation +{ + public interface IModularNavigationNavigationManager + { + T CurrentView { get; } + Task GetCurrentViewModel(); + bool CanNavigateBack { get; } + Task NavigateTo(T view, bool pushToHistory = true); + Task NavigateTo(T view, TPass objectToPass, bool pushToHistory = true); + Task NavigateBack(); + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/ModularNavigationFSEViewModel.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/ModularNavigationFSEViewModel.cs new file mode 100644 index 000000000..3bef447f1 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/ModularNavigationFSEViewModel.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.DI; + +namespace Tango.FSE.Common.Navigation +{ + public abstract class ModularNavigationFSEViewModel : FSEViewModel + { + [TangoInject(TangoInjectMode.WhenAvailable)] + protected IModularNavigationNavigationManager ModularNavigationManager { get; set; } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/ModularNavigationManager.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/ModularNavigationManager.cs new file mode 100644 index 000000000..33a1df304 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Navigation/ModularNavigationManager.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using Tango.Core; +using Tango.SharedUI.Controls; + +namespace Tango.FSE.Common.Navigation +{ + public abstract class ModularNavigationManager : ExtendedObject, IModularNavigationNavigationManager + { + private FrameworkElement _navigationControlParent; + private NavigationControl _navigationControl; + private Stack _history; + + private T _currentView; + public T CurrentView + { + get { return _currentView; } + protected set { _currentView = value; RaisePropertyChangedAuto(); } + } + + public bool CanNavigateBack + { + get { return _history.Count > 0; } + } + + public ModularNavigationManager(FrameworkElement navigationControlParent) + { + _history = new Stack(); + _navigationControlParent = navigationControlParent; + _navigationControlParent.RegisterForLoadedOrNow((_, __) => + { + _navigationControl = _navigationControlParent.FindChildOffline(); + _navigationControl.RegisterForLoadedOrNow((___, ____) => + { + var currentVM = (_navigationControl.GetElement(CurrentView.ToString()).DataContext as FSEViewModel); + currentVM.OnBeforeNavigatedTo(); + currentVM.OnNavigatedTo(); + }); + }); + } + + public Task NavigateTo(T view, bool pushToHistory = true) + { + return NavigateToInternal(view, null, pushToHistory); + } + + public Task NavigateTo(T view, TPass objectToPass, bool pushToHistory = true) + { + return NavigateToInternal(view, objectToPass, pushToHistory); + } + + private Task NavigateToInternal(T view, TPass objectToPass, bool pushToHistory) + { + TaskCompletionSource completion = new TaskCompletionSource(); + + var fromVM = _navigationControl.SelectedElement.DataContext as FSEViewModel; + var toVM = _navigationControl.GetElement(view.ToString()).DataContext as FSEViewModel; + + if (fromVM != toVM) + { + fromVM.OnBeforeNavigatedFrom(); + toVM.OnBeforeNavigatedTo(); + + if (toVM is INavigationObjectReceiver && objectToPass != null) + { + (toVM as INavigationObjectReceiver).OnNavigatedToWithObject(objectToPass); + } + + _navigationControl.NavigateTo(view.ToString(), () => + { + if (pushToHistory) + { + _history.Push(CurrentView); + DistinctHistory(); + RaisePropertyChanged(nameof(CanNavigateBack)); + } + + CurrentView = view; + + fromVM.OnNavigatedFrom(); + toVM.OnNavigatedTo(); + + completion.SetResult(true); + }); + } + else + { + completion.SetResult(true); + } + + return completion.Task; + } + + public async Task NavigateBack() + { + if (CanNavigateBack) + { + var toView = _history.Peek(); + + var fromVM = _navigationControl.GetElement(CurrentView.ToString()).DataContext as FSEViewModel; + + if (fromVM is INavigationBlocker) + { + if (!await (fromVM as INavigationBlocker).OnNavigateBackRequest()) + { + return false; + } + } + + _history.Pop(); + RaisePropertyChanged(nameof(CanNavigateBack)); + + await NavigateTo(toView); + + return true; + } + else + { + return false; + } + } + + private void DistinctHistory() + { + var list = _history.Distinct().ToList(); + list.Reverse(); + _history.Clear(); + + foreach (var item in list) + { + _history.Push(item); + } + + RaisePropertyChanged(nameof(CanNavigateBack)); + } + + public async Task GetCurrentViewModel() + { + if (_navigationControl == null) + { + await Task.Factory.StartNew(() => + { + while (_navigationControl == null) + { + Thread.Sleep(10); + } + }); + } + + return _navigationControl.GetElement(CurrentView.ToString()).DataContext as FSEViewModel; + } + } +} 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 4d2389dc6..ec06b2e8f 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteUpgrade/IRemoteUpgradeManager.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteUpgrade/IRemoteUpgradeManager.cs @@ -41,5 +41,12 @@ namespace Tango.FSE.Common.RemoteUpgrade /// The .tup file. /// Task PerformRemoteApplicationUpgrade(String tupFile); + + /// + /// Performs a remote firmware upgrade using the specified .tfp file. + /// + /// The .tfp file. + /// + Task PerformRemoteFirmwareUpgrade(String tfpFile); } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteUpgrade/RemoteUpgradeHandler.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteUpgrade/RemoteUpgradeHandler.cs index 8ba757edc..977a7a4cc 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteUpgrade/RemoteUpgradeHandler.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteUpgrade/RemoteUpgradeHandler.cs @@ -14,6 +14,10 @@ namespace Tango.FSE.Common.RemoteUpgrade public event EventHandler StatusChanged; + internal bool IsAborted { get; private set; } + + public bool CanAbort { get; internal set; } = true; + private double _progress; public double Progress { @@ -83,6 +87,7 @@ namespace Tango.FSE.Common.RemoteUpgrade public void Abort() { + IsAborted = true; _abortAction?.Invoke(); } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Images.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Images.xaml index c0ce6434d..ef3cb683e 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Images.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Images.xaml @@ -11,5 +11,6 @@ + \ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Styles.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Styles.xaml index 6aaffbd8a..ad59a5775 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Styles.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Styles.xaml @@ -585,6 +585,26 @@ + + + + + + + + + + + + + + + + + + + + + +