Files
cloud-services/pkg/cache/vehicle_config.go

198 lines
5.0 KiB
Go

package cache
import (
"encoding/json"
"fiskerinc.com/modules/common"
"fiskerinc.com/modules/logger"
"fiskerinc.com/modules/mongo"
"fiskerinc.com/modules/redis"
"fiskerinc.com/modules/utils/envtool"
"fiskerinc.com/modules/utils/elptr"
redigo "github.com/gomodule/redigo/redis"
"github.com/pkg/errors"
)
const (
ENABLE_DBG_MASK_EV_NAME = "ENABLE_DEBUGMASK"
ENABLE_DBG_MASK_VAL_FALSE = "0"
ENABLE_DBG_MASK_VAL_TRUE = "1"
ENABLE_DBG_MASK_VAL_DEFAULT = ENABLE_DBG_MASK_VAL_FALSE
)
// This flag is to decide whether retrieved value of DebugMask is to be passed to TrexCfg or not.
// When the flag is true, the retrieved value is passed; else no value is passed.
// The value of flag is fetched from the specific environmental variable. If that environmental
// variable is not present / not defined, we assume the flag itself to be FALSE. That is the
// default value (FALSE) of the environmental variable. When user/developer has set this evironmental
// variable correctly, the flag can become TRUE in which case the value is passed to TrexCfg.
var ENABLE_DEBUG_MASK = DbgMaskEnabled()
// method introduced so as unit testing is easier otherwise not necessary since environment variables
// can't be changed so easily subsequent to a process start (meaning revaluation at runtime of no much use).
func DbgMaskEnabled() bool {
return envtool.GetEnv(ENABLE_DBG_MASK_EV_NAME, ENABLE_DBG_MASK_VAL_DEFAULT) == ENABLE_DBG_MASK_VAL_TRUE
}
func RetrieveVehicleConfig(r redis.Client, m mongo.Client, id string) (*common.TRexConfigResponse, error) {
config := &common.TRexConfigResponse{}
reply, err := checkCacheForVehicleConfig(r, id)
if err != nil {
return nil, errors.WithStack(err)
}
if reply != nil {
err = json.Unmarshal(reply, config)
if err != nil {
return nil, errors.WithStack(err)
}
if config.CANBus.DTCEnabled == nil {
config.CANBus.DTCEnabled = elptr.ElPtr(false)
}
return config, nil
}
config.LogLevel = common.Critical
config.Log = &common.LogConfig{
Matches: []common.LogConfigChannel{
{
Channel: common.ChannelCMD,
Level: common.Trace,
},
},
}
config.CANBus.Enabled = true
config.CANBus.DataLogger = true
filters := make(FiltersMap)
f, err := checkFleetsDBForVehicleConfig(m, id)
if err != nil {
logger.Warn().Err(err).Send()
}
if f != nil {
config.CANBus = f.CANBus
config.LogLevel = f.LogLevel
filters.AppendFilters(f.CANBus.Filters)
}
v, err := checkVehiclesDBForVehicleConfig(m, id)
if err != nil {
logger.Warn().Err(err).Send()
}
if v != nil {
config.CANBus = v.CANBus
config.LogLevel = v.LogLevel
config.DLTEnabled = v.DLTEnabled
config.DLTLevel = v.DLTLevel
// we should evaluate at run-time, not just at start-up time
if ENABLE_DEBUG_MASK {
config.DebugMask = v.DebugMask
}
config.IDPSEnabled = v.IDPSEnabled
filters.AppendFilters(v.CANBus.Filters)
}
config.CANBus.Filters = filters.ToSlice()
if config.CANBus.DTCEnabled == nil {
config.CANBus.DTCEnabled = elptr.ElPtr(false)
}
err = setCacheForVehicleConfig(r, id, config)
return config, err
}
func checkCacheForVehicleConfig(r redis.Client, id string) ([]byte, error) {
key := redis.CarConfigKey(id)
reply, err := redigo.Bytes(r.Execute("GET", key))
if err != nil {
if errors.Is(err, redigo.ErrNil) {
return nil, nil
}
return nil, err
}
return reply, nil
}
func checkVehiclesDBForVehicleConfig(m mongo.Client, id string) (*mongo.Vehicle, error) {
return m.GetVehicles().FindVehicle(&mongo.Vehicle{VIN: id})
}
func checkFleetsDBForVehicleConfig(m mongo.Client, id string) (*mongo.Fleet, error) {
return m.GetFleets().GetCANBusForVehicle(id)
}
func setCacheForVehicleConfig(r redis.Client, id string, config *common.TRexConfigResponse) error {
key := redis.CarConfigKey(id)
data, err := json.Marshal(config)
if err != nil {
return errors.WithStack(err)
}
batch := redis.NewRedisBatchCommands()
batch.Add("SET", key, data)
batch.Add("EXPIRE", key, redisObjectExpire)
_, err = r.ExecuteBatch(batch)
if err != nil {
return errors.WithStack(err)
}
return nil
}
func RemoveCacheConfigForVehicles(r redis.Client, vins []string) error {
batch := redis.NewRedisBatchCommands()
for _, vin := range vins {
batch.Add("DEL", redis.CarConfigKey(vin))
}
_, err := r.ExecuteBatch(batch)
if err != nil {
return errors.WithStack(err)
}
return nil
}
type IntervalEdgeMask struct {
Interval *int
EdgeMask *common.BinaryHex
}
type FiltersMap map[string]IntervalEdgeMask
func (f FiltersMap) AppendFilters(filters []common.CANFilter) {
for _, filter := range filters {
if filter.EdgeMask != nil && filter.EdgeMask.String() != "" {
f[filter.CANID] = IntervalEdgeMask{
EdgeMask: filter.EdgeMask,
}
} else if filter.Interval != nil {
f[filter.CANID] = IntervalEdgeMask{
Interval: filter.Interval,
}
}
}
}
func (f FiltersMap) ToSlice() []common.CANFilter {
filters := make([]common.CANFilter, 0, len(f))
for k, v := range f {
filters = append(filters, common.CANFilter{
CANID: k,
Interval: v.Interval,
EdgeMask: v.EdgeMask,
})
}
return filters
}