56 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			56 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			Go
		
	
	
| package swift
 | |
| 
 | |
| import (
 | |
| 	"io"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| var watchdogChunkSize = 1 << 20 // 1 MiB
 | |
| 
 | |
| // An io.Reader which resets a watchdog timer whenever data is read
 | |
| type watchdogReader struct {
 | |
| 	timeout   time.Duration
 | |
| 	reader    io.Reader
 | |
| 	timer     *time.Timer
 | |
| 	chunkSize int
 | |
| }
 | |
| 
 | |
| // Returns a new reader which will kick the watchdog timer whenever data is read
 | |
| func newWatchdogReader(reader io.Reader, timeout time.Duration, timer *time.Timer) *watchdogReader {
 | |
| 	return &watchdogReader{
 | |
| 		timeout:   timeout,
 | |
| 		reader:    reader,
 | |
| 		timer:     timer,
 | |
| 		chunkSize: watchdogChunkSize,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Read reads up to len(p) bytes into p
 | |
| func (t *watchdogReader) Read(p []byte) (int, error) {
 | |
| 	//read from underlying reader in chunks not larger than t.chunkSize
 | |
| 	//while resetting the watchdog timer before every read; the small chunk
 | |
| 	//size ensures that the timer does not fire when reading a large amount of
 | |
| 	//data from a slow connection
 | |
| 	start := 0
 | |
| 	end := len(p)
 | |
| 	for start < end {
 | |
| 		length := end - start
 | |
| 		if length > t.chunkSize {
 | |
| 			length = t.chunkSize
 | |
| 		}
 | |
| 
 | |
| 		resetTimer(t.timer, t.timeout)
 | |
| 		n, err := t.reader.Read(p[start : start+length])
 | |
| 		start += n
 | |
| 		if n == 0 || err != nil {
 | |
| 			return start, err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	resetTimer(t.timer, t.timeout)
 | |
| 	return start, nil
 | |
| }
 | |
| 
 | |
| // Check it satisfies the interface
 | |
| var _ io.Reader = &watchdogReader{}
 |