credentials.go raw

   1  package credentials
   2  
   3  import (
   4  	"errors"
   5  	"sync"
   6  )
   7  
   8  var (
   9  	ErrMissingIncomplete = errors.New("missing or incomplete API credentials")
  10  )
  11  
  12  type Value struct {
  13  	APIKey    string
  14  	APISecret string
  15  }
  16  
  17  // IsSet returns true if the credentials Value has both APIKey and APISecret.
  18  func (v Value) IsSet() bool {
  19  	return v.APIKey != "" && v.APISecret != ""
  20  }
  21  
  22  type Provider interface {
  23  	// Retrieve returns nil if it successfully retrieved the value.
  24  	// Error is returned if the value were not obtainable, or empty.
  25  	Retrieve() (Value, error)
  26  
  27  	// IsExpired returns if the credentials are no longer valid, and need
  28  	// to be retrieved.
  29  	IsExpired() bool
  30  }
  31  
  32  type Credentials struct {
  33  	credentials Value
  34  	provider    Provider
  35  
  36  	sync.RWMutex
  37  }
  38  
  39  func NewCredentials(provider Provider) *Credentials {
  40  	creds := &Credentials{
  41  		provider: provider,
  42  	}
  43  
  44  	return creds
  45  }
  46  
  47  func (c *Credentials) Expire() {
  48  	c.Lock()
  49  	defer c.Unlock()
  50  
  51  	c.credentials = Value{}
  52  }
  53  
  54  func (c *Credentials) Get() (Value, error) {
  55  	if c.IsExpired() {
  56  		if err := c.retrieve(); err != nil {
  57  			return Value{}, err
  58  		}
  59  	}
  60  	c.RLock()
  61  	defer c.RUnlock()
  62  
  63  	if !c.credentials.IsSet() {
  64  		return Value{}, ErrMissingIncomplete
  65  	}
  66  
  67  	return c.credentials, nil
  68  }
  69  
  70  func (c *Credentials) IsExpired() bool {
  71  	c.RLock()
  72  	defer c.RUnlock()
  73  
  74  	return (!c.credentials.IsSet() || c.provider.IsExpired())
  75  }
  76  
  77  func (c *Credentials) retrieve() error {
  78  	c.Lock()
  79  	defer c.Unlock()
  80  
  81  	v, err := c.provider.Retrieve()
  82  	if err != nil {
  83  		return err
  84  	}
  85  
  86  	c.credentials = v
  87  
  88  	return nil
  89  }
  90