Vaillant: share token source across chargers on the same account (#32471)
This commit is contained in:
parent
6f430d4a99
commit
dc1ac7c6dd
2 changed files with 49 additions and 4 deletions
|
|
@ -33,7 +33,6 @@ import (
|
||||||
"github.com/evcc-io/evcc/util"
|
"github.com/evcc-io/evcc/util"
|
||||||
"github.com/evcc-io/evcc/util/request"
|
"github.com/evcc-io/evcc/util/request"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"golang.org/x/oauth2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
@ -79,15 +78,14 @@ func NewVaillantFromConfig(ctx context.Context, other map[string]any) (api.Charg
|
||||||
}
|
}
|
||||||
|
|
||||||
log := util.NewLogger("vaillant").Redact(cc.User, cc.Password)
|
log := util.NewLogger("vaillant").Redact(cc.User, cc.Password)
|
||||||
logCtx := context.WithValue(ctx, oauth2.HTTPClient, request.NewClient(log))
|
|
||||||
|
|
||||||
oc := sensonet.Oauth2ConfigForRealm(cc.Realm)
|
oc := sensonet.Oauth2ConfigForRealm(cc.Realm)
|
||||||
token, err := vaillant.Login(logCtx, log, oc, cc.User, cc.Password)
|
ts, err := vaillant.Identity(log, oc, cc.Realm, cc.User, cc.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := sensonet.NewConnection(oc.TokenSource(logCtx, token), sensonet.WithHttpClient(request.NewClient(log)))
|
conn, err := sensonet.NewConnection(ts, sensonet.WithHttpClient(request.NewClient(log)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
47
charger/vaillant/identity.go
Normal file
47
charger/vaillant/identity.go
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
package vaillant
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/WulfgarW/sensonet"
|
||||||
|
"github.com/evcc-io/evcc/util"
|
||||||
|
"github.com/evcc-io/evcc/util/request"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
mu sync.Mutex
|
||||||
|
identities = make(map[string]oauth2.TokenSource)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Identity returns an oauth2 token source shared by all Vaillant chargers on the
|
||||||
|
// same myVaillant account. The login is performed once while holding the lock,
|
||||||
|
// which serialises concurrent startups so the parallel login flows can no longer
|
||||||
|
// clobber each other's session (#30625).
|
||||||
|
func Identity(log *util.Logger, oc *sensonet.Oauth2Config, realm, user, password string) (oauth2.TokenSource, error) {
|
||||||
|
// serialise instance handling
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
|
||||||
|
// reuse identity instance
|
||||||
|
subject := "vaillant." + strings.ToLower(realm) + "." + strings.ToLower(user)
|
||||||
|
if ts, ok := identities[subject]; ok {
|
||||||
|
return ts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// decoupled from the calling charger's context, which is bounded by a timeout
|
||||||
|
// during device creation and would otherwise cancel the shared token refresh
|
||||||
|
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, request.NewClient(log))
|
||||||
|
|
||||||
|
token, err := Login(ctx, log, oc, user, password)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ts := oc.TokenSource(ctx, token)
|
||||||
|
identities[subject] = ts
|
||||||
|
|
||||||
|
return ts, nil
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue