Exemple #1
0
        private static void InvokeProgressEvent(uint currentFileSlicesCount, uint currentFileSlice, FileTransferState state)
        {
            if (state == FileTransferState.Finished)
            {
                throw new InvalidOperationException();
            }

            FileTransferProgressEventArgs ea = null;

            if (!isQueue)
            {
                ea = new FileTransferProgressEventArgs {
                    CurrentPart = currentFileSlice + 1, Total = currentFileSlicesCount, State = FileTransferState.DataTransfer, Guid = requestGuid, SenderName = senderName, TotalFiles = filesCount
                };
                System.Diagnostics.Debug.WriteLine(ea.CurrentPart + " / " + ea.Total);
            }
            else if (state == FileTransferState.QueueList)
            {
                ea = new FileTransferProgressEventArgs {
                    CurrentPart = 0, Total = 0, State = FileTransferState.QueueList, Guid = requestGuid, SenderName = senderName, TotalFiles = filesCount
                };
                System.Diagnostics.Debug.WriteLine("Downloading queue data...");
            }
            else
            {
                ea = new FileTransferProgressEventArgs {
                    CurrentPart = (ulong)(queueSlicesFinished + currentFileSlice + 1), Total = (ulong)queueTotalSlices, State = FileTransferState.QueueList, Guid = requestGuid, SenderName = senderName, TotalFiles = filesCount
                };
                System.Diagnostics.Debug.WriteLine(ea.CurrentPart + " / " + ea.Total);
            }

            FileTransferProgress?.Invoke(ea);
        }
Exemple #2
0
        private static async Task ProcessRequest(Dictionary <string, object> request, int fileSenderVersion, IDownloadFolderDecider downloadFolderDecider, Func <string, Task <IFolder> > folderResolver, bool isResume)
        {
            var sessionKey   = Guid.Parse(request["Guid"] as string);
            var ip           = request["ServerIP"].ToString();
            var isCompatible = CompatibilityHelper.IsCompatible(fileSenderVersion, fileReceiverVersion);
            var senderName   = request["SenderName"].ToString();

            if ((!isResume) && (fileSenderVersion >= 2))
            {
                await SendVersionCheckGetRequestAsync(ip, sessionKey, isCompatible);
            }

            if (!isCompatible)
            {
                // TODO
                return;
            }

            currentReceiveSessionAgent = new ReceiveSessionAgent(ip, sessionKey, senderName, downloadFolderDecider, folderResolver);
            currentReceiveSessionAgent.FileTransferProgress += (e) =>
            {
                FileTransferProgress?.Invoke(e);
            };

            currentReceiveSessionAgent.StartReceive(isResume);
            await currentReceiveSessionAgent.ReceiveFinishTcs.Task;
        }
Exemple #3
0
        public static async Task <Dictionary <string, object> > ReceiveRequest(Dictionary <string, object> request, IDownloadFolderDecider downloadFolderDecider)
        {
            Dictionary <string, object> returnVal = new Dictionary <string, object>();

            try
            {
                if ((request.ContainsKey("Type")) && (request["Type"] as string == "QueueInit"))
                {
                    await InitQueue(request, downloadFolderDecider, returnVal);
                }
                else if ((request.ContainsKey("IsQueueItemGroup")) && (request["IsQueueItemGroup"] as string == "true"))
                {
                    await ProcessQueueItemGroup(request, downloadFolderDecider);
                }
                else if ((request.ContainsKey("IsQueueItem")) && (request["IsQueueItem"] as string == "true"))
                {
                    await ProcessQueueItem(request, downloadFolderDecider);
                }
                else
                {
                    await ProcessSingularFile(request, downloadFolderDecider);
                }
            }
            catch (FailedToDownloadException)
            {
                FileTransferProgress?.Invoke(new FileTransferProgressEventArgs
                {
                    Guid  = requestGuid,
                    State = FileTransferState.Error,
                });
            }

            return(returnVal);
        }
