Skip to content

Commit

Permalink
added ecobee.New() and Options
Browse files Browse the repository at this point in the history
Deprecated ecobee.NewClient()

All client creation options are now passed through ecobee.Options.

This allows persisting OAuth2 tokens in storage other than files,
for example etcd or a database and allows passing custom context.
  • Loading branch information
jkowalski committed Dec 1, 2018
1 parent 2359387 commit 404f4cd
Showing 1 changed file with 69 additions and 11 deletions.
80 changes: 69 additions & 11 deletions ecobee/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package ecobee
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
Expand All @@ -31,17 +32,45 @@ import (
var Scopes = []string{"smartRead", "smartWrite"}

type tokenSource struct {
token oauth2.Token
cacheFile, clientID string
token oauth2.Token
clientID string
authCache AuthCache
}

// AuthCache encapsulates persistent cache for OAuth2 token.
type AuthCache interface {
LoadTokenData() ([]byte, error)
SaveTokenData(data []byte) error
}

type fileAuthCache struct {
fileName string
}

func (p fileAuthCache) LoadTokenData() ([]byte, error) {
return ioutil.ReadFile(p.fileName)
}

func (p fileAuthCache) SaveTokenData(data []byte) error {
return ioutil.WriteFile(p.fileName, data, 0777)
}

// TokenCacheFile returns AuthCache that persists the OAuth2 token in the specified file.
func TokenCacheFile(fileName string) AuthCache {
return fileAuthCache{fileName}
}

func TokenSource(clientID, cacheFile string) oauth2.TokenSource {
return oauth2.ReuseTokenSource(nil, newTokenSource(clientID, cacheFile))
return TokenSourceWithAuthCache(clientID, fileAuthCache{cacheFile})
}

func newTokenSource(clientID, cacheFile string) *tokenSource {
file, err := ioutil.ReadFile(cacheFile)
ets := tokenSource{clientID: clientID, cacheFile: cacheFile}
func TokenSourceWithAuthCache(clientID string, authCache AuthCache) oauth2.TokenSource {
return oauth2.ReuseTokenSource(nil, newTokenSource(clientID, authCache))
}

func newTokenSource(clientID string, authCache AuthCache) *tokenSource {
file, err := authCache.LoadTokenData()
ets := tokenSource{clientID: clientID, authCache: authCache}
if err != nil {
// no file, corrupted, or other problem: just start with an
// empty token.
Expand All @@ -56,8 +85,7 @@ func (ts *tokenSource) save() error {
if err != nil {
return err
}
err = ioutil.WriteFile(ts.cacheFile, d, 0777)
return err
return ts.authCache.SaveTokenData(d)
}

func (ts *tokenSource) firstAuth() error {
Expand Down Expand Up @@ -204,8 +232,38 @@ type Client struct {
// (Application Key). Use the Ecobee Developer Portal to create the
// Application Key.
// (https://www.ecobee.com/consumerportal/index.html#/dev)
// This function is deprecated - use New() instead.
func NewClient(clientID, authCache string) *Client {
return &Client{oauth2.NewClient(
context.Background(),
TokenSource(clientID, authCache))}
c, err := New(context.TODO(), clientID, Options{
AuthCache: fileAuthCache{authCache},
})

if err != nil {
// can't fail here.
panic("unexpected usage: " + err.Error())
}

return c
}

// Options specifies EcoBee client parameters.
type Options struct {
ApplicationID string // application ID created in Ecobee Developer Portal
AuthCache AuthCache // token cache, typically usually TokenCacheFile(fileName)
}

// New creates a Ecobee API client for the specific options
// Use the Ecobee Developer Portal to create the Application Key.
// (https://www.ecobee.com/consumerportal/index.html#/dev)
func New(ctx context.Context, clientID string, opt Options) (*Client, error) {
if opt.ApplicationID == "" {
return nil, errors.New("application ID is required")
}
if opt.AuthCache == nil {
return nil, fmt.Errorf("auth cache is required")
}

ts := TokenSourceWithAuthCache(clientID, opt.AuthCache)
cli := oauth2.NewClient(ctx, ts)
return &Client{cli}, nil
}

0 comments on commit 404f4cd

Please sign in to comment.