github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/lib/oauthutil/renew.go (about)

     1  package oauthutil
     2  
     3  import (
     4  	"sync/atomic"
     5  
     6  	"github.com/ncw/rclone/fs"
     7  )
     8  
     9  // Renew allows tokens to be renewed on expiry if uploads are in progress.
    10  type Renew struct {
    11  	name    string       // name to use in logs
    12  	ts      *TokenSource // token source that needs renewing
    13  	uploads int32        // number of uploads in progress - atomic access required
    14  	run     func() error // a transaction to run to renew the token on
    15  }
    16  
    17  // NewRenew creates a new Renew struct and starts a background process
    18  // which renews the token whenever it expires.  It uses the run() call
    19  // to run a transaction to do this.
    20  //
    21  // It will only renew the token if the number of uploads > 0
    22  func NewRenew(name string, ts *TokenSource, run func() error) *Renew {
    23  	r := &Renew{
    24  		name: name,
    25  		ts:   ts,
    26  		run:  run,
    27  	}
    28  	go r.renewOnExpiry()
    29  	return r
    30  }
    31  
    32  // renewOnExpiry renews the token whenever it expires.  Useful when there
    33  // are lots of uploads in progress and the token doesn't get renewed.
    34  // Amazon seem to cancel your uploads if you don't renew your token
    35  // for 2hrs.
    36  func (r *Renew) renewOnExpiry() {
    37  	expiry := r.ts.OnExpiry()
    38  	for {
    39  		<-expiry
    40  		uploads := atomic.LoadInt32(&r.uploads)
    41  		if uploads != 0 {
    42  			fs.Debugf(r.name, "Token expired - %d uploads in progress - refreshing", uploads)
    43  			// Do a transaction
    44  			err := r.run()
    45  			if err == nil {
    46  				fs.Debugf(r.name, "Token refresh successful")
    47  			} else {
    48  				fs.Errorf(r.name, "Token refresh failed: %v", err)
    49  			}
    50  		} else {
    51  			fs.Debugf(r.name, "Token expired but no uploads in progress - doing nothing")
    52  		}
    53  	}
    54  }
    55  
    56  // Start should be called before starting an upload
    57  func (r *Renew) Start() {
    58  	atomic.AddInt32(&r.uploads, 1)
    59  }
    60  
    61  // Stop should be called after finishing an upload
    62  func (r *Renew) Stop() {
    63  	atomic.AddInt32(&r.uploads, -1)
    64  }
    65  
    66  // Invalidate invalidates the token source
    67  func (r *Renew) Invalidate() {
    68  	r.ts.Invalidate()
    69  }