Exemple #4
0
        private static async Task BeginProcessingQueue(Func <string[], Task <IFolder> > downloadFolderDecider)
        {
            var downloadFolder = await downloadFolderDecider(queueItems.Select(x => Path.GetExtension((string)x["FileName"])).ToArray());

            string queueParentDirectory2 = await GetUniqueQueueParentDirectory(downloadFolder);

            foreach (var item in queueItems)
            {
                if ((((string)item["Directory"]).Length >= queueParentDirectory.Length) && (((string)item["Directory"]).Substring(0, queueParentDirectory.Length) == queueParentDirectory))
                {
                    if (queueParentDirectory2 != queueParentDirectory)
                    {
                        item["Directory"] = queueParentDirectory2 + ((string)item["Directory"]).Substring(queueParentDirectory.Length);
                    }
                }
                else if (queueParentDirectory.Length > 0)
                {
                    item["Directory"] = Path.Combine(queueParentDirectory2, (string)item["Directory"]);
                }
            }

            var logItems = from x in queueItems
                           select new ReceivedFile
            {
                Name      = (string)x["FileName"],
                Size      = (long)x["FileSize"],
                StorePath = System.IO.Path.Combine(downloadFolder.Path, (string)x["Directory"]),
            };

            await DataStorageProviders.HistoryManager.OpenAsync();

            DataStorageProviders.HistoryManager.Add(requestGuid,
                                                    DateTime.Now,
                                                    senderName,
                                                    new ReceivedFileCollection
            {
                Files         = logItems.ToList(),
                StoreRootPath = System.IO.Path.Combine(downloadFolder.Path, queueParentDirectory2),
            },
                                                    false);
            DataStorageProviders.HistoryManager.Close();

            foreach (var item in queueItems)
            {
                await DownloadFile(item, downloadFolder);
            }

            FileTransferProgress?.Invoke(new FileTransferProgressEventArgs {
                CurrentPart = (ulong)queueTotalSlices, Total = (ulong)queueTotalSlices, State = FileTransferState.Finished, Guid = requestGuid, SenderName = senderName, TotalFiles = filesCount
            });

            await DataStorageProviders.HistoryManager.OpenAsync();

            DataStorageProviders.HistoryManager.ChangeCompletedStatus(requestGuid, true);
            DataStorageProviders.HistoryManager.Close();

            await QueueProcessFinishedNotifySender();
        }
Exemple #5
0
 private static void ServerIPFinder_IPDetectionFailed()
 {
     FileTransferProgress?.Invoke(new FileTransfer2ProgressEventArgs
     {
         State     = FileTransferState.Error,
         Exception = new HandshakeFailedException(),
         Guid      = Guid.NewGuid(),
     });
 }
Exemple #6
0
        private async Task <FileTransferResult> SendFiles(string sessionKey, string ip, FileSendProgressCalculator transferProgress, CancellationToken cancellationToken = default(CancellationToken))
        {
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            SendInitReceiverMessage(transferProgress.TotalSlices, sessionKey, ip, isResume: false);
#pragma warning restore CS4014

            transferProgress.InitTimeout(timeoutTcs);

            var cancellationTcs          = new TaskCompletionSource <FileTransferResult>();
            var cancellationRegistration = cancellationToken.Register(s => ((TaskCompletionSource <FileTransferResult>)s).SetResult(FileTransferResult.Cancelled), cancellationTcs);

            try
            {
                while (true)
                {
                    var result = (await Task.WhenAny(transferTcs.Task, timeoutTcs.Task, cancellationTcs.Task)).Result;
                    if (result == FileTransferResult.Timeout && fileReceiverVersion >= 2)
                    {
                        if (transferProgress.TransferStarted)
                        {
                            // Resume Request
                            FileTransferProgress?.Invoke(this, new FileTransfer2ProgressEventArgs
                            {
                                State = FileTransferState.Reconnecting,
                            });
                            await packageManager.Connect();

                            await Task.Delay(1000); // This is needed otherwise the message won't reach destination (Windows). Why? Idk, ask Project Rome SDK.

#pragma warning disable CS4014                      // Because this call is not awaited, execution of the current method continues before the call is completed
                            SendInitReceiverMessage(transferProgress.TotalSlices, sessionKey, ip, isResume: true);
#pragma warning restore CS4014

                            FileTransferProgress?.Invoke(this, new FileTransfer2ProgressEventArgs
                            {
                                State = FileTransferState.Reconnected,
                            });

                            timeoutTcs = new TaskCompletionSource <FileTransferResult>();
                            transferProgress.InitTimeout(timeoutTcs);
                        }
                        else
                        {
                            return(FileTransferResult.FailedOnPrepare);
                        }
                    }
                    else
                    {
                        return(result);
                    }
                }
            }
            finally
            {
                cancellationRegistration.Dispose();
            }
        }
