// files must be a list to make the function predictable. (As we modify the FileSendInfo objects by calling their InitSlicingAsync() funciton) public async Task <FileTransferResult> Send(List <FileSendInfo> files, CancellationToken cancellationToken = default(CancellationToken)) { IWebServer server = null; var transferProgress = new FileSendProgressCalculator(Constants.FileSliceMaxLength); transferProgress.FileTransferProgress += TransferProgress_FileTransferProgress; try { transferTcs = new TaskCompletionSource <FileTransferResult>(); timeoutTcs = new TaskCompletionSource <FileTransferResult>(); var sessionKey = Guid.NewGuid().ToString(); var myIp = await handshaker.Handshake(cancellationToken); if (myIp.Length == 0) { return(FileTransferResult.FailedOnHandshake); } if (cancellationToken.IsCancellationRequested) { return(FileTransferResult.Cancelled); } server = InitServer(myIp, Constants.CommunicationPort); await InitFileReceiveEndpoints(server, files, transferProgress, cancellationToken); await InitGenericEndpoints(server, sessionKey, myIp, files, cancellationToken); if (cancellationToken.IsCancellationRequested) { return(FileTransferResult.Cancelled); } return(await SendFiles(sessionKey, myIp, transferProgress, cancellationToken)); } finally { transferProgress.FileTransferProgress -= TransferProgress_FileTransferProgress; server?.Dispose(); } }
private async Task InitFileReceiveEndpoints(IWebServer server, FileSendInfo fileInfo, FileSendProgressCalculator transferProgress) { await fileInfo.InitSlicingAsync(); var 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 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(); } }
private async Task InitFileReceiveEndpoints(IWebServer server, IEnumerable <FileSendInfo> files, FileSendProgressCalculator transferProgress, CancellationToken cancellationToken = default(CancellationToken)) { foreach (var item in files) { await InitFileReceiveEndpoints(server, item, transferProgress); if (cancellationToken.IsCancellationRequested) { return; } } var list = files.ToList(); }