private async Task InitFileReceiveEndpoints(IWebServer server, FileSendInfo fileInfo, FileSendProgressCalculator transferProgress) { await fileInfo.InitSlicingAsync(); fileSliceSender = new FileSliceSender(fileInfo); transferProgress.AddFileSliceSender(fileSliceSender); fileSliceSender.SliceRequested += transferProgress.SliceRequestReceived; for (int i = 0; i < fileInfo.SlicesCount; i++) { server.AddResponseUrl($"/{fileInfo.UniqueKey}/{i}/", (Func <IWebServer, RequestDetails, Task <byte[]> >)fileSliceSender.GetFileSlice); } }
private static async Task <IFile> CreateFile(FileSendInfo fileInfo, Guid sessionKey, IFolder downloadFolder) { var file = await FileHelper.CreateFile(downloadFolder, fileInfo.FileName); if (file.Name != fileInfo.FileName) //File already existed, so new name generated for it. We should update database now. { await DataStorageProviders.HistoryManager.OpenAsync(); DataStorageProviders.HistoryManager.UpdateFileName(sessionKey, fileInfo.FileName, file.Name, downloadFolder.Path); DataStorageProviders.HistoryManager.Close(); } return(file); }
private async Task DownloadFile(FileSendInfo fileInfo, IFolder downloadRootFolder, string serverIp, Guid sessionKey, CancellationToken cancellationToken) { //TODO: Add a semaphore or sth to make sure two threads don't start writing on one file. IFolder downloadFolder = await FileHelper.CreateDirectoryIfNecessary(downloadRootFolder, fileInfo.RelativePath); await DataStorageProviders.HistoryManager.OpenAsync(); var origFile = DataStorageProviders.HistoryManager.GetFileFromOriginalName(guid: sessionKey, originalFileName: fileInfo.FileName, path: downloadFolder.Path); DataStorageProviders.HistoryManager.Close(); IFile file; uint firstSliceToReceive = 0; if (origFile.DownloadStarted == false) { file = await CreateFile(fileInfo, sessionKey, downloadFolder); } else if (origFile.Completed == true) { return; } else { file = await FileHelper.GetFile(downloadFolder, origFile.Name); var stats = await file.GetFileStats(); if (stats.Length == (long)(fileInfo.SlicesCount * fileInfo.SliceMaxLength + fileInfo.LastSliceSize)) { //It's already finished. await DataStorageProviders.HistoryManager.OpenAsync(); DataStorageProviders.HistoryManager.MarkFileAsCompleted(sessionKey, file.Name, downloadFolder.Path); DataStorageProviders.HistoryManager.Close(); return; } else if (stats.Length % (long)fileInfo.SliceMaxLength != 0) { //Invalid size. Will start over. await file.DeleteAsync(); file = await CreateFile(fileInfo, sessionKey, downloadFolder); firstSliceToReceive = 0; } else { firstSliceToReceive = (uint)(stats.Length / (long)fileInfo.SliceMaxLength); if (firstSliceToReceive > 0) { progressCalculator.SliceReceived(fileInfo, firstSliceToReceive - 1); } } } ulong totalBytesReceived = 0; using (var stream = await file.OpenAsync(PCLStorage.FileAccess.ReadAndWrite)) { stream.Seek(stream.Length, SeekOrigin.Begin); await DataStorageProviders.HistoryManager.OpenAsync(); DataStorageProviders.HistoryManager.SetDownloadStarted(sessionKey, file.Name, downloadFolder.Path); DataStorageProviders.HistoryManager.Close(); for (uint i = firstSliceToReceive; i < fileInfo.SlicesCount; i++) { string url = $"http://{serverIp}:{Constants.CommunicationPort}/{fileInfo.UniqueKey}/{i}/"; if (cancellationToken.IsCancellationRequested) { throw new ReceiveCancelledException(); } byte[] buffer = await HttpHelper.DownloadDataFromUrl(url, cancellationToken : cancellationToken); if (cancellationToken.IsCancellationRequested) { throw new ReceiveCancelledException(); } int expectedLength; if (i == (fileInfo.SlicesCount - 1)) { expectedLength = (int)(fileInfo.FileSize % fileInfo.SliceMaxLength); } else { expectedLength = (int)fileInfo.SliceMaxLength; } if (buffer.Length != expectedLength) { Debug.WriteLine("Slice length violation! Will retry..."); i--; continue; } await stream.WriteAsync(buffer, 0, buffer.Length); await stream.FlushAsync(); totalBytesReceived += (ulong)expectedLength; progressCalculator.SliceReceived(fileInfo, i); } } await DataStorageProviders.HistoryManager.OpenAsync(); DataStorageProviders.HistoryManager.MarkFileAsCompleted(sessionKey, file.Name, downloadFolder.Path); DataStorageProviders.HistoryManager.Close(); }
internal void SliceReceived(FileSendInfo file, uint receivedSlice) { SliceReceived(file.UniqueKey, receivedSlice); }