Exemple #7
0
        private void OnProgressChanged(object sender, FileTransferProgress e)
        {
            Task fileCompressProgressTask = Task.Factory.StartNew(() =>
            {
                ShowTotalProcess = true;
                ValueProgress    = CalcUploadPresignedURClientProgress((int)e.Offset, e.FileSize, ProgressOrigineType.UploadFile);
            });

            fileCompressProgressTask.Wait();
        }
Exemple #8
0
 private static void LegacyFileReceiver_FileTransferProgress(FileTransferProgressEventArgs e)
 {
     FileTransferProgress?.Invoke(new FileTransfer2ProgressEventArgs
     {
         Guid                  = e.Guid,
         SenderName            = e.SenderName,
         State                 = e.State,
         TotalBytes            = e.Total * Constants.FileSliceMaxLength,
         TotalTransferredBytes = e.CurrentPart * Constants.FileSliceMaxLength,
         TotalFiles            = e.TotalFiles,
     });
 }
Exemple #9
0
        /// <summary>
        /// Callback method invoked whenever bytes have been transferred.
        /// </summary>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="e">The event arguments containing the SISession instance for
        /// which bytes have been transferred.</param>
        void OnBytesTransferred(object sender, BytesTransferredEventArgs e)
        {
            // Get the Metadata of the file.
            FileMetaData meta;

            if (metaData.TryGetValue(e.Session.Sid, out meta))
            {
                // Raise the 'FileTransferProgress' event.
                FileTransferProgress.Raise(this, new FileTransferProgressEventArgs(
                                               new FileTransfer(e.Session, meta.Name, meta.Description)));
            }
        }
Exemple #10
0
 private static void InvokeFinishedEvent(uint currentFileSlicesCount)
 {
     if (!isQueue)
     {
         FileTransferProgress?.Invoke(new FileTransferProgressEventArgs {
             CurrentPart = currentFileSlicesCount, Total = currentFileSlicesCount, State = FileTransferState.Finished, Guid = requestGuid, SenderName = senderName, TotalFiles = filesCount
         });
     }
     else
     {
         queueSlicesFinished += (int)currentFileSlicesCount;
     }
 }
        private void DispatchFileTransferProgress(long bytesLoaded, long bytesTotal, string callbackId, bool keepCallback = true)
        {
            Debug.WriteLine("DispatchFileTransferProgress : " + callbackId);
            // send a progress change event
            FileTransferProgress progEvent = new FileTransferProgress(bytesTotal);

            progEvent.BytesLoaded = bytesLoaded;
            PluginResult plugRes = new PluginResult(PluginResult.Status.OK, progEvent);

            plugRes.KeepCallback = keepCallback;
            plugRes.CallbackId   = callbackId;
            DispatchCommandResult(plugRes, callbackId);
        }
Exemple #12
0
        public static async Task <Dictionary <string, object> > ReceiveRequest(Dictionary <string, object> request, IDownloadFolderDecider downloadFolderDecider, Func <string, Task <IFolder> > folderResolver)
        {
            try
            {
                int fileSenderVersion = 2;
                // FileSender v1
                if (!request.ContainsKey("FileSenderVersion") || (int.Parse(request["FileSenderVersion"].ToString()) < 2))
                {
                    fileSenderVersion = 1;
                    return(await ProcessRequestLegacy(request, fileSenderVersion, downloadFolderDecider));
                }

                if (!request.ContainsKey("Type"))
                {
                    throw new InvalidOperationException("Field 'Type' is missing from request.");
                }

                switch (request["Type"] as string)
                {
                case "QueueInit":
                    await ProcessRequest(request, fileSenderVersion, downloadFolderDecider, folderResolver, isResume : false);

                    return(new Dictionary <string, object>());

                case "ResumeReceive":
                    Debug.WriteLine("Received ResumeReceive request. TODO.");
                    if (currentReceiveSessionAgent != null)
                    {
                        currentReceiveSessionAgent.Stop();
                        await Task.Delay(500);
                    }
                    await ProcessRequest(request, fileSenderVersion, downloadFolderDecider, folderResolver, isResume : true);

                    return(new Dictionary <string, object>());

                default:
                    throw new InvalidOperationException($"Type '{request["Type"]}' is invalid.");
                }
            }
            catch (Exception ex)
            {
                FileTransferProgress?.Invoke(new FileTransfer2ProgressEventArgs {
                    State     = FileTransferState.Error,
                    Exception = ex,
                });
                throw ex;
            }
        }
        private async Task StartDownload(QueueInfo queueInfo, string senderName, string ip, Guid sessionKey, bool isResume, CancellationToken cancellationToken)
        {
            IFolder downloadRootFolder;

            if (isResume)
            {
                await DataStorageProviders.HistoryManager.OpenAsync();

                downloadRootFolder = await folderResolver((DataStorageProviders.HistoryManager.GetItem(sessionKey).Data as ReceivedFileCollection).StoreRootPath);

                DataStorageProviders.HistoryManager.Close();
            }
            else
            {
                downloadRootFolder = await downloadFolderDecider.DecideAsync(queueInfo.Files.Select(x => Path.GetExtension(x.FileName)).ToArray());
                await AddToHistory(queueInfo, sessionKey, senderName, downloadRootFolder);
            }
            progressCalculator = new FileReceiveProgressCalculator(queueInfo, queueInfo.Files.First().SliceMaxLength, senderName, sessionKey);
            progressCalculator.FileTransferProgress += ProgressCalculator_FileTransferProgress;

            await queueInfo.Files.ParallelForEachAsync(numberOfParallelDownloads, async item =>
            {
                await DownloadFile(item, downloadRootFolder, ip, sessionKey, cancellationToken);
            });

            await DataStorageProviders.HistoryManager.OpenAsync();

            DataStorageProviders.HistoryManager.ChangeCompletedStatus(sessionKey, true);
            DataStorageProviders.HistoryManager.Close();

            await SendFinishGetRequestAsync(ip, sessionKey);

            FileTransferProgress?.Invoke(new FileTransfer2ProgressEventArgs
            {
                State      = FileTransferState.Finished,
                Guid       = sessionKey,
                TotalFiles = queueInfo.Files.Count,
                SenderName = senderName,
            });

            ReceiveFinishTcs.SetResult(true);
        }
Exemple #14
0
 private void TransferProgress_FileTransferProgress(object sender, FileTransfer2ProgressEventArgs e)
 {
     FileTransferProgress?.Invoke(this, e);
 }
