void TryDeleteUploadTempFile(HttpTransfer transfer) { if (!transfer.IsUpload) { return; } var path = this.platform.GetUploadTempFilePath(transfer); if (File.Exists(path)) { try { this.logger.LogDebug($"Deleting temporary upload file - {transfer.Identifier}"); // sometimes iOS will hold a file lock a bit longer than it should File.Delete(path); this.logger.LogDebug($"Temporary upload file deleted - {transfer.Identifier}"); } catch (Exception ex) { this.logger.LogWarning($"Unable to delete temporary upload file - {transfer.Identifier}", ex); } } }
protected virtual async Task HandleError(HttpTransfer transfer, NSError error) { this.logger.LogError(transfer.Exception, "Error with HTTP transfer: " + transfer.Identifier); await this.shinyDelegates.Value.RunDelegates( x => x.OnError(transfer, transfer.Exception) ); }
static MetricHolder Get(HttpTransfer transfer, Dictionary <string, MetricHolder> metrics) { if (!metrics.ContainsKey(transfer.Identifier)) { metrics.Add(transfer.Identifier, new MetricHolder { LastBytesTransferred = transfer.BytesTransferred, LastPing = DateTime.UtcNow }); } return(metrics[transfer.Identifier]); }
static HttpTransferMetric Calculate(HttpTransfer transfer, IDictionary <string, MetricHolder> metrics) { var holder = metrics[transfer.Identifier]; var elapsed = DateTime.UtcNow - holder.LastPing; var totalSeconds = (long)elapsed.TotalSeconds; var xferDiff = transfer.BytesTransferred - holder.LastBytesTransferred; var bytesPerSecond = xferDiff / totalSeconds; var rawEta = (transfer.FileSize - transfer.BytesTransferred) / bytesPerSecond; var metric = new HttpTransferMetric(transfer, bytesPerSecond, TimeSpan.FromSeconds(rawEta)); holder.LastPing = DateTime.UtcNow; holder.LastBytesTransferred = transfer.BytesTransferred; return(metric); }
async Task <HttpTransfer> Create(HttpTransferRequest request) { var id = Guid.NewGuid().ToString(); await this.Services .Repository .Set(id, new HttpTransferStore { Id = id, Uri = request.Uri, IsUpload = request.IsUpload, PostData = request.PostData, LocalFile = request.LocalFile.FullName, UseMeteredConnection = request.UseMeteredConnection, HttpMethod = request.HttpMethod.ToString(), Headers = request.Headers }) .ConfigureAwait(false); await this.jobManager.Register(new JobInfo(typeof(TransferJob), id) { RequiredInternetAccess = InternetAccess.Any, Repeat = true }); var transfer = new HttpTransfer( id, request.Uri, request.LocalFile.FullName, request.IsUpload, request.UseMeteredConnection, null, request.IsUpload ? request.LocalFile.Length : 0L, 0, HttpTransferState.Pending ); // fire and forget this.jobManager.Run(id); return(transfer); }
// TODO: pause due to network async Task <HttpTransfer> Upload(HttpTransferStore request, CancellationToken ct) { var file = new FileInfo(request.LocalFile); var status = HttpTransferState.Pending; var bytesTransferred = 0L; Exception exception = null; HttpTransfer lastTransfer = default; // and not cancelled or error while (!status.IsCompleted() && !ct.IsCancellationRequested) { try { var content = new MultipartFormDataContent(); content.Add( new ProgressStreamContent( file.OpenRead(), 8192, sent => { status = HttpTransferState.InProgress; bytesTransferred += sent; lastTransfer = new HttpTransfer( request.Id, request.Uri, request.LocalFile, true, request.UseMeteredConnection, null, file.Length, bytesTransferred, status ); this.messageBus.Publish(lastTransfer); } ), "blob", file.Name ); var message = this.Build(request); await this.httpClient .SendAsync(message, ct) .ConfigureAwait(false); status = HttpTransferState.Completed; } catch (TimeoutException) { status = HttpTransferState.Retrying; } catch (IOException ex) { if (ex.InnerException is WebException) { status = HttpTransferState.Retrying; } else { exception = ex; status = HttpTransferState.Error; } } //Java.Net.ProtocolException catch (WebException ex) { switch (ex.Status) { case WebExceptionStatus.ConnectFailure: case WebExceptionStatus.Timeout: status = HttpTransferState.Retrying; break; default: status = HttpTransferState.Error; exception = ex; break; } } catch (TaskCanceledException) { status = ct.IsCancellationRequested ? HttpTransferState.Canceled : HttpTransferState.Retrying; } catch (Exception ex) { exception = ex; status = HttpTransferState.Error; } lastTransfer = new HttpTransfer( request.Id, request.Uri, request.LocalFile, true, request.UseMeteredConnection, exception, file.Length, bytesTransferred, status ); this.messageBus.Publish(lastTransfer); } return(lastTransfer); }
async Task <HttpTransfer> Download(HttpTransferStore request, CancellationToken ct) { HttpTransfer lastTransfer = default; var status = HttpTransferState.Pending; var file = new FileInfo(request.LocalFile); var message = this.Build(request); var fileSize = 0L; var bytesTransferred = file.Exists ? file.Length : 0; Exception exception = null; var fileMode = file.Exists ? FileMode.Append : FileMode.Create; using (var fs = file.Open(fileMode, FileAccess.Write, FileShare.Write)) { while (!status.IsCompleted() && !ct.IsCancellationRequested) { try { if (fs.Length > 0) { var resumeOffset = fs.Length + 1; message.Headers.Range = new RangeHeaderValue(resumeOffset, null); } var buffer = new byte[65535]; var response = await this.httpClient .SendAsync( message, HttpCompletionOption.ResponseHeadersRead, ct ) .ConfigureAwait(false); response.EnsureSuccessStatusCode(); var inputStream = await response .Content .ReadAsStreamAsync() .ConfigureAwait(false); var read = inputStream.Read(buffer, 0, buffer.Length); // status code 206 means restart if (response.Headers.AcceptRanges == null && fs.Length > 0) { // resume not supported, starting over fs.SetLength(0); fs.Flush(); bytesTransferred = 0; } var i = 0; while (read > 0 && !ct.IsCancellationRequested) { fileSize = response.Content.Headers?.ContentRange?.Length ?? response.Content?.Headers?.ContentLength ?? 0; //this.RemoteFileName = response.Content?.Headers?.ContentDisposition?.FileName ?? String.Empty; ////pr.FileSize = response.Content?.Headers?.ContentLength ?? 0; // this will change on resume bytesTransferred += read; fs.Write(buffer, 0, read); fs.Flush(); i++; if (i % 4 == 0) { lastTransfer = new HttpTransfer( request.Id, request.Uri, request.LocalFile, false, request.UseMeteredConnection, null, fileSize, bytesTransferred, HttpTransferState.InProgress ); this.messageBus.Publish(lastTransfer); } read = inputStream.Read(buffer, 0, buffer.Length); } status = HttpTransferState.Completed; } catch (TaskCanceledException) { status = ct.IsCancellationRequested ? HttpTransferState.Canceled : HttpTransferState.Retrying; } catch (IOException ex) { if (ex.InnerException is WebException) { status = HttpTransferState.Retrying; } else { exception = ex; status = HttpTransferState.Error; } } catch (Exception ex) { exception = ex; status = HttpTransferState.Error; } lastTransfer = new HttpTransfer( request.Id, request.Uri, request.LocalFile, true, request.UseMeteredConnection, exception, fileSize, bytesTransferred, status ); this.messageBus.Publish(lastTransfer); } } return(lastTransfer); }
public static string GetUploadTempFilePath(this IPlatform platform, HttpTransfer transfer) => GetUploadTempFilePath(platform, transfer.LocalFilePath);
public HttpTransferMetric(HttpTransfer transfer) : this(transfer, 0, TimeSpan.Zero) { }
public HttpTransferMetric(HttpTransfer transfer, long bytesPerSecond, TimeSpan estimatedTimeRemaining) { this.Transfer = transfer; this.BytesPerSecond = bytesPerSecond; this.EstimatedTimeRemaining = estimatedTimeRemaining; }