1//go:build go1.16 2// +build go1.16 3 4// Copyright (c) Microsoft Corporation. All rights reserved. 5// Licensed under the MIT License. 6 7package streaming 8 9import ( 10 "io" 11 12 "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" 13) 14 15type progress struct { 16 rc io.ReadCloser 17 rsc io.ReadSeekCloser 18 pr func(bytesTransferred int64) 19 offset int64 20} 21 22// NopCloser returns a ReadSeekCloser with a no-op close method wrapping the provided io.ReadSeeker. 23func NopCloser(rs io.ReadSeeker) io.ReadSeekCloser { 24 return shared.NopCloser(rs) 25} 26 27// NewRequestProgress adds progress reporting to an HTTP request's body stream. 28func NewRequestProgress(body io.ReadSeekCloser, pr func(bytesTransferred int64)) io.ReadSeekCloser { 29 return &progress{ 30 rc: body, 31 rsc: body, 32 pr: pr, 33 offset: 0, 34 } 35} 36 37// NewResponseProgress adds progress reporting to an HTTP response's body stream. 38func NewResponseProgress(body io.ReadCloser, pr func(bytesTransferred int64)) io.ReadCloser { 39 return &progress{ 40 rc: body, 41 rsc: nil, 42 pr: pr, 43 offset: 0, 44 } 45} 46 47// Read reads a block of data from an inner stream and reports progress 48func (p *progress) Read(b []byte) (n int, err error) { 49 n, err = p.rc.Read(b) 50 if err != nil && err != io.EOF { 51 return 52 } 53 p.offset += int64(n) 54 // Invokes the user's callback method to report progress 55 p.pr(p.offset) 56 return 57} 58 59// Seek only expects a zero or from beginning. 60func (p *progress) Seek(offset int64, whence int) (int64, error) { 61 // This should only ever be called with offset = 0 and whence = io.SeekStart 62 n, err := p.rsc.Seek(offset, whence) 63 if err == nil { 64 p.offset = int64(n) 65 } 66 return n, err 67} 68 69// requestBodyProgress supports Close but the underlying stream may not; if it does, Close will close it. 70func (p *progress) Close() error { 71 return p.rc.Close() 72} 73