chore. fix memory leak with Cacheable objects (#5782)
This commit is contained in:
parent
9cc6d3f3bd
commit
6d7006fe65
5 changed files with 63 additions and 64 deletions
|
|
@ -22,8 +22,8 @@ type DaheimLaden struct {
|
|||
idTag string
|
||||
token string
|
||||
transactionID int32
|
||||
statusG func() (daheimladen.GetLatestStatus, error)
|
||||
meterG func() (daheimladen.GetLatestMeterValueResponse, error)
|
||||
statusCache provider.Cacheable[daheimladen.GetLatestStatus]
|
||||
meterCache provider.Cacheable[daheimladen.GetLatestMeterValueResponse]
|
||||
cache time.Duration
|
||||
}
|
||||
|
||||
|
|
@ -67,29 +67,30 @@ func NewDaheimLaden(token, stationID string, cache time.Duration) (*DaheimLaden,
|
|||
Base: c.Client.Transport,
|
||||
}
|
||||
|
||||
c.reset()
|
||||
c.statusCache = provider.ResettableCached(func() (daheimladen.GetLatestStatus, error) {
|
||||
var res daheimladen.GetLatestStatus
|
||||
err := c.GetJSON(fmt.Sprintf("%s/cs/%s/status", daheimladen.BASE_URL, c.stationID), &res)
|
||||
return res, err
|
||||
}, c.cache)
|
||||
|
||||
c.meterCache = provider.ResettableCached(func() (daheimladen.GetLatestMeterValueResponse, error) {
|
||||
var res daheimladen.GetLatestMeterValueResponse
|
||||
err := c.GetJSON(fmt.Sprintf("%s/cs/%s/metervalue", daheimladen.BASE_URL, c.stationID), &res)
|
||||
return res, err
|
||||
}, c.cache)
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// reset cache
|
||||
func (c *DaheimLaden) reset() {
|
||||
c.statusG = provider.Cached(func() (daheimladen.GetLatestStatus, error) {
|
||||
var res daheimladen.GetLatestStatus
|
||||
err := c.GetJSON(fmt.Sprintf("%s/cs/%s/status", daheimladen.BASE_URL, c.stationID), &res)
|
||||
return res, err
|
||||
}, c.cache)
|
||||
|
||||
c.meterG = provider.Cached(func() (daheimladen.GetLatestMeterValueResponse, error) {
|
||||
var res daheimladen.GetLatestMeterValueResponse
|
||||
err := c.GetJSON(fmt.Sprintf("%s/cs/%s/metervalue", daheimladen.BASE_URL, c.stationID), &res)
|
||||
return res, err
|
||||
}, c.cache)
|
||||
c.statusCache.Reset()
|
||||
c.meterCache.Reset()
|
||||
}
|
||||
|
||||
// Status implements the api.Charger interface
|
||||
func (c *DaheimLaden) Status() (api.ChargeStatus, error) {
|
||||
res, err := c.statusG()
|
||||
res, err := c.statusCache.Get()
|
||||
if err != nil {
|
||||
return api.StatusNone, err
|
||||
}
|
||||
|
|
@ -111,7 +112,7 @@ func (c *DaheimLaden) Status() (api.ChargeStatus, error) {
|
|||
|
||||
// Enabled implements the api.Charger interface
|
||||
func (c *DaheimLaden) Enabled() (bool, error) {
|
||||
res, err := c.statusG()
|
||||
res, err := c.statusCache.Get()
|
||||
return res.Status == string(daheimladen.CHARGING), err
|
||||
}
|
||||
|
||||
|
|
@ -192,7 +193,7 @@ var _ api.Meter = (*DaheimLaden)(nil)
|
|||
|
||||
// CurrentPower implements the api.Meter interface
|
||||
func (c *DaheimLaden) CurrentPower() (float64, error) {
|
||||
res, err := c.meterG()
|
||||
res, err := c.meterCache.Get()
|
||||
return float64(res.ActivePowerImport * 1e3), err
|
||||
}
|
||||
|
||||
|
|
@ -200,7 +201,7 @@ var _ api.MeterEnergy = (*DaheimLaden)(nil)
|
|||
|
||||
// TotalEnergy implements the api.MeterMeterEnergy interface
|
||||
func (c *DaheimLaden) TotalEnergy() (float64, error) {
|
||||
res, err := c.meterG()
|
||||
res, err := c.meterCache.Get()
|
||||
return float64(res.EnergyActiveImportRegister), err
|
||||
}
|
||||
|
||||
|
|
@ -208,6 +209,6 @@ var _ api.PhaseCurrents = (*DaheimLaden)(nil)
|
|||
|
||||
// Currents implements the api.PhaseCurrents interface
|
||||
func (c *DaheimLaden) Currents() (float64, float64, float64, error) {
|
||||
res, err := c.meterG()
|
||||
res, err := c.meterCache.Get()
|
||||
return float64(res.CurrentImportPhaseL1), float64(res.CurrentImportPhaseL2), float64(res.CurrentImportPhaseL3), err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ func init() {
|
|||
type MyStrom struct {
|
||||
conn *mystrom.Connection
|
||||
*switchSocket
|
||||
cache time.Duration
|
||||
reportG func() (mystrom.Report, error)
|
||||
cache time.Duration
|
||||
reportCache provider.Cacheable[mystrom.Report]
|
||||
}
|
||||
|
||||
// NewMyStromFromConfig creates a myStrom charger from generic config
|
||||
|
|
@ -45,21 +45,21 @@ func NewMyStromFromConfig(other map[string]interface{}) (api.Charger, error) {
|
|||
}
|
||||
|
||||
c.switchSocket = NewSwitchSocket(c.Enabled, c.conn.CurrentPower, cc.StandbyPower)
|
||||
c.reportG = provider.Cached(c.conn.Report, c.cache)
|
||||
c.reportCache = provider.ResettableCached(c.conn.Report, c.cache)
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Enabled implements the api.Charger interface
|
||||
func (c *MyStrom) Enabled() (bool, error) {
|
||||
res, err := c.reportG()
|
||||
res, err := c.reportCache.Get()
|
||||
return res.Relay, err
|
||||
}
|
||||
|
||||
// Enable implements the api.Charger interface
|
||||
func (c *MyStrom) Enable(enable bool) error {
|
||||
// reset cache
|
||||
c.reportG = provider.Cached(c.conn.Report, c.cache)
|
||||
c.reportCache.Reset()
|
||||
|
||||
onoff := map[bool]int{false: 0, true: 1}
|
||||
return c.conn.Request(fmt.Sprintf("relay?state=%d", onoff[enable]))
|
||||
|
|
|
|||
|
|
@ -37,12 +37,12 @@ import (
|
|||
// smaevchager charger implementation
|
||||
type Smaevcharger struct {
|
||||
*request.Helper
|
||||
log *util.Logger
|
||||
uri string // 192.168.XXX.XXX
|
||||
cache time.Duration
|
||||
oldstate float64
|
||||
measurementG func() ([]smaevcharger.Measurements, error)
|
||||
parameterG func() ([]smaevcharger.Parameters, error)
|
||||
log *util.Logger
|
||||
uri string // 192.168.XXX.XXX
|
||||
cache time.Duration
|
||||
oldstate float64
|
||||
measurementCache provider.Cacheable[[]smaevcharger.Measurements]
|
||||
parameterCache provider.Cacheable[[]smaevcharger.Parameters]
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
@ -95,7 +95,8 @@ func NewSmaevcharger(uri, user, password string, cache time.Duration) (api.Charg
|
|||
}
|
||||
|
||||
// setup cached values
|
||||
wb.reset()
|
||||
wb.measurementCache = provider.ResettableCached(wb._measurementData, wb.cache)
|
||||
wb.parameterCache = provider.ResettableCached(wb._parameterData, wb.cache)
|
||||
|
||||
ts, err := smaevcharger.TokenSource(log, wb.uri, user, password)
|
||||
if err != nil {
|
||||
|
|
@ -267,8 +268,8 @@ func (wb *Smaevcharger) Currents() (float64, float64, float64, error) {
|
|||
|
||||
// reset cache
|
||||
func (wb *Smaevcharger) reset() {
|
||||
wb.measurementG = provider.Cached(wb._measurementData, wb.cache)
|
||||
wb.parameterG = provider.Cached(wb._parameterData, wb.cache)
|
||||
wb.measurementCache.Reset()
|
||||
wb.parameterCache.Reset()
|
||||
}
|
||||
|
||||
func (wb *Smaevcharger) _measurementData() ([]smaevcharger.Measurements, error) {
|
||||
|
|
@ -298,7 +299,7 @@ func (wb *Smaevcharger) _parameterData() ([]smaevcharger.Parameters, error) {
|
|||
}
|
||||
|
||||
func (wb *Smaevcharger) getMeasurement(id string) (float64, error) {
|
||||
res, err := wb.measurementG()
|
||||
res, err := wb.measurementCache.Get()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
@ -313,7 +314,7 @@ func (wb *Smaevcharger) getMeasurement(id string) (float64, error) {
|
|||
}
|
||||
|
||||
func (wb *Smaevcharger) getParameter(id string) (string, error) {
|
||||
res, err := wb.parameterG()
|
||||
res, err := wb.parameterCache.Get()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,11 +41,11 @@ import (
|
|||
// Zaptec charger implementation
|
||||
type Zaptec struct {
|
||||
*request.Helper
|
||||
log *util.Logger
|
||||
statusG func() (zaptec.StateResponse, error)
|
||||
id string
|
||||
priority bool
|
||||
cache time.Duration
|
||||
log *util.Logger
|
||||
statusCache provider.Cacheable[zaptec.StateResponse]
|
||||
id string
|
||||
priority bool
|
||||
cache time.Duration
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
@ -91,7 +91,14 @@ func NewZaptec(user, password, id string, priority bool, cache time.Duration) (a
|
|||
}
|
||||
|
||||
// setup cached values
|
||||
c.reset()
|
||||
c.statusCache = provider.ResettableCached(func() (zaptec.StateResponse, error) {
|
||||
var res zaptec.StateResponse
|
||||
|
||||
uri := fmt.Sprintf("%s/api/chargers/%s/state", zaptec.ApiURL, c.id)
|
||||
err := c.GetJSON(uri, &res)
|
||||
|
||||
return res, err
|
||||
}, c.cache)
|
||||
|
||||
data := url.Values{
|
||||
"grant_type": {"password"},
|
||||
|
|
@ -118,17 +125,6 @@ func NewZaptec(user, password, id string, priority bool, cache time.Duration) (a
|
|||
return c, err
|
||||
}
|
||||
|
||||
func (c *Zaptec) reset() {
|
||||
c.statusG = provider.Cached(func() (zaptec.StateResponse, error) {
|
||||
var res zaptec.StateResponse
|
||||
|
||||
uri := fmt.Sprintf("%s/api/chargers/%s/state", zaptec.ApiURL, c.id)
|
||||
err := c.GetJSON(uri, &res)
|
||||
|
||||
return res, err
|
||||
}, c.cache)
|
||||
}
|
||||
|
||||
func (c *Zaptec) chargers() ([]string, error) {
|
||||
var res zaptec.ChargersResponse
|
||||
|
||||
|
|
@ -145,7 +141,7 @@ func (c *Zaptec) chargers() ([]string, error) {
|
|||
|
||||
// Status implements the api.Charger interface
|
||||
func (c *Zaptec) Status() (api.ChargeStatus, error) {
|
||||
res, err := c.statusG()
|
||||
res, err := c.statusCache.Get()
|
||||
if err != nil {
|
||||
return api.StatusA, err
|
||||
}
|
||||
|
|
@ -167,7 +163,7 @@ func (c *Zaptec) Status() (api.ChargeStatus, error) {
|
|||
|
||||
// Enabled implements the api.Charger interface
|
||||
func (c *Zaptec) Enabled() (bool, error) {
|
||||
res, err := c.statusG()
|
||||
res, err := c.statusCache.Get()
|
||||
return res.ObservationByID(zaptec.IsEnabled).Bool() && !res.ObservationByID(zaptec.FinalStopActive).Bool(), err
|
||||
}
|
||||
|
||||
|
|
@ -183,7 +179,7 @@ func (c *Zaptec) Enable(enable bool) error {
|
|||
req, err := request.New(http.MethodPost, uri, nil, request.JSONEncoding)
|
||||
if err == nil {
|
||||
_, err = c.DoBody(req)
|
||||
c.reset()
|
||||
c.statusCache.Reset()
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
@ -195,7 +191,7 @@ func (c *Zaptec) chargerUpdate(data zaptec.Update) error {
|
|||
req, err := request.New(http.MethodPost, uri, request.MarshalJSON(data), request.JSONEncoding)
|
||||
if err == nil {
|
||||
_, err = c.DoBody(req)
|
||||
c.reset()
|
||||
c.statusCache.Reset()
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
@ -207,7 +203,7 @@ func (c *Zaptec) sessionPriority(session string, data zaptec.SessionPriority) er
|
|||
req, err := request.New(http.MethodPost, uri, request.MarshalJSON(data), request.JSONEncoding)
|
||||
if err == nil {
|
||||
_, err = c.DoBody(req)
|
||||
c.reset()
|
||||
c.statusCache.Reset()
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
@ -227,7 +223,7 @@ var _ api.Meter = (*Zaptec)(nil)
|
|||
|
||||
// CurrentPower implements the api.Meter interface
|
||||
func (c *Zaptec) CurrentPower() (float64, error) {
|
||||
res, err := c.statusG()
|
||||
res, err := c.statusCache.Get()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
@ -239,7 +235,7 @@ var _ api.ChargeRater = (*Zaptec)(nil)
|
|||
|
||||
// ChargedEnergy implements the api.ChargeRater interface
|
||||
func (c *Zaptec) ChargedEnergy() (float64, error) {
|
||||
res, err := c.statusG()
|
||||
res, err := c.statusCache.Get()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
@ -251,7 +247,7 @@ var _ api.PhaseCurrents = (*Zaptec)(nil)
|
|||
|
||||
// Currents implements the api.PhaseCurrents interface
|
||||
func (c *Zaptec) Currents() (float64, float64, float64, error) {
|
||||
res, err := c.statusG()
|
||||
res, err := c.statusCache.Get()
|
||||
if err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
|
|
@ -270,7 +266,7 @@ var _ api.PhaseSwitcher = (*Zaptec)(nil)
|
|||
|
||||
// Phases1p3p implements the api.ChargePhases interface
|
||||
func (c *Zaptec) Phases1p3p(phases int) error {
|
||||
res, err := c.statusG()
|
||||
res, err := c.statusCache.Get()
|
||||
|
||||
if err == nil {
|
||||
data := zaptec.Update{
|
||||
|
|
@ -299,7 +295,7 @@ var _ api.Diagnosis = (*Zaptec)(nil)
|
|||
|
||||
// Diagnosis implements the api.ChargePhases interface
|
||||
func (c *Zaptec) Diagnose() {
|
||||
res, _ := c.statusG()
|
||||
res, _ := c.statusCache.Get()
|
||||
|
||||
// sort for printing
|
||||
sort.Slice(res, func(i, j int) bool {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ type cached[T any] struct {
|
|||
// Cached wraps a getter with a cache
|
||||
func Cached[T any](g func() (T, error), cache time.Duration) func() (T, error) {
|
||||
c := ResettableCached(g, cache)
|
||||
_ = bus.Subscribe(reset, c.Reset)
|
||||
return c.Get
|
||||
}
|
||||
|
||||
|
|
@ -51,11 +50,13 @@ var _ Cacheable[int64] = (*cached[int64])(nil)
|
|||
// ResettableCached wraps a getter with a cache. It returns a `Cacheable`.
|
||||
// Instead of the cached getter, the `Get()` and `Reset()` methods are exposed.
|
||||
func ResettableCached[T any](g func() (T, error), cache time.Duration) *cached[T] {
|
||||
return &cached[T]{
|
||||
c := &cached[T]{
|
||||
clock: clock.New(),
|
||||
cache: cache,
|
||||
g: g,
|
||||
}
|
||||
_ = bus.Subscribe(reset, c.Reset)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *cached[T]) Get() (T, error) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue