193 lines
6.4 KiB
Go
193 lines
6.4 KiB
Go
package cachev2
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/fiskerinc/cloud-services/pkg/dbc/state"
|
|
"github.com/fiskerinc/cloud-services/pkg/logger"
|
|
"github.com/fiskerinc/cloud-services/pkg/redis"
|
|
"github.com/fiskerinc/cloud-services/pkg/utils/querystring"
|
|
redigo "github.com/gomodule/redigo/redis"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
const (
|
|
pattern = "car:*:state"
|
|
)
|
|
|
|
type DigitalTwinTimestampState struct {
|
|
redisClient redis.Client
|
|
}
|
|
|
|
func NewDigitalTwinTimestampState(redisClient redis.Client) *DigitalTwinTimestampState {
|
|
return &DigitalTwinTimestampState{
|
|
redisClient: redisClient,
|
|
}
|
|
}
|
|
|
|
// getStateKeys retrieves car state keys from Redis based on the specified pattern
|
|
// and returns a sliced list of keys according to the provided offset and limit.
|
|
//
|
|
// Parameters:
|
|
// - offset: An integer indicating the starting index of the slice.
|
|
// - limit: An integer specifying the maximum number of elements in the sliced list.
|
|
//
|
|
// Returns:
|
|
// - []string: A sliced list of car state keys based on the given offset and limit.
|
|
// - error: An error, if any, encountered during the Redis operation or slicing process.
|
|
func (dtts *DigitalTwinTimestampState) getStateKeys(offset, limit int) ([]string, error) {
|
|
keys, err := redigo.Strings(dtts.redisClient.Execute("KEYS", pattern))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
totalKeys := len(keys)
|
|
if totalKeys <= offset {
|
|
return nil, nil
|
|
}
|
|
|
|
if (offset + limit) > totalKeys {
|
|
limit = totalKeys - offset
|
|
}
|
|
|
|
sort.Strings(keys)
|
|
|
|
keys = keys[offset : offset+limit]
|
|
return keys, nil
|
|
}
|
|
|
|
// readCarStateByKey retrieves data from Redis based on the specified key using the HGETALL command.
|
|
// It iterates over all keys and values returned by the command, sets them in a response map,
|
|
// and returns the populated map along with any encountered errors.
|
|
//
|
|
// Parameters:
|
|
// - key: A string representing the key to retrieve data from in Redis.
|
|
//
|
|
// Returns:
|
|
// - map[string]interface{}: A map containing keys and values retrieved from Redis.
|
|
// - error: An error, if any, encountered during the Redis HGETALL operation or mapping process.
|
|
func (dtts *DigitalTwinTimestampState) readCarStateByKey(key string) (map[string]interface{}, error) {
|
|
|
|
keyval := make(map[string]interface{})
|
|
batch := redis.NewRedisBatchCommands()
|
|
|
|
batch.Add("HGETALL", key)
|
|
|
|
payload, err := redigo.Values(dtts.redisClient.ExecuteBatch(batch))
|
|
if err != nil {
|
|
return keyval, err
|
|
}
|
|
|
|
stateValues, err := redigo.Values(payload[0], nil)
|
|
if err != nil {
|
|
return keyval, err
|
|
}
|
|
|
|
for i := 0; i < len(stateValues); i += 2 {
|
|
key, okKey := stateValues[i].([]byte)
|
|
value, okValue := stateValues[i+1].([]byte)
|
|
|
|
if !okKey || !okValue {
|
|
continue
|
|
}
|
|
|
|
err = dtts.parseCarState(string(key), value, keyval)
|
|
// log error, do not return error so we can read other properties for digital twin
|
|
if err != nil {
|
|
logger.Warn().Err(err).Send()
|
|
continue
|
|
}
|
|
}
|
|
return keyval, nil
|
|
}
|
|
|
|
// GetDigitalTwinSignals retrieves digital twin signals from Redis based on the specified offset and limit.
|
|
// It reads all signals from Redis and returns a list of maps, where each map represents a cars signal with its properties.
|
|
//
|
|
// Parameters:
|
|
// - offset: An integer indicating the starting index of the signals to retrieve.
|
|
// - limit: An integer specifying the maximum number of signals to retrieve.
|
|
//
|
|
// Returns:
|
|
// - []map[string]interface{}: A list of maps representing digital twin signals.
|
|
|
|
func (dtts *DigitalTwinTimestampState) GetDigitalTwinSignals(offset, limit int) (resp []map[string]interface{}) {
|
|
|
|
keys, err := dtts.getStateKeys(offset, limit)
|
|
if err != nil {
|
|
logger.Warn().Err(err).Send()
|
|
return
|
|
}
|
|
for _, key := range keys {
|
|
keyval, err := dtts.readCarStateByKey(key)
|
|
if err != nil {
|
|
logger.Warn().Err(err).Send()
|
|
continue
|
|
}
|
|
if len(keyval) > 0 {
|
|
keySlice := strings.Split(key, ":")
|
|
keyval["VIN"] = keySlice[1]
|
|
resp = append(resp, keyval)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// timestampKey generates a timestamp key based on the provided key by appending ":updated" to it.
|
|
// It formats the key in a way suitable for storing timestamps associated with the original key in data storage systems.
|
|
//
|
|
// Parameters:
|
|
// - key: A string representing the original key for which the timestamp key is generated.
|
|
//
|
|
// Returns:
|
|
// - string: A formatted string representing the timestamp key.
|
|
func (dtts *DigitalTwinTimestampState) timestampKey(key string) string {
|
|
return fmt.Sprintf("%s:%s", key, "updated")
|
|
}
|
|
|
|
// timestampVal parses a byte slice containing a JSON-encoded timestamp and returns a pointer to a time.Time
|
|
// representing the parsed timestamp. It uses the UnmarshalJSON method of the time.Time type for decoding.
|
|
//
|
|
// Parameters:
|
|
// - val: A byte slice containing the JSON-encoded timestamp to be parsed.
|
|
//
|
|
// Returns:
|
|
// - time.Time: A time representing the parsed timestamp.
|
|
// - error: An error, if any, encountered during the parsing process.
|
|
func (dtts *DigitalTwinTimestampState) timestampVal(val []byte) (time.Time, error) {
|
|
t := &time.Time{}
|
|
err := t.UnmarshalJSON(val)
|
|
return *t, err
|
|
}
|
|
|
|
// parseCarState checks if the provided key is needed and, if so, sets the key and value in the given map.
|
|
//
|
|
// Parameters:
|
|
// - key: A string representing the key to check and potentially set in the map.
|
|
// - value: A byte slice containing the value associated with the key.
|
|
// - keyval: A map[string]interface{} where the key and valueset if the key is needed.
|
|
//
|
|
// Returns:
|
|
// - error: An error, if any, encountered during the parsing and mapping process.
|
|
func (dtts *DigitalTwinTimestampState) parseCarState(key string, value []byte, keyval map[string]interface{}) error {
|
|
var err error
|
|
val := string(value)
|
|
switch key {
|
|
case state.BMS_PwrBattRmngCpSOC, state.BMS_RmChrgTi_FullChrg, state.BCM_PwrMod, state.PWC_ChrgSts, state.VCU_DCChrgRmngTi, state.BMS_RmChrgTi_TrgtSoC:
|
|
keyval[key], err = strconv.Atoi(val)
|
|
case state.ICC_TotMilg_ODO:
|
|
keyval[key], err = querystring.ConvertStringToInt(val)
|
|
case state.IBS_BatteryVoltage:
|
|
keyval[key], err = strconv.ParseFloat(val, 64)
|
|
|
|
// updated timestamps
|
|
case dtts.timestampKey(state.BMS_PwrBattRmngCpSOC), dtts.timestampKey(state.ICC_TotMilg_ODO), dtts.timestampKey(state.VCU_DCChrgRmngTi), dtts.timestampKey(state.BMS_RmChrgTi_TrgtSoC), dtts.timestampKey(state.IBS_BatteryVoltage),
|
|
dtts.timestampKey(state.BMS_RmChrgTi_FullChrg), dtts.timestampKey(state.BCM_PwrMod), dtts.timestampKey(state.PWC_ChrgSts):
|
|
keyval[key], err = dtts.timestampVal(value)
|
|
}
|
|
return errors.WithStack(err)
|
|
}
|