Exemple #15
0
        public virtual async Task <Result> ReceiveFileAsync(
            FileTransfer fileTransfer,
            Socket socket,
            byte[] unreadBytes,
            CancellationToken token)
        {
            var bufferSize     = Settings.SocketSettings.BufferSize;
            var timeoutMs      = Settings.SocketSettings.SocketTimeoutInMilliseconds;
            var updateInterval = Settings.TransferUpdateInterval;
            var buffer         = new byte[bufferSize];

            fileTransfer.Status            = FileTransferStatus.InProgress;
            fileTransfer.TransferStartTime = DateTime.Now;

            EventOccurred?.Invoke(this, new ServerEvent
            {
                EventType              = EventType.ReceiveFileBytesStarted,
                FileTransferId         = fileTransfer.Id,
                RemoteServerIpAddress  = fileTransfer.RemoteServerInfo.SessionIpAddress,
                RemoteServerPortNumber = fileTransfer.RemoteServerInfo.PortNumber,
                FileTransferStartTime  = fileTransfer.TransferStartTime,
                FileName               = fileTransfer.FileName,
                FileSizeInBytes        = fileTransfer.FileSizeInBytes,
                LocalFolder            = fileTransfer.LocalFolderPath,
                RetryCounter           = fileTransfer.RetryCounter,
                RemoteServerRetryLimit = fileTransfer.RemoteServerRetryLimit
            });

            var receiveCount = 0;

            fileTransfer.TotalBytesReceived         = 0;
            fileTransfer.BytesRemaining             = fileTransfer.FileSizeInBytes;
            fileTransfer.PercentComplete            = 0;
            fileTransfer.InboundFileTransferStalled = false;

            if (unreadBytes.Length > 0)
            {
                fileTransfer.TotalBytesReceived += unreadBytes.Length;
                fileTransfer.BytesRemaining     -= unreadBytes.Length;

                lock (FileLock)
                {
                    var writeBytesToFile =
                        FileHelper.WriteBytesToFile(
                            fileTransfer.LocalFilePath,
                            unreadBytes,
                            unreadBytes.Length,
                            10);

                    if (writeBytesToFile.Failure)
                    {
                        return(writeBytesToFile);
                    }
                }

                EventOccurred?.Invoke(this, new ServerEvent
                {
                    EventType = EventType.CopySavedBytesToIncomingFile,
                    CurrentFileBytesReceived = unreadBytes.Length,
                    TotalFileBytesReceived   = fileTransfer.TotalBytesReceived,
                    FileSizeInBytes          = fileTransfer.FileSizeInBytes,
                    FileBytesRemaining       = fileTransfer.BytesRemaining,
                    FileTransferId           = fileTransfer.Id,
                });
            }

            // Read file bytes from transfer socket until
            //      1. the entire file has been received OR
            //      2. Data is no longer being received OR
            //      3, Transfer is canceled
            var receivedZeroBytesFromSocket = false;

            while (!receivedZeroBytesFromSocket)
            {
                if (token.IsCancellationRequested)
                {
                    fileTransfer.Status = FileTransferStatus.Cancelled;
                    fileTransfer.TransferCompleteTime = DateTime.Now;
                    fileTransfer.ErrorMessage         = "Cancellation requested";

                    return(Result.Ok());
                }

                var readFromSocket =
                    await socket.ReceiveWithTimeoutAsync(
                        buffer,
                        0,
                        bufferSize,
                        SocketFlags.None,
                        timeoutMs)
                    .ConfigureAwait(false);

                if (readFromSocket.Failure)
                {
                    return(readFromSocket);
                }

                fileTransfer.CurrentBytesReceived = readFromSocket.Value;
                if (fileTransfer.CurrentBytesReceived == 0)
                {
                    receivedZeroBytesFromSocket = true;
                    continue;
                }

                var receivedBytes = new byte[fileTransfer.CurrentBytesReceived];
                buffer.ToList().CopyTo(0, receivedBytes, 0, fileTransfer.CurrentBytesReceived);

                int fileWriteAttempts;
                lock (FileLock)
                {
                    var writeBytesToFile = FileHelper.WriteBytesToFile(
                        fileTransfer.LocalFilePath,
                        receivedBytes,
                        fileTransfer.CurrentBytesReceived,
                        999);

                    if (writeBytesToFile.Failure)
                    {
                        return(writeBytesToFile);
                    }

                    fileWriteAttempts = writeBytesToFile.Value + 1;
                }

                receiveCount++;
                fileTransfer.TotalBytesReceived += fileTransfer.CurrentBytesReceived;
                fileTransfer.BytesRemaining     -= fileTransfer.CurrentBytesReceived;
                var checkPercentComplete  = fileTransfer.TotalBytesReceived / (float)fileTransfer.FileSizeInBytes;
                var changeSinceLastUpdate = checkPercentComplete - fileTransfer.PercentComplete;

                if (fileWriteAttempts > 1)
                {
                    EventOccurred?.Invoke(this, new ServerEvent
                    {
                        EventType         = EventType.MultipleFileWriteAttemptsNeeded,
                        FileWriteAttempts = fileWriteAttempts,
                        PercentComplete   = fileTransfer.PercentComplete,
                        FileTransferId    = fileTransfer.Id,
                    });
                }

                // this event fires on every socket read event, which could be hurdreds of thousands
                // of times depending on the file size and buffer size. Since this  event is only used
                // by myself when debugging small test files, I limited this event to only fire when
                // the size of the file will result in 10 socket read events at most.
                if (fileTransfer.FileSizeInBytes <= 10 * bufferSize)
                {
                    SocketEventOccurred?.Invoke(this, new ServerEvent
                    {
                        EventType                = EventType.ReceivedFileBytesFromSocket,
                        SocketReadCount          = receiveCount,
                        BytesReceivedCount       = fileTransfer.CurrentBytesReceived,
                        CurrentFileBytesReceived = fileTransfer.CurrentBytesReceived,
                        TotalFileBytesReceived   = fileTransfer.TotalBytesReceived,
                        FileSizeInBytes          = fileTransfer.FileSizeInBytes,
                        FileBytesRemaining       = fileTransfer.BytesRemaining,
                        PercentComplete          = fileTransfer.PercentComplete,
                        FileTransferId           = fileTransfer.Id
                    });
                }

                // Report progress in intervals which are set by the user in the settings file
                if (changeSinceLastUpdate < updateInterval)
                {
                    continue;
                }

                fileTransfer.PercentComplete = checkPercentComplete;

                FileTransferProgress?.Invoke(this, new ServerEvent
                {
                    EventType = EventType.UpdateFileTransferProgress,
                    TotalFileBytesReceived = fileTransfer.TotalBytesReceived,
                    PercentComplete        = fileTransfer.PercentComplete,
                    FileTransferId         = fileTransfer.Id
                });
            }

            var fileTransferIsIncomplete = (fileTransfer.TotalBytesReceived / (float)fileTransfer.FileSizeInBytes) < 1;

            if (fileTransfer.InboundFileTransferStalled || fileTransferIsIncomplete)
            {
                const string fileTransferStalledErrorMessage =
                    "Data is no longer bring received from remote client, file transfer has been canceled (ReceiveFileAsync)";

                fileTransfer.Status       = FileTransferStatus.Stalled;
                fileTransfer.ErrorMessage = fileTransferStalledErrorMessage;

                return(Result.Ok());
            }

            fileTransfer.Status = FileTransferStatus.ConfirmedComplete;
            fileTransfer.TransferCompleteTime = DateTime.Now;
            fileTransfer.PercentComplete      = 1;
            fileTransfer.CurrentBytesReceived = 0;
            fileTransfer.BytesRemaining       = 0;

            EventOccurred?.Invoke(this, new ServerEvent
            {
                EventType                = EventType.ReceiveFileBytesComplete,
                FileTransferStartTime    = fileTransfer.TransferStartTime,
                FileTransferCompleteTime = DateTime.Now,
                FileSizeInBytes          = fileTransfer.FileSizeInBytes,
                FileTransferRate         = fileTransfer.TransferRate,
                RemoteServerIpAddress    = fileTransfer.RemoteServerInfo.SessionIpAddress,
                RemoteServerPortNumber   = fileTransfer.RemoteServerInfo.PortNumber,
                FileTransferId           = fileTransfer.Id
            });

            return(Result.Ok());
        }
 private void DispatchFileTransferProgress(long bytesLoaded, long bytesTotal, string callbackId, bool keepCallback = true)
 {
     Debug.WriteLine("DispatchFileTransferProgress : " + callbackId);
     // send a progress change event
     FileTransferProgress progEvent = new FileTransferProgress(bytesTotal);
     progEvent.BytesLoaded = bytesLoaded;
     PluginResult plugRes = new PluginResult(PluginResult.Status.OK, progEvent);
     plugRes.KeepCallback = keepCallback;
     plugRes.CallbackId = callbackId;
     DispatchCommandResult(plugRes, callbackId);
 }
 private void ProgressCalculator_FileTransferProgress(object sender, FileTransfer2ProgressEventArgs e)
 {
     FileTransferProgress?.Invoke(e);
 }
