Skip to content

Commit

Permalink
add token caching
Browse files Browse the repository at this point in the history
  • Loading branch information
brchri committed Oct 2, 2023
1 parent c1456ba commit 9f59e86
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 7 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ docker run \
-e MYQ_EMAIL=my_email@address.com \ # optional, can also be saved in the config.yml file
-e MYQ_PASS=my_super_secret_pass \ # optional, can also be saved in the config.yml file
-e TZ=America/New_York \ # optional, sets timezone for container
-v /etc/tesla-youq:/app/config:ro \ # required, mounts folder containing config file(s) into container
-v /etc/tesla-youq:/app/config \ # required, mounts folder containing config file(s) into container
brchri/tesla-youq:latest
```

Expand All @@ -48,7 +48,7 @@ services:
- MYQ_PASS=my_super_secret_pass # optional, can also be saved in the config.yml file
- TZ=America/New_York # optional, sets timezone for container
volumes:
- /etc/tesla-youq:/app/config:ro # required, mounts folder containing config file(s) into container
- /etc/tesla-youq:/app/config # required, mounts folder containing config file(s) into container
restart: unless-stopped
```

Expand Down
1 change: 1 addition & 0 deletions config.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ global:
cooldown: 5 # minutes to wait after operating garage before allowing another garage operation
myq_email: myq@example.com # email to auth to myq account; can also be passed as env var MYQ_EMAIL
myq_pass: super_secret_password # password to auth to myq account; can also be passed as env var MYQ_PASS
cache_token_dir: config/token_cache.txt # location to cache myq auth token; omit to disable caching token; useful to prevent generating too many myq auth requests, especially when testing

garage_doors:
- # main garage example
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/brchri/tesla-youq
go 1.19

require (
github.com/brchri/myq v0.0.0-20231002041725-18aa0c937db3
github.com/eclipse/paho.mqtt.golang v1.4.2
github.com/google/uuid v1.3.0
github.com/joeshaw/myq v0.0.0-20221122173250-4d1216b9fc87
Expand All @@ -15,6 +16,6 @@ require (
github.com/gorilla/websocket v1.4.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.5.0 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/net v0.15.0 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
)
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/brchri/myq v0.0.0-20231002041725-18aa0c937db3 h1:t5edNn/KiV1Kgz1Ll1kdpupABPUtOUDIebHLm5JmDV8=
github.com/brchri/myq v0.0.0-20231002041725-18aa0c937db3/go.mod h1:EDuAgiwrpS8cfzKCUrXpelEw1YOjxO/jhklEthAKmEs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -22,8 +24,8 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down
47 changes: 45 additions & 2 deletions internal/geo/geo.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ package geo

import (
"fmt"
"io"
"log"
"math"
"os"
"time"

util "github.com/brchri/tesla-youq/internal/util"

"github.com/joeshaw/myq"
"github.com/brchri/myq"
)

// interface that allows api calls to myq to be abstracted and mocked by testing functions
Expand All @@ -19,6 +20,8 @@ type MyqSessionInterface interface {
SetDoorState(serialNumber, action string) error
SetUsername(string)
SetPassword(string)
GetToken() string
SetToken(string)
New()
}

Expand All @@ -40,7 +43,22 @@ func (m *MyqSessionWrapper) DeviceState(s string) (string, error) {
}

func (m *MyqSessionWrapper) Login() error {
return m.myqSession.Login()
err := m.myqSession.Login()
// cache token if requested
if err == nil && util.Config.Global.CacheTokenDir != "" {
file, fileErr := os.OpenFile(util.Config.Global.CacheTokenDir, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if fileErr != nil {
log.Printf("WARNING: Unable to write to cache file %s", util.Config.Global.CacheTokenDir)
} else {
defer file.Close()

_, writeErr := file.WriteString(m.GetToken())
if writeErr != nil {
log.Printf("WARNING: Unable to write to cache file %s", util.Config.Global.CacheTokenDir)
}
}
}
return err
}

func (m *MyqSessionWrapper) SetDoorState(serialNumber, action string) error {
Expand All @@ -51,6 +69,14 @@ func (m *MyqSessionWrapper) New() {
m.myqSession = &myq.Session{}
}

func (m *MyqSessionWrapper) GetToken() string {
return m.myqSession.GetToken()
}

func (m *MyqSessionWrapper) SetToken(token string) {
m.myqSession.SetToken(token)
}

var myqExec MyqSessionInterface // executes myq package commands

func init() {
Expand Down Expand Up @@ -204,6 +230,23 @@ func setGarageDoor(config util.ConfigStruct, deviceSerial string, action string)
return nil
}

// check for cached token if we haven't retrieved it already
if util.Config.Global.CacheTokenDir != "" && myqExec.GetToken() == "" {
file, err := os.Open(util.Config.Global.CacheTokenDir)
if err != nil {
log.Printf("WARNING: Unable to read token cache from %s", util.Config.Global.CacheTokenDir)
} else {
defer file.Close()

data, err := io.ReadAll(file)
if err != nil {
log.Printf("WARNING: Unable to read token cache from %s", util.Config.Global.CacheTokenDir)
} else {
myqExec.SetToken(string(data))
}
}
}

curState, err := myqExec.DeviceState(deviceSerial)
if err != nil {
// fetching device state may have failed due to invalid session token; try fresh login to resolve
Expand Down
1 change: 1 addition & 0 deletions internal/geo/geo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var (

func init() {
util.LoadConfig(filepath.Join("..", "..", "config.example.yml"))
util.Config.Global.CacheTokenDir = "" // dont assume cached token in testing

// used for testing events based on distance
distanceGarageDoor = util.Config.GarageDoors[0]
Expand Down
74 changes: 74 additions & 0 deletions internal/mocks/MyqSessionInterface.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions internal/util/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ type (
OpCooldown int `yaml:"cooldown"`
MyQEmail string `yaml:"myq_email"`
MyQPass string `yaml:"myq_pass"`
CacheTokenDir string `yaml:"cache_token_dir"`
} `yaml:"global"`
GarageDoors []*GarageDoor `yaml:"garage_doors"`
Testing bool
Expand Down

0 comments on commit 9f59e86

Please sign in to comment.