diff options
| author | Petter Rasmussen | 2016-02-20 22:47:55 +0100 |
|---|---|---|
| committer | Petter Rasmussen | 2016-02-20 23:39:05 +0100 |
| commit | 7eaf0c84ebb01c84f39ed93d69a7b856d8c633ce (patch) | |
| tree | 8f0ef9c0f7ec8c7ee09b12461cfc0fe017b1c92b | |
| parent | 5d561380f73f2b1bcb663191e363a752cc097dcc (diff) | |
| download | gdrive-7eaf0c84ebb01c84f39ed93d69a7b856d8c633ce.tar.bz2 | |
Add TimeoutReader
TimeoutReader wraps a reader and takes a cancel function as argument,
the cancel function will be called when the reader is idle for too long.
| -rw-r--r-- | drive/timeout_reader.go | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/drive/timeout_reader.go b/drive/timeout_reader.go new file mode 100644 index 0000000..e228160 --- /dev/null +++ b/drive/timeout_reader.go @@ -0,0 +1,86 @@ +package drive + +import ( + "io" + "time" + "sync" + "golang.org/x/net/context" +) + +const MaxIdleTimeout = time.Second * 120 +const TimeoutTimerInterval = time.Second * 10 + +func getTimeoutReader(r io.Reader, cancel context.CancelFunc) io.Reader { + return &TimeoutReader{ + reader: r, + cancel: cancel, + mutex: &sync.Mutex{}, + } +} + +type TimeoutReader struct { + reader io.Reader + cancel context.CancelFunc + lastActivity time.Time + timer *time.Timer + mutex *sync.Mutex + done bool +} + +func (self *TimeoutReader) Read(p []byte) (int, error) { + if self.timer == nil { + self.startTimer() + } + + self.mutex.Lock() + + // Read + n, err := self.reader.Read(p) + + self.lastActivity = time.Now() + self.done = (err != nil) + + self.mutex.Unlock() + + if self.done { + self.stopTimer() + } + + return n, err +} + +func (self *TimeoutReader) startTimer() { + self.mutex.Lock() + defer self.mutex.Unlock() + + if !self.done { + self.timer = time.AfterFunc(TimeoutTimerInterval, self.timeout) + } +} + +func (self *TimeoutReader) stopTimer() { + self.mutex.Lock() + defer self.mutex.Unlock() + + if self.timer != nil { + self.timer.Stop() + } +} + +func (self *TimeoutReader) timeout() { + self.mutex.Lock() + + if self.done { + self.mutex.Unlock() + return + } + + if time.Since(self.lastActivity) > MaxIdleTimeout { + self.cancel() + self.mutex.Unlock() + return + } + + self.mutex.Unlock() + self.startTimer() +} |
