Fritz!: refactor session caching (#29574)
This commit is contained in:
parent
ba29520170
commit
c96dbed78e
3 changed files with 41 additions and 42 deletions
|
|
@ -6,7 +6,6 @@ import (
|
|||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/meter/fritz"
|
||||
|
|
@ -23,8 +22,6 @@ import (
|
|||
type Connection struct {
|
||||
*request.Helper
|
||||
*fritz.Settings
|
||||
SID string
|
||||
updated time.Time
|
||||
}
|
||||
|
||||
// NewConnection creates FritzDECT connection
|
||||
|
|
@ -58,19 +55,13 @@ func NewConnection(uri, ain, user, password string) (*Connection, error) {
|
|||
|
||||
// ExecCmd execautes an FritzDECT AHA-HTTP-Interface command
|
||||
func (c *Connection) ExecCmd(function string) (string, error) {
|
||||
// refresh Fritzbox session id
|
||||
if time.Since(c.updated) >= fritz.SessionTimeout {
|
||||
sid, err := c.GetSessionID(c.Helper)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// update session timestamp
|
||||
c.SID = sid
|
||||
c.updated = time.Now()
|
||||
sid, err := c.GetSessionID(c.Helper)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
parameters := url.Values{
|
||||
"sid": {c.SID},
|
||||
"sid": {sid},
|
||||
"ain": {c.AIN},
|
||||
"switchcmd": {function},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,10 +21,8 @@ import (
|
|||
type Connection struct {
|
||||
*request.Helper
|
||||
*fritz.Settings
|
||||
SID string
|
||||
UID string // device UID (AIN with space)
|
||||
updated time.Time
|
||||
unitG util.Cacheable[Unit]
|
||||
UID string // device UID (AIN with space)
|
||||
unitG util.Cacheable[Unit]
|
||||
}
|
||||
|
||||
// NewConnection creates a new REST API connection
|
||||
|
|
@ -75,7 +73,8 @@ func ainToUID(ain string) string {
|
|||
|
||||
// getUnit fetches unit data from REST API
|
||||
func (c *Connection) getUnit() (Unit, error) {
|
||||
if err := c.refreshSession(); err != nil {
|
||||
sid, err := c.GetSessionID(c.Helper)
|
||||
if err != nil {
|
||||
return Unit{}, err
|
||||
}
|
||||
|
||||
|
|
@ -83,7 +82,7 @@ func (c *Connection) getUnit() (Unit, error) {
|
|||
uri := fmt.Sprintf("%s/api/v0/smarthome/overview/units/%s", c.URI, url.PathEscape(c.UID))
|
||||
|
||||
req, _ := request.New("GET", uri, nil, map[string]string{
|
||||
"Authorization": "AVM-SID " + c.SID,
|
||||
"Authorization": "AVM-SID " + sid,
|
||||
}, request.AcceptJSON)
|
||||
|
||||
var unit Unit
|
||||
|
|
@ -101,10 +100,15 @@ func (c *Connection) getUnit() (Unit, error) {
|
|||
|
||||
// findUnit searches for our unit in the list of all units
|
||||
func (c *Connection) findUnit() (Unit, error) {
|
||||
sid, err := c.GetSessionID(c.Helper)
|
||||
if err != nil {
|
||||
return Unit{}, err
|
||||
}
|
||||
|
||||
uri := fmt.Sprintf("%s/api/v0/smarthome/overview/units", c.URI)
|
||||
|
||||
req, err := request.New("GET", uri, nil, map[string]string{
|
||||
"Authorization": "AVM-SID " + c.SID,
|
||||
"Authorization": "AVM-SID " + sid,
|
||||
}, request.AcceptJSON)
|
||||
if err != nil {
|
||||
return Unit{}, err
|
||||
|
|
@ -201,7 +205,8 @@ func (c *Connection) SwitchOff() error {
|
|||
|
||||
// setSwitch sets the switch state via REST API
|
||||
func (c *Connection) setSwitch(on bool) error {
|
||||
if err := c.refreshSession(); err != nil {
|
||||
sid, err := c.GetSessionID(c.Helper)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -219,7 +224,7 @@ func (c *Connection) setSwitch(on bool) error {
|
|||
}
|
||||
|
||||
req, _ := request.New("PUT", uri, request.MarshalJSON(data), map[string]string{
|
||||
"Authorization": "AVM-SID " + c.SID,
|
||||
"Authorization": "AVM-SID " + sid,
|
||||
}, request.JSONEncoding)
|
||||
|
||||
var unit Unit
|
||||
|
|
@ -240,19 +245,3 @@ func (c *Connection) setSwitch(on bool) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// refreshSession ensures we have a valid session ID
|
||||
func (c *Connection) refreshSession() error {
|
||||
// refresh Fritzbox session id
|
||||
if time.Since(c.updated) >= fritz.SessionTimeout {
|
||||
sid, err := c.GetSessionID(c.Helper)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// update session timestamp
|
||||
c.SID = sid
|
||||
c.updated = time.Now()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
|
|
@ -20,12 +21,24 @@ const SessionTimeout = 15 * time.Minute
|
|||
type Settings struct {
|
||||
URI, AIN, User, Password string
|
||||
Firmware82 bool // use new REST API (FritzOS 8.2+)
|
||||
|
||||
mu sync.Mutex
|
||||
sid string
|
||||
updated time.Time
|
||||
}
|
||||
|
||||
// Fritzbox helpers (credits to https://github.com/rsdk/ahago)
|
||||
|
||||
// getSessionID fetches a session-id based on the username and password in the connection struct
|
||||
func (s Settings) GetSessionID(c *request.Helper) (string, error) {
|
||||
// GetSessionID returns a valid Fritzbox session ID, refreshing it when the
|
||||
// previously fetched session has timed out.
|
||||
func (s *Settings) GetSessionID(c *request.Helper) (string, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if time.Since(s.updated) < SessionTimeout {
|
||||
return s.sid, nil
|
||||
}
|
||||
|
||||
uri := fmt.Sprintf("%s/login_sid.lua", s.URI)
|
||||
body, err := c.GetBody(uri)
|
||||
if err != nil {
|
||||
|
|
@ -53,11 +66,17 @@ func (s Settings) GetSessionID(c *request.Helper) (string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return v.SID, err
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
s.sid = v.SID
|
||||
s.updated = time.Now()
|
||||
return v.SID, nil
|
||||
}
|
||||
|
||||
// createChallengeResponse creates the Fritzbox challenge response string
|
||||
func (s Settings) createChallengeResponse(challenge string) (string, error) {
|
||||
func (s *Settings) createChallengeResponse(challenge string) (string, error) {
|
||||
encoder := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
|
||||
utf16le, err := encoder.String(challenge + "-" + s.Password)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue