using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tango.BL.Enumerations;
using Tango.Core;
using Tango.Core.DI;
using Tango.Core.ExtensionMethods;
using Tango.Core.IO;
using Tango.Core.Threading;
using Tango.FileSystem;
using Tango.FileSystem.Network;
using Tango.FSE.Common.Authentication;
using Tango.FSE.Common.Build;
using Tango.FSE.Common.Connection;
using Tango.FSE.Common.FileSystem;
using Tango.FSE.Common.Notifications;
using Tango.Transport;
using Tango.Transport.Transporters;
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; //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;
[TangoInject]
private INotificationProvider NotificationProvider { get; set; }
[TangoInject]
private IAuthenticationProvider AuthenticationProvider { get; set; }
[TangoInject(Mode = TangoInjectMode.WhenAvailable)]
private IBuildProvider BuildProvider { get; set; }
#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();
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();
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();
EnableWebRTC = true; //TODO: From Settings..
_machineProvider = machineProvider;
_machineProvider.MachineConnected += _machineProvider_MachineConnected;
_machineProvider.MachineDisconnected += _machineProvider_MachineDisconnected;
}
#endregion
#region Machine Connection Event Handlers
private async void _machineProvider_MachineDisconnected(object sender, MachineDisconnectedEventArgs e)
{
IsWebRtcAvailable = false;
foreach (var handler in _activeHandlers.ToList())
{
try
{
handler.RaiseFailed(new TransporterDisconnectedException("Machine disconnected."));
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
_activeHandlers.Clear();
if (_webRtcTransporter != null)
{
try
{
LogManager.Log("Machine disconnected. Disconnecting FileSystem WebRTC Transporter...");
await _webRtcTransporter.Disconnect();
}
catch (Exception ex)
{
LogManager.Log(ex, "Error while disconnecting FileSystem WebRTC Transporter.");
}
}
}
private async void _machineProvider_MachineConnected(object sender, MachineConnectedEventArgs e)
{
if (_machineProvider.ConnectionType.IsRemote())
{
try
{
IsWebRtcAvailable = false;
await _machineProvider.MachineOperator.SendGenericRequest(new InitWebRtcRequest()
{
DataChannelName = WEB_RTC_CHANNEL_NAME
}, new TransportRequestConfig()
{
Timeout = TimeSpan.FromSeconds(60),
Priority = QueuePriority.Low
});
_webRtcTransporter = new BasicTransporter(new WebRtcTransportAdapter(_machineProvider.MachineOperator, WebRtcTransportAdapterMode.Active, WEB_RTC_CHANNEL_NAME)
{
EnableCompression = _machineProvider.MachineOperator.Adapter.EnableCompression,
});
_webRtcTransporter.UseKeepAlive = false;
_webRtcTransporter.GenericProtocol = _machineProvider.MachineOperator.GenericProtocol;
_webRtcTransporter.ComponentName = "File System Active WebRTC Transporter";
await _webRtcTransporter.Connect();
IsWebRtcAvailable = true;
LogManager.Log("FileSystem via WebRTC is ready.");
}
catch (Exception ex)
{
IsWebRtcAvailable = false;
LogManager.Log(ex, "Error initializing FileSystem via WebRTC.");
NotificationProvider.PushErrorReportingSnackbar(ex, "PPC Module Warning", "Could not initialize the remote file system P2P channel.", MessageType.Warning);
}
}
}
#endregion
#region Public Methods
///
/// Gets a folder by the specified path.
///
/// The path.
///
public async Task GetFolder(string path)
{
try
{
LogManager.Log($"Retrieving remote folder '{path}'...");
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)
{
try
{
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;
}
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()
{
try
{
LogManager.Log("Retrieving remote root directory (This PC)...");
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 remote file or folder.
/// Indicates whether the remote path is a file.
/// The local target folder or file.
/// Indicates whether the localTargetFolder is a file.
///
public Task Download(FileSystemItem item, String localTargetFolderOrFile, bool isLocalTargetFile = false)
{
AuthenticationProvider.ThrowIfNoPermission(Permissions.FSE_PPCFileSystemRead);
LogManager.Log($"Downloading remote item '{item.Path}' to local path '{localTargetFolderOrFile}'...");
String operationId = String.Empty;
String destination = String.Empty;
long downloadLength = 0;
bool aborted = false;
FileSystemHandler handler = null;
if (isLocalTargetFile)
{
destination = localTargetFolderOrFile;
}
else
{
destination = Path.Combine(localTargetFolderOrFile, 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 for '{item.Name}'.");
}
finally
{
handler.RaiseAborted();
}
}
});
_activeHandlers.Add(handler);
ThreadFactory.StartNew(async () =>
{
try
{
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;
}
else
{
throw new NotSupportedException("The requested file system item is not supported for downloading.");
}
}
catch (Exception ex)
{
LogManager.Log(ex, $"Error downloading remote item '{item.Path}'.");
_activeHandlers.Remove(handler);
handler.RaiseFailed(ex);
return;
}
long position = 0;
bool webRtcFailed = false;
int webRtcRetries = WEB_RTC_MAX_RETRIES;
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)
{
if (handler.IsPaused)
{
Thread.Sleep(1000);
continue;
}
try
{
ChunkDownloadResponse response = null;
ChunkDownloadRequest request = new ChunkDownloadRequest()
{
MaxChunkSize = MAX_CHUNK_SIZE,
OperationId = operationId,
Position = position,
};
if (_webRtcTransporter != null && _webRtcTransporter.State == TransportComponentState.Connected && EnableWebRTC && !webRtcFailed && _machineProvider.ConnectionType == MachineConnectionTypes.SignalR)
{
try
{
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 for '{item.Name}' failed after {WEB_RTC_MAX_RETRIES} retries with exception:\n{ex.FlattenMessage()}\nFalling back to SignalR download...");
}
continue;
}
}
else
{
request.MaxChunkSize = dynamicMaxChunkSizeSignalR;
Stopwatch watch = new Stopwatch();
watch.Start();
response = await _machineProvider.MachineOperator.SendGenericRequest(request, new TransportRequestConfig()
{
Timeout = TimeSpan.FromSeconds(30),
Priority = QueuePriority.Low
});
watch.Stop();
if (watch.Elapsed.TotalSeconds < 1)
{
dynamicMaxChunkSizeSignalR += 1024 * 10;
}
else if (watch.Elapsed.TotalSeconds > 1)
{
dynamicMaxChunkSizeSignalR -= 1024 * 10;
}
dynamicMaxChunkSizeSignalR = Math.Max(dynamicMaxChunkSizeSignalR, MIN_CHUNK_SIZE);
}
using (FileStream fs = new FileStream(tempFile, FileMode.Append))
{
fs.Write(response.Data, 0, response.Data.Length);
}
position += response.Data.Length;
handler.InvalidateProgress(position, downloadLength);
}
catch (Exception ex)
{
LogManager.Log(ex, $"Download failed for '{item.Name}'.");
_activeHandlers.Remove(handler);
tempFile.Delete();
handler.RaiseFailed(ex);
return;
}
}
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);
}
}
else
{
tempFile.Delete();
}
_activeHandlers.Remove(handler);
});
return Task.FromResult(handler);
}
///
/// Downloads the specified file or folder item.
///
/// The remote file or folder.
/// Indicates whether the remote path is a file.
/// The local target folder or file.
/// Indicates whether the localTargetFolder is a file.
///
public Task Download(String remotePath, bool isRemotePathFile, String localTargetFolderOrFile, bool isLocalTargetFile = false)
{
FileSystemItem item = null;
if (isRemotePathFile)
{
item = new FileItem();
}
else
{
item = new FolderItem();
}
item.Path = remotePath;
return Download(item, localTargetFolderOrFile, isLocalTargetFile);
}
///
/// 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 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.
/// Indicates whether this upload operation is performed for a remote upgrade.
///
/// Could not locate the local file or directory to upload.
public Task Upload(String localSourcePath, String remotePath, bool forRemoteUpgrade = false)
{
if (!BuildProvider.IsTwineRSM)
{
if (!forRemoteUpgrade)
{
AuthenticationProvider.ThrowIfNoPermission(Permissions.FSE_PPCFileSystemWrite);
}
else
{
AuthenticationProvider.ThrowIfNoPermission(Permissions.FSE_RemoteUpgradeOnline);
}
}
String operationId = String.Empty;
String destination = remotePath;
bool isFolder = false;
bool aborted = false;
FileSystemItem sourceItem = null;
if (Directory.Exists(localSourcePath))
{
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 '{destination}'...");
sourceItem = new FileItem() { Path = localSourcePath };
isFolder = false;
}
else
{
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)
{
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);
ThreadFactory.StartNew(async () =>
{
try
{
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;
}
if (isFolder)
{
var originalPath = localSourcePath;
localSourcePath = TemporaryManager.CreateImaginaryFile().Path;
LogManager.Log($"Compressing local folder to temporary zip file '{localSourcePath}'...");
ZipFile.CreateFromDirectory(originalPath, localSourcePath);
}
long position = 0;
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))
{
while (position < fs.Length && !aborted)
{
fs.Position = position;
if (handler.IsPaused)
{
Thread.Sleep(1000);
continue;
}
try
{
ChunkUploadResponse response = null;
ChunkUploadRequest request = new ChunkUploadRequest()
{
OperationId = operationId,
};
if (_webRtcTransporter != null && _webRtcTransporter.State == TransportComponentState.Connected && EnableWebRTC && !webRtcFailed && _machineProvider.ConnectionType == MachineConnectionTypes.SignalR)
{
try
{
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;
response = await _webRtcTransporter.SendGenericRequest(request, new TransportRequestConfig()
{
Timeout = request.IsCompleted ? TimeSpan.FromSeconds(120) : 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 upload for '{sourceItem.Name}' failed after {WEB_RTC_MAX_RETRIES} retries with exception:\n{ex.FlattenMessage()}\nFalling back to SignalR upload...");
}
continue;
}
}
else
{
byte[] data = new byte[Math.Min(dynamixMaxChunkSizeSignalR, fs.Length - fs.Position)];
fs.Read(data, 0, data.Length);
request.Data = data;
request.IsCompleted = fs.Position == fs.Length;
Stopwatch watch = new Stopwatch();
watch.Start();
response = await _machineProvider.MachineOperator.SendGenericRequest(request, new TransportRequestConfig()
{
Timeout = request.IsCompleted ? TimeSpan.FromSeconds(120) : TimeSpan.FromSeconds(30),
Priority = QueuePriority.Low
});
watch.Stop();
if (watch.Elapsed.TotalSeconds < 1)
{
dynamixMaxChunkSizeSignalR += 1024 * 10;
}
else if (watch.Elapsed.TotalSeconds > 1)
{
dynamixMaxChunkSizeSignalR -= 1024 * 10;
}
dynamixMaxChunkSizeSignalR = Math.Max(dynamixMaxChunkSizeSignalR, MIN_CHUNK_SIZE);
}
position = fs.Position;
handler.InvalidateProgress(position, fs.Length);
}
catch (Exception ex)
{
LogManager.Log(ex, $"Upload failed for '{sourceItem.Name}'.");
_activeHandlers.Remove(handler);
handler.RaiseFailed(ex);
if (isFolder)
{
try
{
fs.Dispose();
LogManager.Log("Removing temporary zip file...");
File.Delete(localSourcePath);
}
catch { }
}
return;
}
}
if (!aborted)
{
LogManager.Log($"Upload for '{sourceItem.Name}' completed successfully.");
handler.RaiseCompleted();
}
if (isFolder)
{
try
{
LogManager.Log("Removing temporary zip file...");
File.Delete(localSourcePath);
}
catch { }
}
}
}
catch (Exception ex)
{
LogManager.Log(ex, $"Error uploading local item '{sourceItem.Name}'.");
_activeHandlers.Remove(handler);
handler.RaiseFailed(ex);
return;
}
_activeHandlers.Remove(handler);
});
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)
{
AuthenticationProvider.ThrowIfNoPermission(Permissions.FSE_PPCFileSystemWrite);
try
{
LogManager.Log($"Copying remote item '{source.Path}' to '{target.Path}'...");
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)
}, new TransportRequestConfig()
{
Timeout = TimeSpan.FromSeconds(120),
});
}
catch (Exception ex)
{
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)
{
AuthenticationProvider.ThrowIfNoPermission(Permissions.FSE_PPCFileSystemWrite);
try
{
LogManager.Log($"Moving remote item '{source.Path}' to '{target.Path}'...");
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.");
}
await _machineProvider.MachineOperator.SendGenericRequest(new MoveRequest()
{
Source = source.Path,
Destination = Path.Combine(target.Path, source.Name)
}, new TransportRequestConfig()
{
Timeout = TimeSpan.FromSeconds(120),
});
}
catch (Exception ex)
{
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)
{
AuthenticationProvider.ThrowIfNoPermission(Permissions.FSE_PPCFileSystemWrite);
try
{
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)
});
}
catch (Exception ex)
{
throw LogManager.Log(ex, "Error performing rename operation on the remote file system item.");
}
}
///
/// 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)
{
AuthenticationProvider.ThrowIfNoPermission(Permissions.FSE_PPCFileSystemWrite);
try
{
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()
{
Path = item.Path
}, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(120) });
}
catch (Exception ex)
{
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)
{
AuthenticationProvider.ThrowIfNoPermission(Permissions.FSE_PPCFileSystemWrite);
try
{
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;
}
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()
{
AuthenticationProvider.ThrowIfNoPermission(Permissions.FSE_PPCFileSystemRead);
try
{
LogManager.Log("Performing disk space optimization on the remote file system.");
var response = await _machineProvider.MachineOperator.SendGenericRequest(new PerformDiskSpaceOptimizationRequest()
{
}, new TransportRequestConfig()
{
Timeout = TimeSpan.FromMinutes(5)
});
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
}
}