1// +build go1.13
2
3// Copyright (c) Microsoft Corporation. All rights reserved.
4// Licensed under the MIT License.
5
6package azcore
7
8import "io"
9
10// ********** The following is common between the request body AND the response body.
11
12// ProgressReceiver defines the signature of a callback function invoked as progress is reported.
13type ProgressReceiver func(bytesTransferred int64)
14
15// ********** The following are specific to the request body (a ReadSeekCloser)
16
17// This struct is used when sending a body to the network
18type requestBodyProgress struct {
19	requestBody ReadSeekCloser // Seeking is required to support retries
20	pr          ProgressReceiver
21}
22
23// NewRequestBodyProgress adds progress reporting to an HTTP request's body stream.
24func NewRequestBodyProgress(requestBody ReadSeekCloser, pr ProgressReceiver) ReadSeekCloser {
25	return &requestBodyProgress{requestBody: requestBody, pr: pr}
26}
27
28// Read reads a block of data from an inner stream and reports progress
29func (rbp *requestBodyProgress) Read(p []byte) (n int, err error) {
30	n, err = rbp.requestBody.Read(p)
31	if err != nil {
32		return
33	}
34	// Invokes the user's callback method to report progress
35	position, err := rbp.requestBody.Seek(0, io.SeekCurrent)
36	if err != nil {
37		return
38	}
39	rbp.pr(position)
40	return
41}
42
43func (rbp *requestBodyProgress) Seek(offset int64, whence int) (offsetFromStart int64, err error) {
44	return rbp.requestBody.Seek(offset, whence)
45}
46
47// requestBodyProgress supports Close but the underlying stream may not; if it does, Close will close it.
48func (rbp *requestBodyProgress) Close() error {
49	return rbp.requestBody.Close()
50}
51
52// ********** The following are specific to the response body (a ReadCloser)
53
54// This struct is used when sending a body to the network
55type responseBodyProgress struct {
56	responseBody io.ReadCloser
57	pr           ProgressReceiver
58	offset       int64
59}
60
61// NewResponseBodyProgress adds progress reporting to an HTTP response's body stream.
62func NewResponseBodyProgress(responseBody io.ReadCloser, pr ProgressReceiver) io.ReadCloser {
63	return &responseBodyProgress{responseBody: responseBody, pr: pr, offset: 0}
64}
65
66// Read reads a block of data from an inner stream and reports progress
67func (rbp *responseBodyProgress) Read(p []byte) (n int, err error) {
68	n, err = rbp.responseBody.Read(p)
69	rbp.offset += int64(n)
70
71	// Invokes the user's callback method to report progress
72	rbp.pr(rbp.offset)
73	return
74}
75
76func (rbp *responseBodyProgress) Close() error {
77	return rbp.responseBody.Close()
78}
79