package models import ( "fmt" "github.com/fiskerinc/cloud-services/pkg/common" "github.com/fiskerinc/cloud-services/pkg/dbc/state" "github.com/fiskerinc/cloud-services/pkg/digitaltwin" "github.com/fiskerinc/cloud-services/pkg/grpc/kafka_grpc" "github.com/fiskerinc/cloud-services/pkg/logger" "github.com/pkg/errors" ) func GetShortKey(key string) string { // the version (hash) is represented as hex // we agreed to use 2 first bytes, so we need 4 characters of hex string const length = 4 if len(key) < length { return key } return key[:length] } type DBCCollectionInterface interface { Get(dbcHash string) (DBCVersionInterface, error) AddVersion(dbcHash string, dbcVersion DBCVersionInterface) DBCCollectionInterface ParseState(vin string, payload *kafka_grpc.GRPC_BatchPayload, cached digitaltwin.DigitalTwinCacheInterface) (map[string]interface{}, error) GetOrigKey(short string) (string, error) GetHashesList() []string } func NewDBCCollection(c map[string]DBCVersionInterface) DBCCollectionInterface { return &DBCCollection{ collections: c, } } type DBCCollection struct { collections map[string]DBCVersionInterface keys map[string]string options []DBCOption } func (d *DBCCollection) getCollectionMap() map[string]DBCVersionInterface { if d.collections == nil { d.collections = map[string]DBCVersionInterface{} } return d.collections } func (d *DBCCollection) getKeyMap() map[string]string { if d.keys == nil { d.keys = map[string]string{} } return d.keys } func (d *DBCCollection) GetHashesList() []string { var hashs []string for _, hash := range d.keys { hashs = append(hashs, hash) } return hashs } func (d *DBCCollection) Get(dbcHash string) (DBCVersionInterface, error) { c := d.getCollectionMap() key := GetShortKey(dbcHash) if db, ok := c[key]; ok { return db, nil } return nil, errors.Errorf("DBC %s does not exists", dbcHash) } func (d *DBCCollection) AddVersion(dbcHash string, dbcVersion DBCVersionInterface) DBCCollectionInterface { c := d.getCollectionMap() m := d.getKeyMap() key := GetShortKey(dbcHash) if _, ok := c[key]; ok { panic(fmt.Sprintf("DBC %s already exists", dbcHash)) } c[key] = dbcVersion m[key] = dbcHash return d } func (d *DBCCollection) GetOrigKey(short string) (string, error) { m := d.getKeyMap() short = GetShortKey(short) if key, ok := m[short]; ok { return key, nil } return "", ErrInvalidDBC(short) } func (d *DBCCollection) ParseState(vin string, payload *kafka_grpc.GRPC_BatchPayload, cached digitaltwin.DigitalTwinCacheInterface) (map[string]interface{}, error) { keyvalues := make(map[string]interface{}) dbc, err := d.Get(payload.Version) if err != nil { return nil, err } updated_at := d.processFrames(dbc, keyvalues, vin, payload.Data.Frames, cached) d.processOptions(keyvalues, vin) if len(keyvalues) > 0 { serialized, err := state.SerializeTimestampUSec(updated_at) if err != nil { return keyvalues, err } keyvalues[state.UPDATED_AT] = serialized } return keyvalues, nil } // cached: Local memory and digital twin, check to see if the value for that digital twin value is already saved in its given value func (d *DBCCollection) processFrames(dbc DBCVersionInterface, keyvaluesOut map[string]interface{}, vin string, frames []*kafka_grpc.GRPC_CANFrame, cached digitaltwin.DigitalTwinCacheInterface) int { var updated_at int for _, msg := range frames { incomingSignals, err := dbc.GenerateCANSignals(vin, msg) if err != nil { logger.At(logger.Warn(), common.TRex.Key(vin), "dbc"). Str("signal", fmt.Sprintf("%v", msg)). Str("dbc", dbc.Hash()). Err(err).Send() continue } updated_at = int(msg.Epoch) err = dbc.ParseState(int(msg.ID), keyvaluesOut, vin, updated_at, incomingSignals, cached) if err != nil { logger.At(logger.Warn(), common.TRex.Key(vin), "dbc"). Str("signal", fmt.Sprintf("%v", msg)). Str("dbc", dbc.Hash()). Err(err).Send() } } return updated_at } func (d *DBCCollection) processOptions(values map[string]interface{}, vin string) error { for _, option := range d.options { err := option.Handler(values, vin) if err != nil { return err } } return nil } /* func (d *DBCCollection) DiagnosticAlert(vin string, payload *kafka_grpc.GRPC_BatchPayload) ([]DiagnosticSignal, error) { var flags = make([]DiagnosticSignal, 0) dbc, err := d.Get(payload.Version) if err != nil { return nil, err } for _, msg := range payload.Data.Frames { signals, err := dbc.GenerateCANSignals(vin, msg) if err != nil { logger.Warn().Str("id", vin).Err(err).Msgf("%+v", msg) continue } alerts, err := dbc.DiagnosticAlert(int(msg.ID), vin, int(msg.Epoch), signals) if err != nil { logger.Warn().Str("id", vin).Err(err).Msgf("%+v", msg) } append(flags, alerts...) } return flags, err } */