aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Scripting/Tango.Scripting.IDE/Windows/DialogWindow.xaml
diff options
context:
space:
mode:
Diffstat (limited to 'Software/Visual_Studio/Scripting/Tango.Scripting.IDE/Windows/DialogWindow.xaml')
0 files changed, 0 insertions, 0 deletions
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.");
                }
            }
        }
    }
}