Exemple #18
0
 void HandleFileTransferProgress(object sender, ServerEvent serverEvent)
 {
     _eventLog.Add(serverEvent);
     FileTransferProgress?.Invoke(sender, serverEvent);
 }
        public virtual async Task <Result> SendFileAsync(FileTransfer fileTransfer, Socket socket, CancellationToken token)
        {
            var bufferSize     = Settings.SocketSettings.BufferSize;
            var timeoutMs      = Settings.SocketSettings.SocketTimeoutInMilliseconds;
            var updateInterval = Settings.TransferUpdateInterval;

            fileTransfer.Status            = FileTransferStatus.InProgress;
            fileTransfer.TransferStartTime = DateTime.Now;

            EventOccurred?.Invoke(this, new ServerEvent
            {
                EventType              = EventType.SendFileBytesStarted,
                RemoteServerIpAddress  = fileTransfer.RemoteServerInfo.SessionIpAddress,
                RemoteServerPortNumber = fileTransfer.RemoteServerInfo.PortNumber,
                FileTransferId         = fileTransfer.Id
            });

            fileTransfer.BytesRemaining              = fileTransfer.FileSizeInBytes;
            fileTransfer.FileChunkSentCount          = 0;
            fileTransfer.OutboundFileTransferStalled = false;

            using (var file = File.OpenRead(fileTransfer.LocalFilePath))
            {
                while (fileTransfer.BytesRemaining > 0)
                {
                    if (token.IsCancellationRequested)
                    {
                        fileTransfer.Status = FileTransferStatus.Cancelled;
                        fileTransfer.TransferCompleteTime = DateTime.Now;
                        fileTransfer.ErrorMessage         = "Cancellation requested";

                        return(Result.Ok());
                    }

                    var fileChunkSize = (int)Math.Min(bufferSize, fileTransfer.BytesRemaining);
                    var buffer        = new byte[fileChunkSize];

                    var numberOfBytesToSend = file.Read(buffer, 0, fileChunkSize);
                    fileTransfer.BytesRemaining -= numberOfBytesToSend;

                    var offset          = 0;
                    var socketSendCount = 0;
                    while (numberOfBytesToSend > 0)
                    {
                        var sendFileChunkResult =
                            await socket.SendWithTimeoutAsync(
                                buffer,
                                offset,
                                fileChunkSize,
                                SocketFlags.None,
                                timeoutMs).ConfigureAwait(false);

                        if (fileTransfer.OutboundFileTransferStalled)
                        {
                            const string fileTransferStalledErrorMessage =
                                "Aborting file transfer, client says that data is no longer being received (SendFileBytesAsync)";

                            fileTransfer.Status = FileTransferStatus.Cancelled;
                            fileTransfer.TransferCompleteTime = DateTime.Now;
                            fileTransfer.ErrorMessage         = fileTransferStalledErrorMessage;

                            return(Result.Ok());
                        }

                        if (sendFileChunkResult.Failure)
                        {
                            return(sendFileChunkResult);
                        }

                        fileTransfer.CurrentBytesSent = sendFileChunkResult.Value;
                        numberOfBytesToSend          -= fileTransfer.CurrentBytesSent;
                        offset += fileTransfer.CurrentBytesSent;
                        socketSendCount++;
                    }

                    fileTransfer.CurrentBytesSent = fileChunkSize;
                    fileTransfer.FileChunkSentCount++;

                    var checkPercentRemaining = fileTransfer.BytesRemaining / (float)fileTransfer.FileSizeInBytes;
                    var checkPercentComplete  = 1 - checkPercentRemaining;
                    var changeSinceLastUpdate = checkPercentComplete - fileTransfer.PercentComplete;

                    // this event fires on every file chunk sent event, which could be hurdreds of thousands
                    // of times depending on the file size and buffer size. Since this  event is only used
                    // by myself when debugging small test files, I limited this event to only fire when
                    // the size of the file will result in 10 file chunk sent events at most.
                    if (fileTransfer.FileSizeInBytes <= 10 * bufferSize)
                    {
                        SocketEventOccurred?.Invoke(this, new ServerEvent
                        {
                            EventType            = EventType.SentFileChunkToRemoteServer,
                            FileSizeInBytes      = fileTransfer.FileSizeInBytes,
                            CurrentFileBytesSent = fileChunkSize,
                            FileBytesRemaining   = fileTransfer.BytesRemaining,
                            FileChunkSentCount   = fileTransfer.FileChunkSentCount,
                            SocketSendCount      = socketSendCount,
                            FileTransferId       = fileTransfer.Id
                        });
                    }

                    // Report progress in intervals which are set by the user in the settings file
                    if (changeSinceLastUpdate < updateInterval)
                    {
                        continue;
                    }
                    fileTransfer.PercentComplete = checkPercentComplete;

                    FileTransferProgress?.Invoke(this, new ServerEvent
                    {
                        EventType = EventType.UpdateFileTransferProgress,
                        TotalFileBytesReceived = fileTransfer.TotalBytesReceived,
                        PercentComplete        = fileTransfer.PercentComplete,
                        FileTransferId         = fileTransfer.Id
                    });
                }

                fileTransfer.Status = FileTransferStatus.TransferComplete;
                fileTransfer.TransferCompleteTime = DateTime.Now;
                fileTransfer.PercentComplete      = 1;
                fileTransfer.CurrentBytesSent     = 0;
                fileTransfer.BytesRemaining       = 0;

                EventOccurred?.Invoke(this, new ServerEvent
                {
                    EventType              = EventType.SendFileBytesComplete,
                    RemoteServerIpAddress  = fileTransfer.RemoteServerInfo.SessionIpAddress,
                    RemoteServerPortNumber = fileTransfer.RemoteServerInfo.PortNumber,
                    FileTransferId         = fileTransfer.Id,
                });

                return(Result.Ok());
            }
        }
