1package swift
2
3import (
4	"io"
5	"time"
6)
7
8var watchdogChunkSize = 1 << 20 // 1 MiB
9
10// An io.Reader which resets a watchdog timer whenever data is read
11type watchdogReader struct {
12	timeout   time.Duration
13	reader    io.Reader
14	timer     *time.Timer
15	chunkSize int
16}
17
18// Returns a new reader which will kick the watchdog timer whenever data is read
19func newWatchdogReader(reader io.Reader, timeout time.Duration, timer *time.Timer) *watchdogReader {
20	return &watchdogReader{
21		timeout:   timeout,
22		reader:    reader,
23		timer:     timer,
24		chunkSize: watchdogChunkSize,
25	}
26}
27
28// Read reads up to len(p) bytes into p
29func (t *watchdogReader) Read(p []byte) (int, error) {
30	//read from underlying reader in chunks not larger than t.chunkSize
31	//while resetting the watchdog timer before every read; the small chunk
32	//size ensures that the timer does not fire when reading a large amount of
33	//data from a slow connection
34	start := 0
35	end := len(p)
36	for start < end {
37		length := end - start
38		if length > t.chunkSize {
39			length = t.chunkSize
40		}
41
42		resetTimer(t.timer, t.timeout)
43		n, err := t.reader.Read(p[start : start+length])
44		start += n
45		if n == 0 || err != nil {
46			return start, err
47		}
48	}
49
50	resetTimer(t.timer, t.timeout)
51	return start, nil
52}
53
54// Check it satisfies the interface
55var _ io.Reader = &watchdogReader{}
56