github.com/anacrolix/torrent@v1.61.0/idle-reader.go (about)

     1  package torrent
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"time"
     7  )
     8  
     9  func newIdleTimeoutReader(r io.Reader, timeout time.Duration, interrupt func()) io.Reader {
    10  	tr := &idleTimeoutReader{
    11  		r:         r,
    12  		interrupt: interrupt,
    13  		timeout:   timeout,
    14  	}
    15  	tr.timer = time.AfterFunc(timeout, tr.timerFunc)
    16  	tr.timer.Stop()
    17  	return tr
    18  }
    19  
    20  type idleTimeoutReader struct {
    21  	r         io.Reader
    22  	interrupt func()
    23  	timer     *time.Timer
    24  	timeout   time.Duration
    25  	fired     bool
    26  }
    27  
    28  func (me *idleTimeoutReader) Read(p []byte) (n int, err error) {
    29  	// Allow resuming reading even after a previous idle timeout.
    30  	me.fired = false
    31  	me.timer.Reset(me.timeout)
    32  	n, err = me.r.Read(p)
    33  	me.timer.Stop()
    34  	if me.fired {
    35  		// Wrap the error, we don't know if the interrupt caused the inner reader to return early.
    36  		err = fmt.Errorf("idle timeout, original error: %w", err)
    37  	}
    38  	return
    39  }
    40  
    41  func (me *idleTimeoutReader) timerFunc() {
    42  	me.fired = true
    43  	me.interrupt()
    44  }