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/request"
|
||||
"github.com/samber/lo"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
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)
|
||||
logCtx := context.WithValue(ctx, oauth2.HTTPClient, request.NewClient(log))
|
||||
|
||||
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 {
|
||||
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 {
|
||||
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