Exemple #1
0
        /// <summary>
        ///     Wrap the specified stream in a <see cref="ProgressStream"/> that will report progress for reads.
        /// </summary>
        /// <param name="stream">
        ///     The stream to wrap.
        /// </param>
        /// <param name="total">
        ///     An optional total used to calculate progress.
        ///
        ///     If not specified, the stream length is used (providing the stream supports seeking).
        /// </param>
        /// <param name="progressObserver">
        ///     An optional <see cref="IObserver{TValue}"/> that receives raw progress data.
        /// </param>
        /// <param name="ownsStream">
        ///     Should the <see cref="ProgressStream"/> close the inner stream when it is closed?
        /// </param>
        /// <returns>
        ///     The new <see cref="ProgressStream"/>.
        /// </returns>
        /// <exception cref="InvalidOperationException">
        ///     The <paramref name="stream"/> is already a <see cref="ProgressStream"/>.
        ///     <paramref name="total"/> was not specified, and the stream does not support seeking.
        /// </exception>
        public static ProgressStream WithReadProgress(this Stream stream, long?total = null, IObserver <RawProgressData <long> > progressObserver = null, bool ownsStream = true)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            IProgressSink <long> sink = DefaultSink.Int64();

            if (total.HasValue)
            {
                sink.Total = total.Value;
            }
            else if (stream.CanSeek)
            {
                sink.Total = stream.Length;
            }
            else
            {
                throw new InvalidOperationException("Total was not specified, and cannot be auto-detected because the specified stream does not support seeking.");
            }

            if (progressObserver != null)
            {
                sink.Subscribe(progressObserver);
            }

            return(new ProgressStream(stream, StreamDirection.Read, ownsStream, sink));
        }
Exemple #2
0
        /// <summary>
        ///     Wrap the specified stream in a <see cref="ProgressStream"/> that will report progress for writes.
        /// </summary>
        /// <param name="stream">
        ///     The stream to wrap.
        /// </param>
        /// <param name="total">
        ///     The total used to calculate progress.
        /// </param>
        /// <param name="progressObserver">
        ///     An optional <see cref="IObserver{TValue}"/> that receives raw progress data.
        /// </param>
        /// <param name="ownsStream">
        ///     Should the <see cref="ProgressStream"/> close the inner stream when it is closed?
        /// </param>
        /// <returns>
        ///     The new <see cref="ProgressStream"/>.
        /// </returns>
        /// <exception cref="InvalidOperationException">
        ///     The <paramref name="stream"/> is already a <see cref="ProgressStream"/>.
        /// </exception>
        public static ProgressStream WithWriteProgress(this Stream stream, long total, IObserver <RawProgressData <long> > progressObserver = null, bool ownsStream = true)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            IProgressSink <long> sink = DefaultSink.Int64();

            if (progressObserver != null)
            {
                sink.Subscribe(progressObserver);
            }

            return(new ProgressStream(stream, StreamDirection.Write, ownsStream, sink));
        }
Exemple #3
0
        /// <summary>
        ///     Create new progress content.
        /// </summary>
        /// <param name="innerContent">
        ///     The inner <see cref="HttpContent"/>.
        /// </param>
        /// <param name="bufferSize">
        ///     An optional buffer size to use when transferring the inner content.
        ///
        ///     Pass <c>null</c> to use the default buffer size.
        /// </param>
        /// <param name="sink">
        ///     The sink which will receive raw progress data.
        /// </param>
        public ProgressContent(HttpContent innerContent, int?bufferSize, IProgressSink <long> sink)
        {
            if (innerContent == null)
            {
                throw new ArgumentNullException(nameof(innerContent));
            }

            if (sink == null)
            {
                throw new ArgumentNullException(nameof(sink));
            }

            _innerContent = innerContent;
            _bufferSize   = bufferSize;
            _sink         = sink;

            LoadHeaders();
        }
