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)
         );
 }
Example #3
0
 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]);
 }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
0
        // 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);
        }
Example #7
0
        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);
        }
Example #8
0
 public static string GetUploadTempFilePath(this IPlatform platform, HttpTransfer transfer)
 => GetUploadTempFilePath(platform, transfer.LocalFilePath);
Example #9
0
 public HttpTransferMetric(HttpTransfer transfer) : this(transfer, 0, TimeSpan.Zero)
 {
 }
Example #10
0
 public HttpTransferMetric(HttpTransfer transfer, long bytesPerSecond, TimeSpan estimatedTimeRemaining)
 {
     this.Transfer               = transfer;
     this.BytesPerSecond         = bytesPerSecond;
     this.EstimatedTimeRemaining = estimatedTimeRemaining;
 }