diff --git a/api/marshal.go b/api/marshal.go new file mode 100644 index 000000000..ec316e836 --- /dev/null +++ b/api/marshal.go @@ -0,0 +1,11 @@ +package api + +// BytesMarshaler marshals into bytes/string representation +type BytesMarshaler interface { + MarshalBytes() ([]byte, error) +} + +// BytesMarshaler marshals into a struct representation +type StructMarshaler interface { + MarshalStruct() (any, error) +} diff --git a/api/rates.go b/api/rates.go index f5baa8997..e1682da51 100644 --- a/api/rates.go +++ b/api/rates.go @@ -47,7 +47,9 @@ func (rr Rates) At(ts time.Time) (Rate, error) { return Rate{}, ErrNotAvailable } -// MarshalMQTT implements server.MQTTMarshaler -func (r Rates) MarshalMQTT() ([]byte, error) { +var _ BytesMarshaler = Rates{} + +// MarshalBytes implements server.BytesMarshaler +func (r Rates) MarshalBytes() ([]byte, error) { return json.Marshal(r) } diff --git a/server/mqtt.go b/server/mqtt.go index 30d5a6f5a..e9113fd50 100644 --- a/server/mqtt.go +++ b/server/mqtt.go @@ -18,12 +18,6 @@ import ( "github.com/samber/lo" ) -// MQTTMarshaler is the interface implemented by types that -// can marshal themselves into valid an MQTT string representation. -type MQTTMarshaler interface { - MarshalMQTT() ([]byte, error) -} - // MQTT is the MQTT server. It uses the MQTT client for publishing. type MQTT struct { log *util.Logger @@ -91,15 +85,25 @@ func (m *MQTT) publishComplex(topic string, retained bool, payload interface{}) return } - if mm, ok := payload.(MQTTMarshaler); ok { - if b, err := mm.MarshalMQTT(); err == nil { + if mm, ok := payload.(api.BytesMarshaler); ok { + if b, err := mm.MarshalBytes(); err == nil { m.publishSingleValue(topic, retained, string(b)) } else { - m.log.ERROR.Printf("marshal mqtt: %v", err) + m.log.ERROR.Printf("marshal bytes: %v", err) } return } + if mm, ok := payload.(api.StructMarshaler); ok { + if d, err := mm.MarshalStruct(); err != nil { + m.log.ERROR.Printf("marshal struct: %v", err) + return + } else { + payload = d + // fallthrough + } + } + switch typ := reflect.TypeOf(payload); typ.Kind() { case reflect.Slice: // publish count diff --git a/util/param_shard.go b/util/param_shard.go index ac78fc297..41411682b 100644 --- a/util/param_shard.go +++ b/util/param_shard.go @@ -7,6 +7,7 @@ import ( "strings" "sync" + "github.com/evcc-io/evcc/api" "github.com/fatih/structs" ) @@ -72,6 +73,12 @@ func (s *sharderImpl) Shards() []Shard { return res } +var _ api.StructMarshaler = (*sharderImpl)(nil) + +func (s *sharderImpl) MarshalStruct() (any, error) { + return s.struc, nil +} + var _ Sharder = (*sharderImpl)(nil) // NewSharder creates a Sharder that splits structs into sub-structs for space-efficient socket publishing