Exemple #20
0
        /// <param name="files">A list of Tuple(Relative directory path, StorageFile) objects.</param>
        public async Task <FileTransferResult> SendQueue(CancellationToken cancellationToken, List <Tuple <string, IFile> > files, string parentDirectoryName)
        {
            if ((ipFinderResult == null) || (ipFinderResult.Success == false))
            {
                await Handshake();

                if (ipFinderResult == null)
                {
                    ipFinderResult = new IPDetectionCompletedEventArgs
                    {
                        Success = false,
                    }
                }
                ;
            }

            if (ipFinderResult.Success == false)
            {
                return(FileTransferResult.FailedOnHandshake);
            }


            InitServer();

            Dictionary <IFile, string> sFileKeyPairs = new Dictionary <IFile, string>();

            IFileStats[] fs = new IFileStats[files.Count];

            ulong totalSlices = 0;

            for (int i = 0; i < files.Count; i++)
            {
                var item = files[i];

                var key = GenerateUniqueRandomKey();

                fs[i] = await item.Item2.GetFileStats();

                var slicesCount = (uint)Math.Ceiling(((double)fs[i].Length) / ((double)Constants.FileSliceMaxLength));

                totalSlices += slicesCount;

                keyTable.Add(key, new FileDetails
                {
                    storageFile       = item.Item2,
                    lastPieceAccessed = 0,
                    lastSliceSize     = (uint)((ulong)fs[i].Length % Constants.FileSliceMaxLength),
                    lastSliceId       = slicesCount - 1
                });

                sFileKeyPairs.Add(item.Item2, key);

                InitUrls(key, slicesCount);
            }

            var queueFinishKey = RandomFunctions.RandomString(15);

            server.AddResponseUrl("/" + queueFinishKey + "/finishQueue/", (Func <IWebServer, RequestDetails, string>)QueueFinished);
            System.Diagnostics.Debug.WriteLine("/" + queueFinishKey + "/finishQueue/");

            queueFinishTcs = new TaskCompletionSource <string>();
            fileSendTcs    = null;

            ulong finishedSlices = 0;

            ClearInternalEventSubscribers();
            FileTransferProgressInternal += (s, ee) =>
            {
                FileTransferProgress?.Invoke(s, new FileTransferProgressEventArgs
                {
                    State       = ee.State,
                    CurrentPart = finishedSlices + ee.CurrentPart,
                    Total       = totalSlices
                });

                if (ee.State == FileTransferState.Finished)
                {
                    finishedSlices += ee.Total;
                }
            };

            cancellationToken.Register(() =>
            {
                queueFinishTcs?.TrySetResult(TRANSFER_CANCELLED_MESSAGE);
                server?.Dispose();
            });

            if (await SendQueueInit(totalSlices, queueFinishKey, parentDirectoryName) == false)
            {
                return(FileTransferResult.FailedOnQueueInit);
            }

            bool infoSendResult = await SendQueueInfo(files, sFileKeyPairs, fs);

            return(await WaitQueueToFinish(cancellationToken));
        }
