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. --- .../FileSystem/DefaultFileSystemProvider.cs | 529 ++++++++++++++++----- 1 file changed, 408 insertions(+), 121 deletions(-) (limited to 'Software/Visual_Studio/FSE/Tango.FSE.UI/FileSystem/DefaultFileSystemProvider.cs') 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 86ee2a73e..8381133bf 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/FileSystem/DefaultFileSystemProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/FileSystem/DefaultFileSystemProvider.cs @@ -8,6 +8,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Tango.Core; +using Tango.Core.ExtensionMethods; using Tango.Core.IO; using Tango.Core.Threading; using Tango.FileSystem; @@ -20,31 +21,79 @@ using Tango.WebRTC; namespace Tango.FSE.UI.FileSystem { + /// + /// Represents the default implementation. + /// + /// + /// public class DefaultFileSystemProvider : ExtendedObject, IFileSystemProvider { private IMachineProvider _machineProvider; private BasicTransporter _webRtcTransporter; private const string WEB_RTC_CHANNEL_NAME = "FileSystemChannel"; - private const long MAX_CHUNK_SIZE = 1024 * 100; - private const long MIN_CHUNK_SIZE = 1024; - private const long MAX_CHUNK_SIZE_WEB_RTC = 1024 * 50; - private const int WEB_RTC_MAX_RETRIES = 8; + private const long MAX_CHUNK_SIZE = 1024 * 100; //Max chunk size for the standard channel (WebSockets/SignalR). + private const long MIN_CHUNK_SIZE = 1024; //Min chunk size for the standard channel. + private const long MAX_CHUNK_SIZE_WEB_RTC = 1024 * 50; //Max chunk size for the WebRTC channel. + private const long MIN_CHUNK_SIZE_WEB_RTC = 1024; //Min chunk size for the WebRTC channel. + private const int WEB_RTC_MAX_RETRIES = 8; //Maximum number of retries per chunk for the WebRTC channel until falling back to standard channel. private List _activeHandlers; + #region Properties + private bool _enableWebRTC; + /// + /// Gets or sets a value indicating whether to enable a P2P WebRTC channel for fast transport. + /// public bool EnableWebRTC { get { return _enableWebRTC; } - set { _enableWebRTC = value; RaisePropertyChangedAuto(); } + set + { + _enableWebRTC = value; + RaisePropertyChangedAuto(); + + if (value) + { + LogManager.Log("File system WebRTC channel is now enabled."); + } + else + { + LogManager.Log("File system WebRTC channel is now disabled."); + } + } } private bool _isWebRtcAvailable; + /// + /// Gets a value indicating whether the WebRTC channel is available. + /// public bool IsWebRtcAvailable { get { return _isWebRtcAvailable; } - private set { _isWebRtcAvailable = value; RaisePropertyChangedAuto(); } + private set + { + _isWebRtcAvailable = value; + RaisePropertyChangedAuto(); + + if (value) + { + LogManager.Log("File system WebRTC channel is now available."); + } + else + { + LogManager.Log("File system WebRTC channel is now available."); + } + } } + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The machine provider. public DefaultFileSystemProvider(IMachineProvider machineProvider) { _activeHandlers = new List(); @@ -55,6 +104,10 @@ namespace Tango.FSE.UI.FileSystem _machineProvider.MachineDisconnected += _machineProvider_MachineDisconnected; } + #endregion + + #region Machine Connection Event Handlers + private async void _machineProvider_MachineDisconnected(object sender, MachineDisconnectedEventArgs e) { IsWebRtcAvailable = false; @@ -89,7 +142,7 @@ namespace Tango.FSE.UI.FileSystem private async void _machineProvider_MachineConnected(object sender, MachineConnectedEventArgs e) { - if (EnableWebRTC) + if (_machineProvider.ConnectionType.IsRemote()) { try { @@ -121,47 +174,100 @@ namespace Tango.FSE.UI.FileSystem } } + #endregion + + #region Public Methods + + /// + /// Gets a folder by the specified path. + /// + /// The path. + /// public async Task GetFolder(string path) { - var response = await _machineProvider.MachineOperator.SendGenericRequest(new GetFileSystemItemRequest() + try { - Path = path - }, new TransportRequestConfig() - { - Timeout = TimeSpan.FromSeconds(30), - }); + LogManager.Log($"Retrieving remote folder '{path}'..."); - return FileSystemItem.FromDTO(response.FileSystemItem) as IFileSystemContainer; + var response = await _machineProvider.MachineOperator.SendGenericRequest(new GetFileSystemItemRequest() + { + Path = path, + }, new TransportRequestConfig() + { + Timeout = TimeSpan.FromSeconds(30), + }); + + return FileSystemItem.FromDTO(response.FileSystemItem) as IFileSystemContainer; + } + catch (Exception ex) + { + throw LogManager.Log(ex, "Error retrieving remote folder."); + } } + /// + /// Gets the specified special folder. + /// + /// The special folder. + /// public async Task GetSpecialFolder(Environment.SpecialFolder specialFolder) { - var response = await _machineProvider.MachineOperator.SendGenericRequest(new GetFileSystemItemRequest() - { - SpecialFolder = specialFolder - }, new TransportRequestConfig() + try { - Timeout = TimeSpan.FromSeconds(30), - }); + LogManager.Log($"Retrieving remote special folder '{specialFolder}'..."); + + var response = await _machineProvider.MachineOperator.SendGenericRequest(new GetFileSystemItemRequest() + { + SpecialFolder = specialFolder + }, new TransportRequestConfig() + { + Timeout = TimeSpan.FromSeconds(30), + }); - return FileSystemItem.FromDTO(response.FileSystemItem) as IFileSystemContainer; + return FileSystemItem.FromDTO(response.FileSystemItem) as IFileSystemContainer; + } + catch (Exception ex) + { + throw LogManager.Log(ex, "Error retrieving remote special folder."); + } } + /// + /// Gets the ThisPC (the root path of the PC). + /// + /// public async Task GetThisPC() { - var response = await _machineProvider.MachineOperator.SendGenericRequest(new GetFileSystemItemRequest() - { - //No parameters at all - }, new TransportRequestConfig() + try { - Timeout = TimeSpan.FromSeconds(30), - }); + LogManager.Log("Retrieving remote root directory (This PC)..."); - return FileSystemItem.FromDTO(response.FileSystemItem) as IFileSystemContainer; + var response = await _machineProvider.MachineOperator.SendGenericRequest(new GetFileSystemItemRequest() + { + //No parameters at all + }, new TransportRequestConfig() + { + Timeout = TimeSpan.FromSeconds(30), + }); + + return FileSystemItem.FromDTO(response.FileSystemItem) as IFileSystemContainer; + } + catch (Exception ex) + { + throw LogManager.Log(ex, "Error retrieving remote root directory."); + } } + /// + /// Downloads the specified file or folder item. + /// + /// The file or folder. + /// The local target folder. + /// public Task Download(FileSystemItem item, string localTargetFolder) { + LogManager.Log($"Downloading remote item '{item.Path}' to local path '{localTargetFolder}'..."); + String operationId = String.Empty; String destination = String.Empty; long downloadLength = 0; @@ -171,23 +277,28 @@ namespace Tango.FSE.UI.FileSystem destination = Path.Combine(localTargetFolder, item.Name); - handler = new FileSystemHandler(item.Type == FileSystemItemType.Folder ? FileSystemHandlerType.FolderDownload : FileSystemHandlerType.FileDownload, item, destination, async () => { if (!aborted) { + LogManager.Log($"Download aborted by user for '{item.Name}'. Aborting download..."); + aborted = true; try { + LogManager.Log("Sending abort download operation request..."); + var response = await _machineProvider.MachineOperator.SendGenericRequest( new AbortOperationRequest() { OperationId = operationId }, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(30) }); + + LogManager.Log($"Download operation for '{item.Name} 'aborted successfully."); } catch (Exception ex) { - LogManager.Log(ex, "Error aborting the download operation."); + LogManager.Log(ex, $"Error aborting the download operation for '{item.Name}'."); } finally { @@ -204,24 +315,32 @@ namespace Tango.FSE.UI.FileSystem { if (item.Type == FileSystemItemType.File) { + LogManager.Log("Download item identified as a file. Sending file download request..."); + var response = await _machineProvider.MachineOperator.SendGenericRequest( new FileDownloadRequest() { Path = item.Path }, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(20) }); + LogManager.Log($"File download response received:\n{response.ToJsonString()}"); + operationId = response.OperationId; downloadLength = response.Length; handler.OperationId = operationId; } else if (item.Type == FileSystemItemType.Folder) { + LogManager.Log("Download item identified as a folder. Sending folder download request..."); + var response = await _machineProvider.MachineOperator.SendGenericRequest( new FolderDownloadRequest() { Path = item.Path }, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(60) }); + LogManager.Log($"folder download response received:\n{response.ToJsonString()}"); + operationId = response.OperationId; downloadLength = response.Length; handler.OperationId = operationId; @@ -233,6 +352,7 @@ namespace Tango.FSE.UI.FileSystem } catch (Exception ex) { + LogManager.Log(ex, $"Error downloading remote item '{item.Path}'."); _activeHandlers.Remove(handler); handler.RaiseFailed(ex); return; @@ -241,9 +361,14 @@ namespace Tango.FSE.UI.FileSystem long position = 0; bool webRtcFailed = false; int webRtcRetries = WEB_RTC_MAX_RETRIES; - long dynamixMaxChunkSizeSignalR = MAX_CHUNK_SIZE; + long dynamicMaxChunkSizeSignalR = MAX_CHUNK_SIZE; + long dynamicMaxChunkSizeWebRTC = MIN_CHUNK_SIZE_WEB_RTC; + bool isWebRTCChunkSizeFixed = false; var tempFile = TemporaryManager.CreateFile(); + LogManager.Log($"Generated temporary local file '{tempFile}'..."); + LogManager.Log("Starting chunks download..."); + LogManager.Log($"WebRTC active: {(IsWebRtcAvailable && EnableWebRTC).ToStringYesNo()}."); while (position < downloadLength && !aborted) { @@ -263,27 +388,36 @@ namespace Tango.FSE.UI.FileSystem Position = position, }; - if (_webRtcTransporter != null && _webRtcTransporter.State == TransportComponentState.Connected && EnableWebRTC && !webRtcFailed) + if (_webRtcTransporter != null && _webRtcTransporter.State == TransportComponentState.Connected && EnableWebRTC && !webRtcFailed && _machineProvider.ConnectionType == MachineConnectionTypes.SignalR) { try { - request.MaxChunkSize = MAX_CHUNK_SIZE_WEB_RTC; + request.MaxChunkSize = dynamicMaxChunkSizeWebRTC; + response = await _webRtcTransporter.SendGenericRequest(request, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(2), Priority = QueuePriority.Low }); + if (!isWebRTCChunkSizeFixed) + { + dynamicMaxChunkSizeWebRTC = Math.Min(dynamicMaxChunkSizeWebRTC + 1024, MAX_CHUNK_SIZE_WEB_RTC); + } + webRtcRetries = WEB_RTC_MAX_RETRIES; } catch (Exception ex) { webRtcRetries--; + dynamicMaxChunkSizeWebRTC = Math.Max(dynamicMaxChunkSizeWebRTC - 1024, MIN_CHUNK_SIZE_WEB_RTC); + isWebRTCChunkSizeFixed = true; + if (webRtcRetries == 0) { webRtcFailed = true; - LogManager.Log(ex, "WebRTC chunk download failed. Falling back to standard download..."); + LogManager.Log(ex, $"WebRTC chunk download for '{item.Name}' failed after {WEB_RTC_MAX_RETRIES} retries with exception:\n{ex.FlattenMessage()}\nFalling back to SignalR download..."); } continue; @@ -291,7 +425,7 @@ namespace Tango.FSE.UI.FileSystem } else { - request.MaxChunkSize = dynamixMaxChunkSizeSignalR; + request.MaxChunkSize = dynamicMaxChunkSizeSignalR; Stopwatch watch = new Stopwatch(); watch.Start(); @@ -306,14 +440,14 @@ namespace Tango.FSE.UI.FileSystem if (watch.Elapsed.TotalSeconds < 1) { - dynamixMaxChunkSizeSignalR += 1024 * 10; + dynamicMaxChunkSizeSignalR += 1024 * 10; } else if (watch.Elapsed.TotalSeconds > 1) { - dynamixMaxChunkSizeSignalR -= 1024 * 10; + dynamicMaxChunkSizeSignalR -= 1024 * 10; } - dynamixMaxChunkSizeSignalR = Math.Max(dynamixMaxChunkSizeSignalR, MIN_CHUNK_SIZE); + dynamicMaxChunkSizeSignalR = Math.Max(dynamicMaxChunkSizeSignalR, MIN_CHUNK_SIZE); } using (FileStream fs = new FileStream(tempFile, FileMode.Append)) @@ -326,6 +460,7 @@ namespace Tango.FSE.UI.FileSystem } catch (Exception ex) { + LogManager.Log(ex, $"Download failed for '{item.Name}'."); _activeHandlers.Remove(handler); tempFile.Delete(); handler.RaiseFailed(ex); @@ -335,27 +470,37 @@ namespace Tango.FSE.UI.FileSystem if (!aborted) { + LogManager.Log($"Chunks completed for '{item.Name}'."); + try { if (item.Type == FileSystemItemType.File) { + LogManager.Log("Copying temporary file to destination directory..."); File.Copy(tempFile, destination, true); + + LogManager.Log("Removing temporary file..."); tempFile.Delete(); } else if (item.Type == FileSystemItemType.Folder) { + LogManager.Log("Extracting temporary zip file to destination directory..."); + using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile(tempFile)) { zip.ExtractAll(destination, Ionic.Zip.ExtractExistingFileAction.OverwriteSilently); } + LogManager.Log("Removing temporary zip file..."); tempFile.Delete(); } + LogManager.Log($"Download completed successfully for '{item.Name}'."); handler.RaiseCompleted(); } catch (Exception ex) { + LogManager.Log(ex, $"Download failed on the final stage for {item.Name}."); handler.RaiseFailed(ex); } } @@ -370,6 +515,13 @@ namespace Tango.FSE.UI.FileSystem return Task.FromResult(handler); } + /// + /// Uploads the specified local file or folder. + /// + /// The local source path. + /// The remote folder. + /// + /// Could not locate the local file or directory to upload. public Task Upload(String localSourcePath, FileSystemItem remoteFolder) { String operationId = String.Empty; @@ -381,44 +533,51 @@ namespace Tango.FSE.UI.FileSystem if (Directory.Exists(localSourcePath)) { + LogManager.Log($"Uploading local folder '{localSourcePath}' to remote path '{remoteFolder.Path}'..."); sourceItem = new FolderItem() { Path = localSourcePath }; isFolder = true; } else if (File.Exists(localSourcePath)) { + LogManager.Log($"Uploading local file '{localSourcePath}' to remote path '{remoteFolder.Path}'..."); sourceItem = new FileItem() { Path = localSourcePath }; isFolder = false; } else { - throw new FileNotFoundException("Could not locate the local file or directory to upload."); + throw LogManager.Log(new FileNotFoundException("Could not locate the local file or directory to upload."), "Error uploading local item to remote location."); } FileSystemHandler handler = null; handler = new FileSystemHandler(isFolder ? FileSystemHandlerType.FolderUpload : FileSystemHandlerType.FileUpload, sourceItem, destination, async () => - { - if (!aborted) - { - aborted = true; - try - { - var response = await _machineProvider.MachineOperator.SendGenericRequest( - new AbortOperationRequest() - { - OperationId = operationId - }, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(30) }); - } - catch (Exception ex) - { - LogManager.Log(ex, "Error aborting the upload operation."); - } - finally - { - handler.RaiseAborted(); - } - } - }); + { + if (!aborted) + { + LogManager.Log($"Upload aborted by user for item '{sourceItem.Name}'. Aborting upload..."); + + aborted = true; + try + { + LogManager.Log("Sending upload operation abort request..."); + var response = await _machineProvider.MachineOperator.SendGenericRequest( + new AbortOperationRequest() + { + OperationId = operationId + }, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(30) }); + + LogManager.Log($"Upload operation successfully aborted for item '{sourceItem.Name}'."); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error aborting the upload operation for item '{sourceItem.Name}'."); + } + finally + { + handler.RaiseAborted(); + } + } + }); _activeHandlers.Add(handler); @@ -428,23 +587,31 @@ namespace Tango.FSE.UI.FileSystem { if (!isFolder) { + LogManager.Log("Upload item identified as a file. Sending file upload request..."); + var response = await _machineProvider.MachineOperator.SendGenericRequest( new FileUploadRequest() { Path = destination }, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(20) }); + LogManager.Log($"File upload response received:\n{response.ToJsonString()}"); + operationId = response.OperationId; handler.OperationId = operationId; } else { + LogManager.Log("Upload item identified as a folder. Sending file upload request..."); + var response = await _machineProvider.MachineOperator.SendGenericRequest( new FolderUploadRequest() { Path = destination }, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(20) }); + LogManager.Log($"Folder upload response received:\n{response.ToJsonString()}"); + operationId = response.OperationId; handler.OperationId = operationId; } @@ -453,11 +620,13 @@ namespace Tango.FSE.UI.FileSystem { var originalPath = localSourcePath; localSourcePath = TemporaryManager.CreateImaginaryFile().Path; + LogManager.Log($"Compressing local folder to temporary zip file '{localSourcePath}'..."); ZipFile.CreateFromDirectory(originalPath, localSourcePath); } } catch (Exception ex) { + LogManager.Log(ex, $"Error uploading local item '{sourceItem.Name}'."); _activeHandlers.Remove(handler); handler.RaiseFailed(ex); return; @@ -467,6 +636,11 @@ namespace Tango.FSE.UI.FileSystem bool webRtcFailed = false; int webRtcRetries = WEB_RTC_MAX_RETRIES; long dynamixMaxChunkSizeSignalR = MAX_CHUNK_SIZE; + long dynamicMaxChunkSizeWebRTC = MIN_CHUNK_SIZE_WEB_RTC; + bool isWebRTCChunkSizeFixed = false; + + LogManager.Log("Starting chunks download..."); + LogManager.Log($"WebRTC active: {(IsWebRtcAvailable && EnableWebRTC).ToStringYesNo()}."); using (FileStream fs = new FileStream(localSourcePath, FileMode.Open)) { @@ -488,11 +662,11 @@ namespace Tango.FSE.UI.FileSystem OperationId = operationId, }; - if (_webRtcTransporter != null && _webRtcTransporter.State == TransportComponentState.Connected && EnableWebRTC && !webRtcFailed) + if (_webRtcTransporter != null && _webRtcTransporter.State == TransportComponentState.Connected && EnableWebRTC && !webRtcFailed && _machineProvider.ConnectionType == MachineConnectionTypes.SignalR) { try { - byte[] data = new byte[Math.Min(MAX_CHUNK_SIZE_WEB_RTC, fs.Length - fs.Position)]; + byte[] data = new byte[Math.Min(dynamicMaxChunkSizeWebRTC, fs.Length - fs.Position)]; fs.Read(data, 0, data.Length); request.Data = data; request.IsCompleted = fs.Position == fs.Length; @@ -503,16 +677,24 @@ namespace Tango.FSE.UI.FileSystem Priority = QueuePriority.Low }); + if (!isWebRTCChunkSizeFixed) + { + dynamicMaxChunkSizeWebRTC = Math.Min(dynamicMaxChunkSizeWebRTC + 1024, MAX_CHUNK_SIZE_WEB_RTC); + } + webRtcRetries = WEB_RTC_MAX_RETRIES; } catch (Exception ex) { webRtcRetries--; + dynamicMaxChunkSizeWebRTC = Math.Max(dynamicMaxChunkSizeWebRTC - 1024, MIN_CHUNK_SIZE_WEB_RTC); + isWebRTCChunkSizeFixed = true; + if (webRtcRetries == 0) { webRtcFailed = true; - LogManager.Log(ex, "WebRTC chunk upload failed. Falling back to standard upload..."); + LogManager.Log(ex, $"WebRTC chunk upload for '{sourceItem.Name}' failed after {WEB_RTC_MAX_RETRIES} retries with exception:\n{ex.FlattenMessage()}\nFalling back to SignalR upload..."); } continue; @@ -553,6 +735,8 @@ namespace Tango.FSE.UI.FileSystem } catch (Exception ex) { + LogManager.Log(ex, $"Upload failed for '{sourceItem.Name}'."); + _activeHandlers.Remove(handler); handler.RaiseFailed(ex); @@ -561,6 +745,7 @@ namespace Tango.FSE.UI.FileSystem try { fs.Dispose(); + LogManager.Log("Removing temporary zip file..."); File.Delete(localSourcePath); } catch { } @@ -572,6 +757,7 @@ namespace Tango.FSE.UI.FileSystem if (!aborted) { + LogManager.Log($"Upload for '{sourceItem.Name}' completed successfully."); handler.RaiseCompleted(); } @@ -579,6 +765,7 @@ namespace Tango.FSE.UI.FileSystem { try { + LogManager.Log("Removing temporary zip file..."); File.Delete(localSourcePath); } catch { } @@ -591,107 +778,207 @@ namespace Tango.FSE.UI.FileSystem return Task.FromResult(handler); } + /// + /// Copies the specified remote file or folder to the specified target remote folder. + /// + /// The remote source file or folder. + /// The remote target folder. + /// + /// + /// The source file system item is not supported for copying. + /// or + /// The target file system item is not a valid container. + /// public async Task Copy(FileSystemItem source, FileSystemItem target) { - if (source.Type == FileSystemItemType.Drive) - { - throw new NotSupportedException("The source file system item is not supported for copying."); - } - if (target.Type == FileSystemItemType.File) + try { - throw new NotSupportedException("The target file system item is not a valid container."); - } + LogManager.Log($"Copying remote item '{source.Path}' to '{target.Path}'..."); - await _machineProvider.MachineOperator.SendGenericRequest(new CopyRequest() - { + if (source.Type == FileSystemItemType.Drive) + { + throw new NotSupportedException("The source file system item is not supported for copying."); + } + if (target.Type == FileSystemItemType.File) + { + throw new NotSupportedException("The target file system item is not a valid container."); + } + + await _machineProvider.MachineOperator.SendGenericRequest(new CopyRequest() + { - Source = source.Path, - Destination = Path.Combine(target.Path, source.Name) + Source = source.Path, + Destination = Path.Combine(target.Path, source.Name) - }, new TransportRequestConfig() + }, new TransportRequestConfig() + { + Timeout = TimeSpan.FromSeconds(120), + }); + } + catch (Exception ex) { - Timeout = TimeSpan.FromSeconds(120), - }); + throw LogManager.Log(ex, "Error performing copy operation on remote file system."); + } } + /// + /// Moves the specified remote file or folder to the remote target folder. + /// + /// The remote source file or folder. + /// The remote target folder. + /// + /// + /// The source file system item is not supported for copying. + /// or + /// The target file system item is not a valid container. + /// public async Task Move(FileSystemItem source, FileSystemItem target) { - if (source.Type == FileSystemItemType.Drive) + try { - throw new NotSupportedException("The source file system item is not supported for copying."); - } - if (target.Type == FileSystemItemType.File) - { - throw new NotSupportedException("The target file system item is not a valid container."); - } + LogManager.Log($"Moving remote item '{source.Path}' to '{target.Path}'..."); - await _machineProvider.MachineOperator.SendGenericRequest(new MoveRequest() - { + if (source.Type == FileSystemItemType.Drive) + { + throw new NotSupportedException("The source file system item is not supported for moving."); + } + if (target.Type == FileSystemItemType.File) + { + throw new NotSupportedException("The target file system item is not a valid container."); + } - Source = source.Path, - Destination = Path.Combine(target.Path, source.Name) + await _machineProvider.MachineOperator.SendGenericRequest(new MoveRequest() + { + + Source = source.Path, + Destination = Path.Combine(target.Path, source.Name) - }, new TransportRequestConfig() + }, new TransportRequestConfig() + { + Timeout = TimeSpan.FromSeconds(120), + }); + } + catch (Exception ex) { - Timeout = TimeSpan.FromSeconds(120), - }); + throw LogManager.Log(ex, "Error performing move operation on the remote file system item."); + } } + /// + /// Renames the specified file or folder. + /// + /// The remote source file or folder. + /// The new name. + /// + /// The source file system item is not supported for copying. + /// The new name contains invalid characters. public async Task Rename(FileSystemItem source, string newName) { - if (source.Type == FileSystemItemType.Drive) + try { - throw new NotSupportedException("The source file system item is not supported for copying."); + LogManager.Log($"Renaming remote item '{source.Path}' to '{newName}'..."); + + if (source.Type == FileSystemItemType.Drive) + { + throw new NotSupportedException("The source file system item is not supported for renaming."); + } + if (newName.ToList().Exists(x => Path.GetInvalidFileNameChars().Contains(x))) + { + throw new ArgumentException("The new name contains invalid characters."); + } + + await _machineProvider.MachineOperator.SendGenericRequest(new MoveRequest() + { + Source = source.Path, + Destination = Path.Combine(Path.GetDirectoryName(source.Path), newName) + }); } - if (newName.ToList().Exists(x => Path.GetInvalidFileNameChars().Contains(x))) + catch (Exception ex) { - throw new ArgumentException("The new name contains invalid characters."); + throw LogManager.Log(ex, "Error performing rename operation on the remote file system item."); } - - await _machineProvider.MachineOperator.SendGenericRequest(new MoveRequest() - { - - Source = source.Path, - Destination = Path.Combine(Path.GetDirectoryName(source.Path), newName) - - }); } + /// + /// Deletes the specified file or folder. + /// + /// The remote file or folder. + /// + /// The source file system item is not supported for deletion. public async Task Delete(FileSystemItem item) { - if (item.Type == FileSystemItemType.Drive) + try { - throw new NotSupportedException("The source file system item is not supported for deletion."); - } + LogManager.Log($"Deleting remote item '{item.Path}'..."); + + if (item.Type == FileSystemItemType.Drive) + { + throw new NotSupportedException("The source file system item is not supported for deletion."); + } - await _machineProvider.MachineOperator.SendGenericRequest(new DeleteRequest() + await _machineProvider.MachineOperator.SendGenericRequest(new DeleteRequest() + { + Path = item.Path + }, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(120) }); + } + catch (Exception ex) { - Path = item.Path - }, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(120) }); + throw LogManager.Log(ex, "Error performing delete operation on the remote file system item."); + } } + /// + /// Creates a new folder at the specified remote parent. + /// + /// The remote parent path. + /// Name of the new folder. + /// public async Task CreateFolder(FileSystemItem parent, string folderName) { - var response = await _machineProvider.MachineOperator.SendGenericRequest(new CreateFolderRequest() + try { - Path = parent.Path, - FolderName = folderName, - }); + LogManager.Log($"Creating new folder '{folderName}' on the remote path '{parent.Path}'..."); + + var response = await _machineProvider.MachineOperator.SendGenericRequest(new CreateFolderRequest() + { + Path = parent.Path, + FolderName = folderName, + }); - return FileSystemItem.FromDTO(response.FolderItem) as FolderItem; + return FileSystemItem.FromDTO(response.FolderItem) as FolderItem; + } + catch (Exception ex) + { + throw LogManager.Log(ex, "Error creating new folder on the remote file system location."); + } } + /// + /// Performs a disk space optimization. + /// + /// public async Task PerformDiskSpaceOptimization() { - var response = await _machineProvider.MachineOperator.SendGenericRequest(new PerformDiskSpaceOptimizationRequest() + try { + LogManager.Log("Performing disk space optimization on the remote file system."); - }, new TransportRequestConfig() - { - Timeout = TimeSpan.FromMinutes(5) - }); + var response = await _machineProvider.MachineOperator.SendGenericRequest(new PerformDiskSpaceOptimizationRequest() + { + + }, new TransportRequestConfig() + { + Timeout = TimeSpan.FromMinutes(5) + }); - return response; + return response; + } + catch (Exception ex) + { + throw LogManager.Log(ex, "Error occurred while trying to perform the disk space optimization on the remote file system."); + } } + + #endregion } } -- cgit v1.3.1