Exemple #4
0
        /// <summary>
        ///     Create a new <see cref="ProgressStream"/> that wraps the specified inner <see cref="Stream"/>.
        /// </summary>
        /// <param name="innerStream">
        ///     The inner stream.
        /// </param>
        /// <param name="streamDirection">
        ///     The direction in which the stream's data is expected to flow.
        /// </param>
        /// <param name="ownsStream">
        ///     Should the <see cref="ProgressStream"/> close the inner stream when it is closed?
        /// </param>
        /// <param name="sink">
        ///     The sink used to report stream progress.
        /// </param>
        public ProgressStream(Stream innerStream, StreamDirection streamDirection, bool ownsStream, IProgressSink <long> sink)
        {
            if (innerStream == null)
            {
                throw new ArgumentNullException(nameof(innerStream));
            }

            if (innerStream is ProgressStream)
            {
                throw new InvalidOperationException("Wrapping a ProgressStream2 in another ProgressStream2 is not currently supported.");
            }

            if (streamDirection == StreamDirection.Unknown)
            {
                throw new ArgumentOutOfRangeException(nameof(streamDirection), streamDirection, $"Invalid stream direction: '{streamDirection}'.");
            }

            _innerStream     = innerStream;
            _streamDirection = streamDirection;
            _sink            = sink;
        }
Exemple #5
0
        /// <summary>
        ///     Add progress reporting for the specified response message.
        /// </summary>
        /// <param name="response">
        ///     The HTTP response message.
        /// </param>
        /// <param name="progressSink">
        ///     An optional sink that will receive raw progress data.
        /// </param>
        /// <param name="bufferSize">
        ///     An optional buffer size to use when transferring content.
        ///
        ///     If not specified, the default buffer size is used.
        /// </param>
        /// <returns>
        ///     The response message.
        /// </returns>
        public static HttpResponseMessage AddProgress(this HttpResponseMessage response, IProgressSink <long> progressSink = null, int?bufferSize = null)
        {
            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            // No response content? No progress to report.
            // Might be worth creating a dummy sink that just emits 100% progress.
            if (response.Content == null)
            {
                return(response);
            }

            if (response.Content is ProgressContent)
            {
                throw new InvalidOperationException("The HTTP response message has already been configured to report progress.");
            }

            response.Content = new ProgressContent(
                innerContent: response.Content,
                sink: progressSink ?? DefaultSink.Int64(),
                bufferSize: bufferSize
                );

            return(response);
        }
Exemple #6
0
        /// <summary>
        ///     Add progress reporting for the specified request message.
        /// </summary>
        /// <param name="request">
        ///     The HTTP request message.
        /// </param>
        /// <param name="progressSink">
        ///     An optional sink that will receive raw progress data.
        /// </param>
        /// <param name="bufferSize">
        ///     An optional buffer size to use when transferring content.
        ///
        ///     If not specified, the default buffer size is used.
        /// </param>
        /// <returns>
        ///     The request message.
        /// </returns>
        public static HttpRequestMessage AddProgress(this HttpRequestMessage request, IProgressSink <long> progressSink = null, int?bufferSize = null)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            // No response content? No progress to report.
            if (request.Content == null)
            {
                return(request);
            }

            if (request.Content is ProgressContent)
            {
                throw new InvalidOperationException("The HTTP request message has already been configured to report progress.");
            }

            request.Content = new ProgressContent(
                innerContent: request.Content,
                sink: progressSink ?? DefaultSink.Int64(),
                bufferSize: bufferSize
                );
            request.SetProgressContextId(ProgressContext.Current.Id);

            return(request);
        }
Exemple #7
0
        /// <summary>
        ///     Add progress reporting to the HTTP response message.
        /// </summary>
        /// <param name="response">
        ///     A <see cref="Task{T}"/> that yields the response message.
        /// </param>
        /// <param name="sink">
        ///     An optional sink that will receive raw progress data.
        /// </param>
        /// <param name="bufferSize">
        ///     An optional buffer size to use when transferring content.
        ///
        ///     If not specified, the default buffer size is used.
        /// </param>
        /// <returns>
        ///     The response message.
        /// </returns>
        public static async Task <HttpResponseMessage> WithProgress(this Task <HttpResponseMessage> response, IProgressSink <long> sink, int?bufferSize = null)
        {
            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            HttpResponseMessage responseMessage = null;

            try
            {
                responseMessage = await response;
                responseMessage.AddProgress(sink, bufferSize);
            }
            catch
            {
                using (responseMessage)
                {
                    throw;
                }
            }

            return(responseMessage);
        }
Exemple #8
0
 /// <summary>
 ///     Create new progress content.
 /// </summary>
 /// <param name="innerContent">
 ///     The inner <see cref="HttpContent"/>.
 /// </param>
 /// <param name="sink">
 ///     The sink which will receive raw progress data.
 /// </param>
 public ProgressContent(HttpContent innerContent, IProgressSink <long> sink)
     : this(innerContent, null, sink)
 {
 }