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.BL.Enumerations; using Tango.Core; using Tango.Core.DI; using Tango.Core.Threading; using Tango.FileSystem; using Tango.FSE.Common.Authentication; using Tango.FSE.Common.Connection; using Tango.FSE.Common.FileSystem; using Tango.FSE.Common.Firmware; using Tango.FSE.Common.Notifications; using Tango.Integration.Storage; namespace Tango.FSE.UI.Firmware { [TangoCreateWhenRegistered] public class DefaultFirmwareStorageProvider : ExtendedObject, IFirmwareStorageProvider { private StorageManager _manager; private IMachineProvider _machineProvider; private List _activeHandlers; private StorageDrive _storageDrive; [TangoInject] private INotificationProvider NotificationProvider { get; set; } [TangoInject] private IAuthenticationProvider AuthenticationProvider { get; set; } public DefaultFirmwareStorageProvider(IMachineProvider machineProvider) { _activeHandlers = new List(); _machineProvider = machineProvider; _manager = machineProvider.MachineOperator.CreateStorageManager(); machineProvider.MachineConnected += MachineProvider_MachineConnected; } private void MachineProvider_MachineConnected(object sender, MachineConnectedEventArgs e) { _manager = e.MachineOperator.CreateStorageManager(); } public async Task GetFolder(string path) { try { LogManager.Log($"Retrieving remote firmware folder '{path}'..."); var storageFolder = await _manager.GetFolder(path); var folderItem = storageFolder.ToFileSystemItem() as IFileSystemContainer; if (_storageDrive != null) { if ((folderItem as FolderItem).Path == _storageDrive.Root) { (folderItem as FolderItem).IsRoot = true; } } return folderItem; } catch (Exception ex) { throw LogManager.Log(ex, "Error retrieving remote firmware folder."); } } public async Task GetRoot() { _storageDrive = await _manager.GetStorageDrive(); return await GetFolder(_storageDrive.Root); } public Task Download(FileItem item, string localTargetPath) { AuthenticationProvider.ThrowIfNoPermission(Permissions.FSE_FirmwareFileSystemRead); LogManager.Log($"Downloading remote firmware item '{item.Path}' to local path '{localTargetPath}'..."); bool aborted = false; FileSystemHandler handler = null; StorageFileHandler storageHandler = null; handler = new FileSystemHandler(FileSystemHandlerType.FileDownload, item, localTargetPath, async () => { if (!aborted) { LogManager.Log($"Download aborted by user for '{item.Name}'. Aborting download..."); aborted = true; try { LogManager.Log("Aborting download operation..."); await storageHandler.Cancel(); 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); handler.IsPausedChanged += (_, __) => { if (storageHandler != null) { storageHandler.IsPaused = handler.IsPaused; } }; ThreadFactory.StartNew(async () => { FileStream fileStream = null; try { TaskCompletionSource completion = new TaskCompletionSource(); fileStream = new FileStream(localTargetPath, FileMode.Create); storageHandler = await _manager.DownloadFile(item.ToStorageItem() as StorageFile, fileStream); storageHandler.Progress += (_, e) => { handler.InvalidateProgress(e.Current, e.Total); }; storageHandler.Canceled += (_, e) => { completion.SetException(new OperationCanceledException()); }; storageHandler.Failed += (_, ex) => { completion.SetException(ex); }; storageHandler.Completed += (_, e) => { LogManager.Log($"'{item.Name}' downloaded successfully."); try { fileStream?.Dispose(); } catch { } handler.RaiseCompleted(); completion.SetResult(true); }; await completion.Task; } catch (OperationCanceledException) { handler.RaiseAborted(); } catch (Exception ex) { LogManager.Log(ex, $"Download failed for '{item.Name}'."); handler.RaiseFailed(ex); } finally { _activeHandlers.Remove(handler); try { fileStream?.Dispose(); } catch { } } }); return Task.FromResult(handler); } public Task Upload(string localSourcePath, string remoteTargetPath) { AuthenticationProvider.ThrowIfNoPermission(Permissions.FSE_FirmwareFileSystemWrite); LogManager.Log($"Uploading file '{localSourcePath}' to remote path '{remoteTargetPath}'..."); bool aborted = false; FileSystemHandler handler = null; StorageFileHandler storageHandler = null; var item = new FileItem() { Path = localSourcePath }; handler = new FileSystemHandler(FileSystemHandlerType.FileUpload, item, remoteTargetPath, async () => { if (!aborted) { LogManager.Log($"Upload aborted by user for '{item.Name}'. Aborting download..."); aborted = true; try { LogManager.Log("Aborting upload operation..."); await storageHandler.Cancel(); LogManager.Log($"Upload operation for '{item.Name} 'aborted successfully."); } catch (Exception ex) { LogManager.Log(ex, $"Error aborting the upload operation for '{item.Name}'."); } finally { handler.RaiseAborted(); } } }); handler.IsPausedChanged += (_, __) => { if (storageHandler != null) { storageHandler.IsPaused = handler.IsPaused; } }; _activeHandlers.Add(handler); ThreadFactory.StartNew(async () => { FileStream fileStream = null; try { TaskCompletionSource completion = new TaskCompletionSource(); fileStream = new FileStream(localSourcePath, FileMode.Open); storageHandler = await _manager.UploadFile(remoteTargetPath, fileStream); storageHandler.Progress += (_, e) => { handler.InvalidateProgress(e.Current, e.Total); }; storageHandler.Canceled += (_, e) => { completion.SetException(new OperationCanceledException()); }; storageHandler.Failed += (_, ex) => { completion.SetException(ex); }; storageHandler.Completed += (_, e) => { LogManager.Log($"'{item.Name}' uploaded successfully."); try { fileStream?.Dispose(); } catch { } handler.RaiseCompleted(); completion.SetResult(true); }; await completion.Task; } catch (OperationCanceledException) { handler.RaiseAborted(); } catch (Exception ex) { LogManager.Log(ex, $"Upload failed for '{item.Name}'."); handler.RaiseFailed(ex); } finally { _activeHandlers.Remove(handler); try { fileStream?.Dispose(); } catch { } } }); return Task.FromResult(handler); } public Task Delete(FileSystemItem item) { AuthenticationProvider.ThrowIfNoPermission(Permissions.FSE_FirmwareFileSystemWrite); try { return _manager.DeleteItem(item.ToStorageItem()); } catch (Exception ex) { throw LogManager.Log(ex, $"Error deleting firmware file system item '{item.Path}'."); } } public async Task CreateFolder(FileSystemItem parent, string folderName) { AuthenticationProvider.ThrowIfNoPermission(Permissions.FSE_FirmwareFileSystemWrite); try { String remotePath = Path.Combine(parent.Path, folderName); await _manager.CreateFolder(remotePath); var storageFolder = await _manager.GetFolder(remotePath); return storageFolder.ToFileSystemItem() as FolderItem; } catch (Exception ex) { throw LogManager.Log(ex, $"Error creating folder '{folderName}' on remote firmware device."); } } } internal static class ExtensionMethods { internal static FileSystemItem ToFileSystemItem(this StorageItem storageItem) { FileSystemItem item = null; if (storageItem.GetType() == typeof(StorageDrive)) { item = new DriveItem(); (item as DriveItem).Path = (storageItem as StorageDrive).Root; (item as DriveItem).Label = "Root"; (item as DriveItem).DriveType = System.IO.DriveType.Fixed; } else if (storageItem.GetType() == typeof(StorageFolder)) { item = new FolderItem(); (item as FolderItem).Path = (storageItem as StorageFolder).Path; (item as FolderItem).Items = (storageItem as StorageFolder).Items.Select(x => x.ToFileSystemItem()).ToObservableCollection(); (item as FolderItem).IsRoot = (item as FolderItem).Path.Length == 1; } else if (storageItem.GetType() == typeof(StorageFile)) { item = new FileItem(); (item as FileItem).Path = (storageItem as StorageFile).Path; (item as FileItem).Size = (storageItem as StorageFile).Length; } item.DateCreated = storageItem.LastModified; item.DateCreated = storageItem.LastModified; return item; } internal static StorageItem ToStorageItem(this FileSystemItem fileSystemItem) { StorageItem item = null; if (fileSystemItem.GetType() == typeof(DriveItem)) { item = new StorageDrive(); (item as StorageDrive).Root = (fileSystemItem as DriveItem).Path; } else if (fileSystemItem.GetType() == typeof(FolderItem)) { item = new StorageFolder(); (item as StorageFolder).Path = (fileSystemItem as FolderItem).Path; (item as StorageFolder).Items = new ReadOnlyCollection((fileSystemItem as FolderItem).Items.Select(x => x.ToStorageItem()).ToList()); (item as StorageFolder).LastModified = (fileSystemItem as FolderItem).DateModified; (item as StorageFolder).Attribute = PMR.IO.FileAttribute.Directory; } else if (fileSystemItem.GetType() == typeof(FileItem)) { item = new StorageFile(); (item as StorageFile).Path = (fileSystemItem as FileItem).Path; (item as StorageFile).Length = (fileSystemItem as FileItem).Size; (item as StorageFile).LastModified = (fileSystemItem as FileItem).DateModified; (item as StorageFile).Attribute = PMR.IO.FileAttribute.Archive; } return item; } } }