aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs')
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs433
1 files changed, 433 insertions, 0 deletions
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs
new file mode 100644
index 000000000..8272ea34d
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs
@@ -0,0 +1,433 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Tango.Core;
+using Tango.Core.DI;
+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.Settings;
+using Tango.Transport;
+using Tango.Transport.Transporters;
+using Tango.WebRTC;
+
+namespace Tango.PPC.Common.FileSystem
+{
+ /// <summary>
+ /// Represents the <see cref="IFileSystemService"/> default implementation.
+ /// </summary>
+ /// <seealso cref="Tango.Core.ExtendedObject" />
+ /// <seealso cref="Tango.PPC.Common.FileSystem.IFileSystemService" />
+ /// <seealso cref="Tango.Integration.ExternalBridge.IExternalBridgeRequestHandler" />
+ [TangoCreateWhenRegistered]
+ public class DefaultFileSystemService : ExtendedObject, IFileSystemService, IExternalBridgeRequestHandler
+ {
+ private FileSystemManager _manager;
+ private Dictionary<String, FileSystemOperation> _operations;
+ private Dictionary<ExternalBridgeReceiver, BasicTransporter> _webRtcClients;
+ private PPCSettings _settings;
+
+ public bool Enabled { get; set; } = true;
+ public bool EnableWebRTC { get; set; } = true;
+
+ public DefaultFileSystemService(IPPCExternalBridgeService externalBridge)
+ {
+ _webRtcClients = new Dictionary<ExternalBridgeReceiver, BasicTransporter>();
+ _manager = new FileSystemManager();
+ _operations = new Dictionary<string, FileSystemOperation>();
+ externalBridge.RegisterRequestHandler(this);
+ _settings = SettingsManager.Default.GetOrCreate<PPCSettings>();
+ }
+
+ [ExternalBridgeRequestHandlerMethod(typeof(InitWebRtcRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)]
+ public async Task OnInitWebRtcRequest(InitWebRtcRequest request, String token, ExternalBridgeReceiver receiver)
+ {
+ this.ThrowIfDisabled();
+
+ try
+ {
+ if (!EnableWebRTC)
+ {
+ await receiver.SendErrorResponse(new InvalidOperationException("The file system service WebRTC channel is disabled on this machine."), token);
+ 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)
+ {
+ EnableCompression = receiver.Adapter.EnableCompression
+ };
+ webRtcAdapter.Ready += (x, e) =>
+ {
+ LogManager.Log("The file system service WebRTC channel is ready.");
+ };
+
+ BasicTransporter webRtcTransporter = new BasicTransporter(webRtcAdapter);
+ webRtcTransporter.GenericProtocol = receiver.GenericProtocol;
+ webRtcTransporter.ComponentName = "File System Passive WebRTC Transporter";
+ webRtcTransporter.UseKeepAlive = false;
+ webRtcTransporter.RegisterRequestHandler<ChunkDownloadRequest>(WebRtcChunkDownloadRequestReceived);
+ webRtcTransporter.RegisterRequestHandler<ChunkUploadRequest>(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 async void WebRtcChunkDownloadRequestReceived(ITransporter transporter, ChunkDownloadRequest request, string token)
+ {
+ await OnChunkDownloadRequest(request, token, transporter);
+ }
+
+ private async void WebRtcChunkUploadRequestReceived(ITransporter transporter, ChunkUploadRequest request, string token)
+ {
+ await OnChunkUploadRequest(request, token, transporter);
+ }
+
+ [ExternalBridgeRequestHandlerMethod(typeof(GetFileSystemItemRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)]
+ public async Task OnGetFileSystemItemRequest(GetFileSystemItemRequest request, String token, ExternalBridgeReceiver receiver)
+ {
+ this.ThrowIfDisabled();
+
+ FileSystemItemDTO dto = _manager.GetFolder(request);
+ await receiver.SendGenericResponse(new GetFileSystemItemResponse() { FileSystemItem = dto }, token);
+ }
+
+ [ExternalBridgeRequestHandlerMethod(typeof(FileUploadRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)]
+ public async Task OnFileUploadRequest(FileUploadRequest request, String token, ExternalBridgeReceiver receiver)
+ {
+ this.ThrowIfDisabled();
+
+ var tempFile = TemporaryManager.CreateFile();
+ using (var stream = new FileStream(tempFile, FileMode.Create)) { }
+
+ 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), RequestHandlerLoggingMode.LogRequestNameAndContent)]
+ public async Task OnFolderUploadRequest(FolderUploadRequest request, String token, ExternalBridgeReceiver receiver)
+ {
+ this.ThrowIfDisabled();
+
+ var tempFile = TemporaryManager.CreateFile();
+ using (var stream = new FileStream(tempFile, FileMode.Create)) { }
+
+ 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), RequestHandlerLoggingMode.LogRequestNameAndContent)]
+ public async Task OnFileDownloadRequest(FileDownloadRequest request, String token, ExternalBridgeReceiver receiver)
+ {
+ this.ThrowIfDisabled();
+
+ if (!File.Exists(request.Path))
+ {
+ throw new FileNotFoundException("Could not find the specified file.");
+ }
+
+ FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Download, request.Path);
+
+ _operations.Add(operation.Id, operation);
+
+ await receiver.SendGenericResponse(new FileDownloadResponse()
+ {
+ OperationId = operation.Id,
+ Length = new FileInfo(request.Path).Length
+ }, token);
+ }
+
+ [ExternalBridgeRequestHandlerMethod(typeof(FolderDownloadRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)]
+ public async Task OnFolderDownloadRequest(FolderDownloadRequest request, String token, ExternalBridgeReceiver receiver)
+ {
+ this.ThrowIfDisabled();
+
+ if (!Directory.Exists(request.Path))
+ {
+ throw new FileNotFoundException("Could not find the specified directory.");
+ }
+
+ var tempFile = TemporaryManager.CreateImaginaryFile();
+
+ ZipFile.CreateFromDirectory(request.Path, tempFile);
+
+ FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Download, tempFile);
+ operation.IsPathTempZip = true;
+
+ _operations.Add(operation.Id, operation);
+
+ await receiver.SendGenericResponse(new FolderDownloadResponse()
+ {
+ OperationId = operation.Id,
+ Length = new FileInfo(tempFile).Length
+ }, token);
+ }
+
+ [ExternalBridgeRequestHandlerMethod(typeof(ChunkUploadRequest))]
+ public async Task OnChunkUploadRequest(ChunkUploadRequest request, String token, ITransporter receiver)
+ {
+ this.ThrowIfDisabled();
+
+ FileSystemOperation operation;
+ _operations.TryGetValue(request.OperationId, out operation);
+
+ if (operation == null)
+ {
+ throw new ArgumentException("Invalid operation id.");
+ }
+
+ using (var stream = new FileStream(operation.Path, FileMode.Append))
+ {
+ stream.Write(request.Data, 0, request.Data.Length);
+ }
+
+ if (request.IsCompleted)
+ {
+ if (!operation.IsPathTempZip)
+ {
+ File.Copy(operation.Path, operation.UploadPostPath, true);
+ try
+ {
+ File.Delete(operation.Path);
+ }
+ catch { }
+ }
+ 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 { }
+ }
+ }
+
+ await receiver.SendGenericResponse(new ChunkUploadResponse(), token, new TransportResponseConfig() { Priority = QueuePriority.Low });
+ }
+
+ [ExternalBridgeRequestHandlerMethod(typeof(ChunkDownloadRequest))]
+ public async Task OnChunkDownloadRequest(ChunkDownloadRequest request, String token, ITransporter receiver)
+ {
+ this.ThrowIfDisabled();
+
+ FileSystemOperation operation;
+ _operations.TryGetValue(request.OperationId, out operation);
+
+ if (operation == null)
+ {
+ throw new ArgumentException("Invalid operation id.");
+ }
+
+ FileStream stream = null;
+ bool removeTempZipFile = false;
+
+ try
+ {
+ stream = new FileStream(operation.Path, FileMode.Open);
+ stream.Position = request.Position;
+ byte[] data = new byte[Math.Min(request.MaxChunkSize, stream.Length - stream.Position)];
+
+ if (stream.Position + data.Length == stream.Length)
+ {
+ removeTempZipFile = true;
+ }
+
+ await stream.ReadAsync(data, 0, data.Length);
+ stream.Dispose();
+ stream = null;
+ await receiver.SendGenericResponse(new ChunkDownloadResponse()
+ {
+ Data = data
+ }, token, new TransportResponseConfig() { Priority = QueuePriority.Low });
+ }
+ catch (Exception ex)
+ {
+ stream?.Dispose();
+ throw ex;
+ }
+ finally
+ {
+ if (operation.IsPathTempZip && removeTempZipFile)
+ {
+ try
+ {
+ if (File.Exists(operation.Path))
+ {
+ File.Delete(operation.Path);
+ }
+ }
+ catch { }
+ }
+ }
+ }
+
+ [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)
+ {
+ throw new ArgumentException("Invalid operation id.");
+ }
+
+ if (operation.Mode == FileSystemOperationMode.Upload)
+ {
+ if (File.Exists(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);
+ }
+
+ [ExternalBridgeRequestHandlerMethod(typeof(MoveRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)]
+ public async Task OnMoveRequest(MoveRequest request, String token, ExternalBridgeReceiver receiver)
+ {
+ this.ThrowIfDisabled();
+
+ _manager.Move(request);
+ await receiver.SendGenericResponse(new MoveResponse(), token);
+ }
+
+ [ExternalBridgeRequestHandlerMethod(typeof(CopyRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)]
+ public async Task OnCopyRequest(CopyRequest request, String token, ExternalBridgeReceiver receiver)
+ {
+ this.ThrowIfDisabled();
+
+ _manager.Copy(request);
+ await receiver.SendGenericResponse(new CopyResponse(), token);
+ }
+
+ [ExternalBridgeRequestHandlerMethod(typeof(DeleteRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)]
+ public async Task OnDeleteRequest(DeleteRequest request, String token, ExternalBridgeReceiver receiver)
+ {
+ this.ThrowIfDisabled();
+
+ _manager.Delete(request.Path);
+ await receiver.SendGenericResponse(new DeleteResponse(), token);
+ }
+
+ [ExternalBridgeRequestHandlerMethod(typeof(CreateFolderRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)]
+ public async Task OnCreateFolderRequest(CreateFolderRequest request, String token, ExternalBridgeReceiver receiver)
+ {
+ this.ThrowIfDisabled();
+
+ var dto = _manager.CreateFolder(request.Path, request.FolderName);
+ await receiver.SendGenericResponse(new CreateFolderResponse() { FolderItem = dto }, token);
+ }
+
+ [ExternalBridgeRequestHandlerMethod(typeof(PerformDiskSpaceOptimizationRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)]
+ public async Task OnPerformDiskSpaceOptimizationRequest(PerformDiskSpaceOptimizationRequest request, String token, ExternalBridgeReceiver receiver)
+ {
+ var deletedBytes = _manager.PerformDiskSpaceOptimization();
+ 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<FileItem>().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))
+ {
+ 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 channel.");
+ }
+ }
+ }
+ }
+}