Exemple #21
0
        public async Task <FileTransferResult> SendFile(CancellationToken cancellationToken, IFile file, string directory = "", bool isQueue = false)
        {
            if ((ipFinderResult == null) || (ipFinderResult.Success == false))
            {
                await Handshake();

                if (ipFinderResult == null)
                {
                    ipFinderResult = new IPDetectionCompletedEventArgs
                    {
                        Success = false,
                    }
                }
                ;
            }

            if (ipFinderResult.Success == false)
            {
                return(FileTransferResult.FailedOnHandshake);
            }

            InitServer();

            var key = GenerateUniqueRandomKey();

            var properties = await file.GetFileStats();

            var slicesCount = (uint)Math.Ceiling(((double)properties.Length) / ((double)Constants.FileSliceMaxLength));

            keyTable.Add(key, new FileDetails
            {
                storageFile       = file,
                lastPieceAccessed = 0,
                lastSliceSize     = (uint)((ulong)properties.Length % Constants.FileSliceMaxLength),
                lastSliceId       = slicesCount - 1
            });

            InitUrls(key, slicesCount);

            queueFinishTcs = null;
            fileSendTcs    = new TaskCompletionSource <string>();

            ClearInternalEventSubscribers();
            FileTransferProgressInternal += (s, ee) =>
            {
                FileTransferProgress?.Invoke(s, ee);
            };

            cancellationToken.Register(() =>
            {
                fileSendTcs?.TrySetResult(TRANSFER_CANCELLED_MESSAGE);
                server?.Dispose();
            });

            if (!(await BeginSending(key, slicesCount, file.Name, properties, directory, false)))
            {
                return(FileTransferResult.FailedOnPrepare);
            }

            return(await WaitForFinish(cancellationToken));
        }