1package swift 2 3import ( 4 "io" 5 "time" 6) 7 8// An io.ReadCloser which obeys an idle timeout 9type timeoutReader struct { 10 reader io.ReadCloser 11 timeout time.Duration 12 cancel func() 13} 14 15// Returns a wrapper around the reader which obeys an idle 16// timeout. The cancel function is called if the timeout happens 17func newTimeoutReader(reader io.ReadCloser, timeout time.Duration, cancel func()) *timeoutReader { 18 return &timeoutReader{ 19 reader: reader, 20 timeout: timeout, 21 cancel: cancel, 22 } 23} 24 25// Read reads up to len(p) bytes into p 26// 27// Waits at most for timeout for the read to complete otherwise returns a timeout 28func (t *timeoutReader) Read(p []byte) (int, error) { 29 // FIXME limit the amount of data read in one chunk so as to not exceed the timeout? 30 // Do the read in the background 31 type result struct { 32 n int 33 err error 34 } 35 done := make(chan result, 1) 36 go func() { 37 n, err := t.reader.Read(p) 38 done <- result{n, err} 39 }() 40 // Wait for the read or the timeout 41 timer := time.NewTimer(t.timeout) 42 defer timer.Stop() 43 select { 44 case r := <-done: 45 return r.n, r.err 46 case <-timer.C: 47 t.cancel() 48 return 0, TimeoutError 49 } 50 panic("unreachable") // for Go 1.0 51} 52 53// Close the channel 54func (t *timeoutReader) Close() error { 55 return t.reader.Close() 56} 57 58// Check it satisfies the interface 59var _ io.ReadCloser = &timeoutReader{} 60