/// <summary> /// Invoked upon a remote request to download a file. /// </summary> /// <param name="username">The username of the requesting user.</param> /// <param name="endpoint">The IP endpoint of the requesting user.</param> /// <param name="filename">The filename of the requested file.</param> /// <param name="tracker">(for example purposes) the ITransferTracker used to track progress.</param> /// <returns>A Task representing the asynchronous operation.</returns> /// <exception cref="DownloadEnqueueException">Thrown when the download is rejected. The Exception message will be passed to the remote user.</exception> /// <exception cref="Exception">Thrown on any other Exception other than a rejection. A generic message will be passed to the remote user for security reasons.</exception> private Task EnqueueDownloadAction(string username, IPEndPoint endpoint, string filename, ITransferTracker tracker) { filename = filename.ToLocalOSPath(); var fileInfo = new FileInfo(filename); if (!fileInfo.Exists) { Console.WriteLine($"[UPLOAD REJECTED] File {filename} not found."); throw new DownloadEnqueueException($"File not found."); } // create a new cancellation token source so that we can cancel the upload from the UI. var cts = new CancellationTokenSource(); var topts = new TransferOptions(stateChanged: (e) => tracker.AddOrUpdate(e, cts), progressUpdated: (e) => tracker.AddOrUpdate(e, cts)); // accept all download requests, and begin the upload immediately. // normally there would be an internal queue, and uploads would be handled separately. Task.Run(async() => { using (var stream = new FileStream(fileInfo.FullName, FileMode.Open)) { await Client.UploadAsync(username, fileInfo.FullName, fileInfo.Length, stream, options: topts, cancellationToken: cts.Token); } }).ContinueWith(t => { Console.WriteLine($"[UPLOAD FAILED] {t.Exception}"); }, TaskContinuationOptions.NotOnRanToCompletion); // fire and forget // return a completed task so that the invoking code can respond to the remote client. return(Task.CompletedTask); }
/// <summary> /// Invoked upon a remote request to download a file. /// </summary> /// <param name="username">The username of the requesting user.</param> /// <param name="endpoint">The IP endpoint of the requesting user.</param> /// <param name="filename">The filename of the requested file.</param> /// <param name="tracker">(for example purposes) the ITransferTracker used to track progress.</param> /// <returns>A Task representing the asynchronous operation.</returns> /// <exception cref="DownloadEnqueueException">Thrown when the download is rejected. The Exception message will be passed to the remote user.</exception> /// <exception cref="Exception">Thrown on any other Exception other than a rejection. A generic message will be passed to the remote user for security reasons.</exception> private Task EnqueueDownloadAction(string username, IPEndPoint endpoint, string filename, ITransferTracker tracker) { _ = endpoint; filename = filename.ToLocalOSPath(); var fileInfo = new FileInfo(filename); if (!fileInfo.Exists) { Console.WriteLine($"[UPLOAD REJECTED] File {filename} not found."); throw new DownloadEnqueueException($"File not found."); } if (tracker.TryGet(TransferDirection.Upload, username, filename, out _)) { // in this case, a re-requested file is a no-op. normally we'd want to respond with a // PlaceInQueueResponse Console.WriteLine($"[UPLOAD RE-REQUESTED] [{username}/{filename}]"); return(Task.CompletedTask); } // create a new cancellation token source so that we can cancel the upload from the UI. var cts = new CancellationTokenSource(); var topts = new TransferOptions(stateChanged: (e) => tracker.AddOrUpdate(e, cts), progressUpdated: (e) => tracker.AddOrUpdate(e, cts), governor: (t, c) => Task.Delay(1, c)); // accept all download requests, and begin the upload immediately. // normally there would be an internal queue, and uploads would be handled separately. Task.Run(async() => { using var stream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read); await Client.UploadAsync(username, fileInfo.FullName, fileInfo.Length, stream, options: topts, cancellationToken: cts.Token); }).ContinueWith(t => { Console.WriteLine($"[UPLOAD FAILED] {t.Exception}"); }, TaskContinuationOptions.NotOnRanToCompletion); // fire and forget // return a completed task so that the invoking code can respond to the remote client. return(Task.CompletedTask); }