74 lines
		
	
	
		
			1.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			74 lines
		
	
	
		
			1.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package incrt
 | 
						|
 | 
						|
import (
 | 
						|
	"io"
 | 
						|
	"time"
 | 
						|
 | 
						|
	logging "github.com/ipfs/go-log/v2"
 | 
						|
)
 | 
						|
 | 
						|
var log = logging.Logger("incrt")
 | 
						|
 | 
						|
var now = time.Now
 | 
						|
 | 
						|
type ReaderDeadline interface {
 | 
						|
	Read([]byte) (int, error)
 | 
						|
	SetReadDeadline(time.Time) error
 | 
						|
}
 | 
						|
 | 
						|
type incrt struct {
 | 
						|
	rd ReaderDeadline
 | 
						|
 | 
						|
	waitPerByte time.Duration
 | 
						|
	wait        time.Duration
 | 
						|
	maxWait     time.Duration
 | 
						|
}
 | 
						|
 | 
						|
// New creates an Incremental Reader Timeout, with minimum sustained speed of
 | 
						|
// minSpeed bytes per second and with maximum wait of maxWait
 | 
						|
func New(rd ReaderDeadline, minSpeed int64, maxWait time.Duration) io.Reader {
 | 
						|
	return &incrt{
 | 
						|
		rd:          rd,
 | 
						|
		waitPerByte: time.Second / time.Duration(minSpeed),
 | 
						|
		wait:        maxWait,
 | 
						|
		maxWait:     maxWait,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type errNoWait struct{}
 | 
						|
 | 
						|
func (err errNoWait) Error() string {
 | 
						|
	return "wait time exceeded"
 | 
						|
}
 | 
						|
func (err errNoWait) Timeout() bool {
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
func (crt *incrt) Read(buf []byte) (int, error) {
 | 
						|
	start := now()
 | 
						|
	if crt.wait == 0 {
 | 
						|
		return 0, errNoWait{}
 | 
						|
	}
 | 
						|
 | 
						|
	err := crt.rd.SetReadDeadline(start.Add(crt.wait))
 | 
						|
	if err != nil {
 | 
						|
		log.Warnf("unable to set deadline: %+v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	n, err := crt.rd.Read(buf)
 | 
						|
 | 
						|
	crt.rd.SetReadDeadline(time.Time{})
 | 
						|
	if err == nil {
 | 
						|
		dur := now().Sub(start)
 | 
						|
		crt.wait -= dur
 | 
						|
		crt.wait += time.Duration(n) * crt.waitPerByte
 | 
						|
		if crt.wait < 0 {
 | 
						|
			crt.wait = 0
 | 
						|
		}
 | 
						|
		if crt.wait > crt.maxWait {
 | 
						|
			crt.wait = crt.maxWait
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return n, err
 | 
						|
}
 |