Add depot, attendant, jetfire, optimus, ota services with kustomize overlays
This commit is contained in:
118
services/depot/handlers/common.go
Normal file
118
services/depot/handlers/common.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/fiskerinc/cloud-services/services/depot/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
fv "github.com/fiskerinc/cloud-services/pkg/flashpackversion"
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// get vehicle settings
|
||||
func getSettings(db *services.DB, vin string) ([]common.CarSetting, error) {
|
||||
settings, err := db.GetCars().GetVehicleSpecificSettings(&common.CarToDriver{
|
||||
VIN: vin,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
osVersionSetting, err := getOSVersion(vin)
|
||||
if err == nil && osVersionSetting != nil {
|
||||
settings = append(settings, *osVersionSetting)
|
||||
} else {
|
||||
logger.Error().Msgf("failed to get os version %v", err)
|
||||
}
|
||||
|
||||
flashpackNumber, err := getFlashpackNumber(vin)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
if flashpackNumber != nil {
|
||||
settings = append(settings, *flashpackNumber)
|
||||
} else {
|
||||
logger.Warn().Msgf("no flashpack number yet for vin %s because not enough ECUs have been updated", vin)
|
||||
}
|
||||
|
||||
certNeedsRenewal, err := services.GetCertService().CheckCertificateNeedsRenewal(vin, common.CertICC)
|
||||
if err != nil {
|
||||
logger.Error().Msgf("failed to check for certificate renewal %v", err)
|
||||
} else if certNeedsRenewal {
|
||||
logger.Debug().Msg("ICC cert for vin " + vin + " is out of date")
|
||||
|
||||
settings = append(settings, common.CarSetting{
|
||||
Name: "certificates",
|
||||
Value: "expired",
|
||||
Type: "string",
|
||||
})
|
||||
}
|
||||
|
||||
clearSettings(settings)
|
||||
return settings, nil
|
||||
}
|
||||
|
||||
// Get the OS version given a vin
|
||||
func getOSVersion(vin string) (*common.CarSetting, error) {
|
||||
sumsVersion, err := getSUMS(vin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sumsDB := services.GetDB().GetUpdateManifestSUMSVersions()
|
||||
sums, err := sumsDB.Select(sumsVersion)
|
||||
if err != nil {
|
||||
logger.Error().Msgf("can not load SUMS, %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cs := common.CarSetting{
|
||||
Name: "os_version",
|
||||
Value: sums.OSVersion,
|
||||
Type: "string",
|
||||
}
|
||||
cs.CreatedAt = sums.CreatedAt
|
||||
cs.UpdatedAt = sums.UpdatedAt
|
||||
|
||||
return &cs, nil
|
||||
}
|
||||
|
||||
// Get the SUMS version from update manifest for a given vin
|
||||
func getSUMS(vin string) (sumsVersion string, err error) {
|
||||
carsDB := services.GetDB().GetCars()
|
||||
car, err := carsDB.SelectByVIN(vin)
|
||||
if err != nil {
|
||||
logger.Err(err).Msgf("failed in getSUMS(vin string) for car %s to fetch car", vin)
|
||||
return
|
||||
}
|
||||
|
||||
return car.SUMSVersion, err
|
||||
}
|
||||
|
||||
// Get the flash pack number
|
||||
func getFlashpackNumber(vin string) (*common.CarSetting, error) {
|
||||
cars := services.GetDB().GetCars()
|
||||
|
||||
car, err := cars.SelectByVIN(vin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
flashpackNumber, err := fv.FindCurrentFlashpackVersionForCar(cars, *car)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if flashpackNumber != "" {
|
||||
cs := &common.CarSetting{
|
||||
Name: "flashpack_number",
|
||||
Value: flashpackNumber,
|
||||
Type: "string",
|
||||
}
|
||||
|
||||
return cs, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
36
services/depot/handlers/hmi_del.go
Normal file
36
services/depot/handlers/hmi_del.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/fiskerinc/cloud-services/services/depot/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis"
|
||||
)
|
||||
|
||||
func HMIDel(db *services.DB, id string) error {
|
||||
client := services.RedisClientPool().GetFromPool()
|
||||
defer client.Close()
|
||||
|
||||
logger.Info().Msgf("Remove HMI session in Redis for %s", id)
|
||||
|
||||
err := removeHMISession(client, id)
|
||||
if err != nil {
|
||||
logger.Warn().Str("id", id).Err(err).Send()
|
||||
}
|
||||
|
||||
err = removeHMISessionID(client, id)
|
||||
if err != nil {
|
||||
logger.Warn().Str("id", id).Err(err).Send()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeHMISession(client redis.Client, id string) error {
|
||||
_, err := client.Execute("SREM", redis.HMISessionsKey(), id)
|
||||
return err
|
||||
}
|
||||
|
||||
func removeHMISessionID(client redis.Client, id string) error {
|
||||
return client.Delete(redis.HMISessionKey(id))
|
||||
}
|
||||
20
services/depot/handlers/hmi_del_test.go
Normal file
20
services/depot/handlers/hmi_del_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/depot/handlers"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/testhelper"
|
||||
)
|
||||
|
||||
func TestHMIDel(t *testing.T) {
|
||||
setupRedisMock()
|
||||
setupDBMock()
|
||||
|
||||
id := "FISKER123"
|
||||
err := handlers.HMIDel(mockDB, id)
|
||||
if err != nil {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestHMIDel", nil, err)
|
||||
}
|
||||
}
|
||||
99
services/depot/handlers/hmi_init.go
Normal file
99
services/depot/handlers/hmi_init.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/depot/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func HMIInit(db *services.DB, id string, data []byte) error {
|
||||
fmt.Printf("HMIInit()")
|
||||
client := services.RedisClientPool().GetFromPool()
|
||||
defer client.Close()
|
||||
|
||||
var sessionPayload common.HMISessionData
|
||||
err := json.Unmarshal(data, &sessionPayload)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
logger.Info().Msgf("Initialize HMI session in Redis for %s with ID %s", id, sessionPayload.SessionID)
|
||||
err = addHMISession(client, id)
|
||||
if err != nil {
|
||||
logger.Warn().Str("id", id).Err(err).Send()
|
||||
}
|
||||
|
||||
err = addHMISessionID(client, id, sessionPayload.SessionID)
|
||||
if err != nil {
|
||||
logger.Warn().Str("id", id).Err(err).Send()
|
||||
}
|
||||
|
||||
if sessionPayload.Salt != "" {
|
||||
err = addHMISaltID(client, id, sessionPayload.Salt)
|
||||
if err != nil {
|
||||
logger.Warn().Str("id", id).Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
err = sendSettingsHMI(client, db, id)
|
||||
if err != nil {
|
||||
logger.Warn().Str("id", id).Err(err).Send()
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addHMISession(client redis.Client, id string) error {
|
||||
_, err := client.Execute("SADD", redis.HMISessionsKey(), id)
|
||||
return err
|
||||
}
|
||||
|
||||
func addHMISessionID(client redis.Client, id string, sessionID string) error {
|
||||
_, err := client.Execute("SET", redis.HMISessionKey(id), sessionID)
|
||||
return err
|
||||
}
|
||||
|
||||
func addHMISaltID(client redis.Client, id string, salt string) error {
|
||||
_, err := client.Execute("SET", redis.HMISaltKey(id), salt)
|
||||
return err
|
||||
}
|
||||
|
||||
func sendSettingsHMI(client redis.Client, db *services.DB, vin string) error {
|
||||
|
||||
settings, err := getSettings(db, vin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(settings) == 0 {
|
||||
logger.Info().Msgf("no settings to send for car %s", vin)
|
||||
return nil
|
||||
}
|
||||
|
||||
return client.SafePublishMessage(common.HMI.Key(vin),
|
||||
common.Message{
|
||||
Handler: "car_settings",
|
||||
Data: settings,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func clearSettings(settings []common.CarSetting) {
|
||||
cTime := time.Now()
|
||||
for i, s := range settings {
|
||||
s.CreatedAt = nil
|
||||
if s.UpdatedAt == nil {
|
||||
s.UpdatedAt = &cTime
|
||||
}
|
||||
settings[i] = s
|
||||
}
|
||||
}
|
||||
30
services/depot/handlers/hmi_init_test.go
Normal file
30
services/depot/handlers/hmi_init_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/depot/handlers"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/testhelper"
|
||||
)
|
||||
|
||||
func TestHMIInit(t *testing.T) {
|
||||
setupRedisMock()
|
||||
setupDBMock()
|
||||
|
||||
id := "FISKER123"
|
||||
sessionData := common.HMISessionData{
|
||||
SessionID: "XXXXX",
|
||||
}
|
||||
data, err := json.Marshal(sessionData)
|
||||
if err != nil {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestHMIInit", nil, err)
|
||||
}
|
||||
|
||||
err = handlers.HMIInit(mockDB, id, data)
|
||||
if err != nil {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestHMIInit", nil, err)
|
||||
}
|
||||
}
|
||||
25
services/depot/handlers/mobile_del.go
Normal file
25
services/depot/handlers/mobile_del.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/fiskerinc/cloud-services/services/depot/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis"
|
||||
)
|
||||
|
||||
func MobileDel(db *services.DB, id string) error {
|
||||
client := services.RedisClientPool().GetFromPool()
|
||||
defer client.Close()
|
||||
|
||||
err := removeMobileSession(client, id)
|
||||
if err != nil {
|
||||
logger.Warn().Str("id", id).Err(err).Send()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeMobileSession(client redis.Client, id string) error {
|
||||
_, err := client.Execute("SREM", redis.MobileSessionsKey(), id)
|
||||
return err
|
||||
}
|
||||
20
services/depot/handlers/mobile_del_test.go
Normal file
20
services/depot/handlers/mobile_del_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/depot/handlers"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/testhelper"
|
||||
)
|
||||
|
||||
func TestMobileDel(t *testing.T) {
|
||||
setupRedisMock()
|
||||
setupDBMock()
|
||||
|
||||
id := "VALID-COGNITO-ID-1"
|
||||
err := handlers.MobileDel(mockDB, id)
|
||||
if err != nil {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestMobileDel", nil, err)
|
||||
}
|
||||
}
|
||||
60
services/depot/handlers/mobile_init.go
Normal file
60
services/depot/handlers/mobile_init.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/fiskerinc/cloud-services/services/depot/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis"
|
||||
)
|
||||
|
||||
func MobileInit(db *services.DB, id string) error {
|
||||
client := services.RedisClientPool().GetFromPool()
|
||||
defer client.Close()
|
||||
|
||||
err := addMobileSession(client, id)
|
||||
if err != nil {
|
||||
logger.Warn().Str("id", id).Err(err).Send()
|
||||
}
|
||||
|
||||
carDrivers, err := db.GetCars().GetCarsForDriver(id)
|
||||
if err != nil {
|
||||
logger.Error().Msgf("can not load cars for driver %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, carDriver := range carDrivers {
|
||||
sendSettingsMobile(client, db, carDriver.VIN, id)
|
||||
// If we fail to send the digital twin, it is not a major problem
|
||||
sendFullDigitalTwinToMobile(carDriver.VIN, id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addMobileSession(client redis.Client, id string) error {
|
||||
_, err := client.Execute("SADD", redis.MobileSessionsKey(), id)
|
||||
return err
|
||||
}
|
||||
|
||||
func sendSettingsMobile(client redis.Client, db *services.DB, vin, driverID string) error {
|
||||
settings, err := getSettings(db, vin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return client.SafePublishMessage(common.Mobile.Key(driverID),
|
||||
common.Message{
|
||||
Handler: "car_settings",
|
||||
Data: settings,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func sendFullDigitalTwinToMobile(vin string, driverID string) (err error) {
|
||||
err = services.GetSendDigitalTwin().SendToDriver(vin, driverID)
|
||||
if err != nil {
|
||||
logger.Err(err).Str("VIN", vin).Str("Driver ID", driverID).Msg("Failed to Send Full Digital Twin to Mobile Connection on INIT")
|
||||
}
|
||||
return
|
||||
}
|
||||
20
services/depot/handlers/mobile_init_test.go
Normal file
20
services/depot/handlers/mobile_init_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/depot/handlers"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/testhelper"
|
||||
)
|
||||
|
||||
func TestMobileInit(t *testing.T) {
|
||||
setupRedisMock()
|
||||
setupDBMock()
|
||||
|
||||
id := "VALID-COGNITO-ID-1"
|
||||
err := handlers.MobileInit(mockDB, id)
|
||||
if err != nil {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestMobileInit", nil, err)
|
||||
}
|
||||
}
|
||||
51
services/depot/handlers/mock_test.go
Normal file
51
services/depot/handlers/mock_test.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"github.com/fiskerinc/cloud-services/services/depot/services"
|
||||
|
||||
"github.com/go-pg/pg/v10/orm"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/db/queries/mocks"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis/tester"
|
||||
)
|
||||
|
||||
var mockRedis *redis.Connection
|
||||
var mockDB *services.DB
|
||||
|
||||
func setupRedisMock() {
|
||||
mockRedis := tester.NewRedisMock()
|
||||
services.SetRedisClientPool(tester.NewMockClientPool(mockRedis))
|
||||
}
|
||||
|
||||
func setupDBMock() {
|
||||
db := services.DB{}
|
||||
db.SetCars(&mocks.MockCars{
|
||||
SelectResponse: &common.Car{VIN: "FISKER123", ICCID: "1111111111111111111F"},
|
||||
SelectCarSettings: []common.CarSetting{},
|
||||
SelectCarECUs: []common.CarECU{
|
||||
{
|
||||
VIN: "FISKER123",
|
||||
ECU: "ADAS",
|
||||
SupplierSWVersion: "ADASVersion",
|
||||
},
|
||||
{
|
||||
VIN: "FISKER123",
|
||||
ECU: "ACUN",
|
||||
SupplierSWVersion: "ACUNVersion",
|
||||
},
|
||||
{
|
||||
VIN: "FISKER123",
|
||||
ECU: "BCM",
|
||||
SupplierSWVersion: "BCMVersion",
|
||||
},
|
||||
},
|
||||
})
|
||||
db.SetCarVersionsLog(&mocks.MockCarVersionsLog{MockLogVersionChange: func(log *common.CarVersionLogs) (orm.Result, error) {
|
||||
return nil, nil
|
||||
}})
|
||||
mockDB = &db
|
||||
services.SetDB(&db)
|
||||
}
|
||||
24
services/depot/handlers/trex_del.go
Normal file
24
services/depot/handlers/trex_del.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/fiskerinc/cloud-services/services/depot/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis"
|
||||
)
|
||||
|
||||
func TRexDel(id string) error {
|
||||
client := services.RedisClientPool().GetFromPool()
|
||||
defer client.Close()
|
||||
|
||||
err := removeTRexSession(client, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeTRexSession(client redis.Client, id string) error {
|
||||
_, err := client.Execute("SREM", redis.CarSessionsKey(), id)
|
||||
return err
|
||||
}
|
||||
20
services/depot/handlers/trex_del_test.go
Normal file
20
services/depot/handlers/trex_del_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/depot/handlers"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/testhelper"
|
||||
)
|
||||
|
||||
func TestTrexDel(t *testing.T) {
|
||||
setupRedisMock()
|
||||
setupDBMock()
|
||||
|
||||
id := "FISKER123"
|
||||
err := handlers.TRexDel(id)
|
||||
if err != nil {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestTrexDel", nil, err)
|
||||
}
|
||||
}
|
||||
336
services/depot/handlers/trex_init.go
Normal file
336
services/depot/handlers/trex_init.go
Normal file
@@ -0,0 +1,336 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/depot/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/cache"
|
||||
"github.com/fiskerinc/cloud-services/pkg/carcommand"
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/db/queries"
|
||||
"github.com/fiskerinc/cloud-services/pkg/dbc/state"
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
"github.com/fiskerinc/cloud-services/pkg/mongo"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis"
|
||||
"github.com/fiskerinc/cloud-services/pkg/userconsent"
|
||||
"github.com/fiskerinc/cloud-services/pkg/utils/envtool"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/loggerdataresp"
|
||||
"github.com/fiskerinc/cloud-services/pkg/utils"
|
||||
"github.com/fiskerinc/cloud-services/pkg/utils/elptr"
|
||||
"github.com/go-pg/pg/v10"
|
||||
redigo "github.com/gomodule/redigo/redis"
|
||||
"github.com/pkg/errors"
|
||||
mon "go.mongodb.org/mongo-driver/mongo"
|
||||
)
|
||||
|
||||
var errInvalidICCID = errors.New("invalid iccid submitted")
|
||||
var errBlocked = errors.New("unable to connect: car is blocked")
|
||||
var logLevel = envtool.GetEnv("TREX_LOG_LEVEL", common.CriticalLabel)
|
||||
var wakeUpVINS = envtool.GetEnv("WAKE_UP_VINS", "VCF1EBU2XPG001140")
|
||||
var defaultFleet = envtool.GetEnv("DEFAULT_FLEET", "Default-Ocean")
|
||||
|
||||
// id is the vehicles VIN
|
||||
func TRexInit(id string, vMap map[string]string) error {
|
||||
carsDB := services.GetDB().GetCars()
|
||||
blocked, err := insertIfNotExist(id, carsDB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if blocked {
|
||||
return errBlocked
|
||||
}
|
||||
|
||||
if strings.Contains(wakeUpVINS, id) {
|
||||
go wakeup(id)
|
||||
}
|
||||
|
||||
client := services.RedisClientPool().GetFromPool()
|
||||
defer client.Close()
|
||||
err = addTRexSession(client, id)
|
||||
if err != nil {
|
||||
logger.Warn().Str("id", id).Err(err).Send()
|
||||
}
|
||||
|
||||
m, err := services.GetMongoClient()
|
||||
if err != nil {
|
||||
logger.Warn().Str("id", id).Err(err).Send()
|
||||
} else {
|
||||
msg, err := retrieveTRexSettings(client, m, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Log the config that will be sent to TREX
|
||||
config, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info().Msgf("TREX Config sent for vin %s: \n%s", id, config)
|
||||
|
||||
err = sendTRexSettings(client, id, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = setTRexVersion(client, id, vMap["version"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = setDBCVersion(client, id, vMap["dbc_version"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = setTRexIP(client, id, vMap["ip"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = addICCID(carsDB, id, vMap["iccid"])
|
||||
if err != nil {
|
||||
logger.Warn().Err(err).Str("VIN", id).Str("ICCID", vMap["iccid"]).Msg("failed to add iccid to car")
|
||||
}
|
||||
|
||||
uMsg, err := getUserConsentData(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = sendTRexUserConsentData(client, id, uMsg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = checkAndRenewCertificate(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkAndRenewCertificate(id string) error {
|
||||
logger.Debug().Msg("on trex init: checking TBOX cert for vin " + id)
|
||||
|
||||
cs := services.GetCertService()
|
||||
certNeedsRenewal, err := cs.CheckCertificateNeedsRenewal(id, common.CertTBOX)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if certNeedsRenewal {
|
||||
logger.Debug().Msg("TBOX cert for vin " + id + " is out of date")
|
||||
|
||||
cert, err := cs.RenewCertificate(id, common.CertTBOX)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := services.RedisClientPool().GetFromPool()
|
||||
defer client.Close()
|
||||
|
||||
err = client.SafeQueueMessage(
|
||||
common.TRex.Key(id),
|
||||
common.Message{
|
||||
Handler: "update_cert",
|
||||
Data: common.UpdateCert{
|
||||
SSLCertBase64: cert.PublicKey,
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
logger.Debug().Msg("TBOX cert for vin " + id + " is not out of date")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getUserConsentData(id string) ([]common.UserConsentDataTrexMsg, error) {
|
||||
var ucdToSend = []common.UserConsentDataTrexMsg{}
|
||||
|
||||
resp, err := userconsent.GetUserConsentService().UserConsentByVehicleNumber(id)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, errors.New("call to user-consent/byVehicleNumber endpoint returned " + resp.Status)
|
||||
}
|
||||
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
ucdResult := []common.UserConsentDataResponse{}
|
||||
err = json.Unmarshal(respBody, &ucdResult)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
if len(ucdResult) < 1 {
|
||||
return ucdToSend, nil
|
||||
}
|
||||
|
||||
// only send to TREX the consents that have the userID of the first consent returned
|
||||
var userId = ucdResult[0].UserID
|
||||
for _, ucd := range ucdResult {
|
||||
if ucd.UserID == userId {
|
||||
ucdToSend = append(ucdToSend, common.BuildUserConsentTrexMessage(ucd))
|
||||
}
|
||||
}
|
||||
|
||||
return ucdToSend, nil
|
||||
}
|
||||
|
||||
func sendTRexUserConsentData(r redis.Client, id string, msg []common.UserConsentDataTrexMsg) error {
|
||||
|
||||
if len(msg) > 0 {
|
||||
return r.SafePublishMessage(
|
||||
common.TRex.Key(id),
|
||||
common.Message{
|
||||
Handler: "consent",
|
||||
Data: msg,
|
||||
},
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func insertIfNotExist(id string, carsDB queries.CarsInterface) (bool, error) {
|
||||
car, err := carsDB.SelectByVIN(id)
|
||||
if err == nil && car != nil {
|
||||
return car.Blocked, nil
|
||||
}
|
||||
if errors.Is(err, pg.ErrNoRows) {
|
||||
err = nil
|
||||
|
||||
c, err := utils.ParseVIN(id)
|
||||
if err != nil {
|
||||
return false, errors.WithStack(err)
|
||||
}
|
||||
|
||||
_, err = carsDB.Insert(c)
|
||||
if err != nil {
|
||||
return false, errors.WithStack(err)
|
||||
}
|
||||
|
||||
client, err := services.GetMongoClient()
|
||||
if err != nil {
|
||||
return false, errors.WithStack(err)
|
||||
}
|
||||
|
||||
v := &mongo.Vehicle{
|
||||
VIN: id,
|
||||
CANBus: common.CANBus{Enabled: true, DataLogger: true, DTCEnabled: elptr.ElPtr(false)},
|
||||
LogLevel: common.UnmarshalLogLevelString(logLevel),
|
||||
}
|
||||
err = client.GetVehicles().AddVehicle(v)
|
||||
if mon.IsDuplicateKeyError(err) {
|
||||
err = client.GetVehicles().UpdateVehicle(v)
|
||||
}
|
||||
if err != nil {
|
||||
return false, errors.WithStack(err)
|
||||
}
|
||||
|
||||
err = client.GetFleets().AddVehiclesToFleet(defaultFleet, []string{id})
|
||||
if err != nil {
|
||||
return false, errors.WithStack(err)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, errors.WithStack(err)
|
||||
}
|
||||
|
||||
func addICCID(db queries.CarsInterface, id, iccid string) error {
|
||||
// Going to only update where an iccid is valid
|
||||
if len(iccid) != 20 {
|
||||
return errInvalidICCID
|
||||
}
|
||||
|
||||
car := &common.Car{ICCID: iccid, VIN: id}
|
||||
|
||||
if ct, err := db.UpdateICCID(car); err != nil {
|
||||
return errors.Wrapf(err, "failed to update car's iccid %s", id)
|
||||
} else if ct.RowsAffected() == 1 {
|
||||
logger.Info().Msgf("car %s has been updated with iccid %s", id, iccid)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addTRexSession(client redis.Client, id string) error {
|
||||
_, err := client.Execute("SADD", redis.CarSessionsKey(), id)
|
||||
return err
|
||||
}
|
||||
|
||||
func retrieveTRexSettings(r redis.Client, m mongo.Client, id string) (*common.TRexConfigResponse, error) {
|
||||
return cache.RetrieveVehicleConfig(r, m, id)
|
||||
}
|
||||
|
||||
func sendTRexSettings(r redis.Client, id string, msg *common.TRexConfigResponse) error {
|
||||
err := r.SafePublishMessage(
|
||||
common.TRex.Key(id),
|
||||
common.Message{
|
||||
Handler: "config",
|
||||
Data: msg,
|
||||
},
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func setTRexIP(r redis.Client, vin, ip string) error {
|
||||
elms := strings.Split(ip, ":")
|
||||
|
||||
return r.SetObjectField(redis.CarStateHashKey(vin), state.TREX_IP, elms[0])
|
||||
}
|
||||
|
||||
func setDBCVersion(r redis.Client, vin, version string) error {
|
||||
return setVersion(r, vin, version, state.DBC_VERSION, common.DBCVersionSource)
|
||||
}
|
||||
|
||||
func setTRexVersion(r redis.Client, vin, version string) error {
|
||||
return setVersion(r, vin, version, state.TREX_VERSION, common.TREXVersionSource)
|
||||
}
|
||||
|
||||
func setVersion(r redis.Client, vin, version, redisField string, versionSource common.VersionSource) error {
|
||||
v, err := r.GetObjectField(redis.CarStateHashKey(vin), redisField)
|
||||
if err != nil && !errors.Is(err, redigo.ErrNil) {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
if v == version {
|
||||
return nil
|
||||
}
|
||||
|
||||
db := services.GetDB().GetCarVersionsLog()
|
||||
err = r.SetObjectField(redis.CarStateHashKey(vin), redisField, version)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
_, err = db.LogVersionChange(&common.CarVersionLogs{
|
||||
VIN: vin,
|
||||
VersionSource: versionSource,
|
||||
Version: version,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func wakeup(vin string) {
|
||||
wake := carcommand.NewCarWakeUp(services.GetDB().GetCars(), services.GetSMSClient())
|
||||
err := wake.WakeUp(vin, false)
|
||||
loggerdataresp.BadDataError(err)
|
||||
}
|
||||
78
services/depot/handlers/trex_init_test.go
Normal file
78
services/depot/handlers/trex_init_test.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/depot/handlers"
|
||||
"github.com/fiskerinc/cloud-services/services/depot/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/db/queries/mocks"
|
||||
"github.com/fiskerinc/cloud-services/pkg/grpc/sms"
|
||||
"github.com/fiskerinc/cloud-services/pkg/mongo"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis/tester"
|
||||
"github.com/fiskerinc/cloud-services/pkg/testhelper"
|
||||
"github.com/fiskerinc/cloud-services/pkg/userconsent"
|
||||
)
|
||||
|
||||
func TestTrexInit(t *testing.T) {
|
||||
rMock := tester.MockRedis{}
|
||||
rMock.Reset()
|
||||
|
||||
mockUserConsent := userconsent.UserConsentServiceMock{}
|
||||
userconsent.SetUserConsentService(&mockUserConsent)
|
||||
|
||||
mockCert := CertServiceMock{}
|
||||
services.SetCertService(&mockCert)
|
||||
|
||||
services.SetRedisClientPool(tester.NewMockClientPool(&rMock))
|
||||
id := "FISKER123"
|
||||
|
||||
setupDBMock()
|
||||
services.SetMongoClient(mongo.NewMockClient())
|
||||
|
||||
mockCertificates := mocks.MockCertificates{}
|
||||
mockCertificates.MockCertificate = &common.Certificate{
|
||||
PublicKey: "test",
|
||||
SerialNumber: "",
|
||||
Type: common.CertTBOX,
|
||||
}
|
||||
services.GetDB().SetCertificates(&mockCertificates)
|
||||
|
||||
mocksms := sms.NewSMSMockSuccess()
|
||||
services.SetSmsClient(&mocksms)
|
||||
|
||||
err := handlers.TRexInit(
|
||||
id,
|
||||
map[string]string{"version": "1.2.3", "iccid": "123456789123456789123456789", "ip": "172.20.0.17:49850"})
|
||||
if err != nil {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestTRexInit", nil, err)
|
||||
}
|
||||
|
||||
rez := rMock.SetValues[redis.CarStateHashKey(id)]
|
||||
if rez.Value.(string) != `{"ip":"172.20.0.17","trex_version":"1.2.3"}` {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestTRexInit_wrongVersion", `{"ip":"172.20.0.17","trex_version":"1.2.3"}`, rez.Value)
|
||||
}
|
||||
|
||||
rez = rMock.SetValues[redis.CarConfigKey(id)]
|
||||
if rez.Value.(string) != `{"canbus":{"enabled":false,"data_logger_enabled":false,"dtc_enabled":false},"log_level":"trace","log":{"matches":[{"channel":"cmd","level":"trace"}]}}` {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "TestTRexInit_wrongVersion", `{"canbus":{"enabled":false,"data_logger_enabled":false,"dtc_enabled":false},"log_level":"trace"}`, rez.Value)
|
||||
}
|
||||
}
|
||||
|
||||
type CertServiceMock struct{}
|
||||
|
||||
func (csm *CertServiceMock) CheckCertificateNeedsRenewal(vin string, certType string) (bool, error) {
|
||||
return certType == common.CertTBOX, nil
|
||||
}
|
||||
|
||||
func (csm *CertServiceMock) RenewCertificate(vin string, certType string) (*common.Certificate, error) {
|
||||
cert := common.Certificate{
|
||||
PublicKey: "test",
|
||||
SerialNumber: "",
|
||||
Type: common.CertTBOX,
|
||||
}
|
||||
|
||||
return &cert, nil
|
||||
}
|
||||
Reference in New Issue
Block a user