Initial cloud-services repo - gateway service + pkg modules
This commit is contained in:
143
pkg/manifestsender/tbox_config_manifest_sender.go
Normal file
143
pkg/manifestsender/tbox_config_manifest_sender.go
Normal file
@@ -0,0 +1,143 @@
|
||||
package manifestsender
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"errors"
|
||||
|
||||
"fiskerinc.com/modules/carcommand"
|
||||
"fiskerinc.com/modules/common"
|
||||
"fiskerinc.com/modules/common/carupdatestatus"
|
||||
"fiskerinc.com/modules/db/queries"
|
||||
"fiskerinc.com/modules/logger"
|
||||
"fiskerinc.com/modules/utils/whereami"
|
||||
)
|
||||
|
||||
// ProcessConfigUpdate handles all steps on the config only update
|
||||
// It will create a car_update record, manifest record, car_update_status record
|
||||
type ProcessConfigUpdateStruct struct {
|
||||
VIN string // The vin of the car that configuration we are generating
|
||||
Username string // The username of who is generating this update
|
||||
Name string // The name of the generated manifest, leave blank for auto generated. name,version is enforced unique
|
||||
SendToCar bool // True to send the manifest to the car
|
||||
DontCreateDatabaseEntry bool // False to create database entry, by default. Cannot be true with SendToCar being true
|
||||
Forced bool
|
||||
}
|
||||
|
||||
var ERR_SEND_AND_DATABASE_MISMATCH = errors.New("cannot send to car with dont create database entry")
|
||||
|
||||
// If called from aftersales, this will be marked as an aftersales update, which are not sent to the car
|
||||
// and they are automatically cancelled when they are hit cancel on the portal
|
||||
func (t *TBOXManifestSender) ProcessConfigUpdate(input ProcessConfigUpdateStruct, ccd queries.CarConfigDataInterface) (ucm common.UpdateConfigManifest, err error) {
|
||||
if input.DontCreateDatabaseEntry && input.SendToCar {
|
||||
return ucm, ERR_SEND_AND_DATABASE_MISMATCH
|
||||
}
|
||||
|
||||
// We have the send to car, so that should be all the info we need to make changes based on the system :()()
|
||||
// Get the VOD and CDSs for the car
|
||||
cds, err := t.getVODCDS(input.VIN, ccd)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
manifest := common.UpdateManifest{}
|
||||
if input.Name != "" {
|
||||
manifest.Name = input.Name
|
||||
} else {
|
||||
manifest.Name = fmt.Sprintf("configuration update %s %s", input.VIN, time.Now().Format("2006-01-02"))
|
||||
}
|
||||
|
||||
manifest.Version = time.Now().Format("2006-01-02 15:04:05")
|
||||
manifest.Description = fmt.Sprintf("configuration for %s by %s", input.VIN, input.Username)
|
||||
manifest.ManifestType = common.ConfigUpdateType
|
||||
|
||||
if input.Forced {
|
||||
manifest.Type = common.ManifestTypeForced
|
||||
} else {
|
||||
manifest.Type = common.ManifestTypeStandard
|
||||
}
|
||||
|
||||
manifestDB := t.db.GetUpdateManifests()
|
||||
if !input.DontCreateDatabaseEntry {
|
||||
_, err = manifestDB.Insert(&manifest)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// AddCDSToECUs calls AddVOD
|
||||
// AddECUsFromCDSList requires the manifest having been inserted so that they
|
||||
// have the manifestID
|
||||
manifest.AddECUsFromCDSList(cds)
|
||||
manifest.SortECUs()
|
||||
manifest.FillECUList()
|
||||
|
||||
// Create a car update for this manifest ot be sent as
|
||||
updatesDB := t.db.GetCarUpdates()
|
||||
update := common.CarUpdate{
|
||||
VIN: input.VIN,
|
||||
UpdateManifestID: manifest.ID,
|
||||
UpdateManifest: &manifest,
|
||||
Username: input.Username,
|
||||
Status: carupdatestatus.Pending,
|
||||
}
|
||||
|
||||
if whereami.Service == whereami.AFTERSALES {
|
||||
input.SendToCar = false
|
||||
update.UpdateSource = common.UPDATE_SOURCE_AFTERSALES
|
||||
} else {
|
||||
update.UpdateSource = common.UPDATE_SOURCE_OTA
|
||||
}
|
||||
|
||||
err = insertUpdateDatabase(input, updatesDB, manifestDB, manifest, &update)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
manifest.CarUpdateID = update.ID
|
||||
|
||||
manifest.Scrub(common.TRex)
|
||||
ucm = manifest.ToUpdateConfigManifest()
|
||||
|
||||
if !input.SendToCar {
|
||||
return
|
||||
}
|
||||
return ucm, t.SendConfig(input.VIN, ucm)
|
||||
}
|
||||
|
||||
func insertUpdateDatabase(input ProcessConfigUpdateStruct, updatesDB queries.CarUpdatesInterface, manifestDB queries.UpdateManifestsInterface, manifest common.UpdateManifest, update *common.CarUpdate) (err error) {
|
||||
if !input.DontCreateDatabaseEntry {
|
||||
_, err = updatesDB.InsertAndCreateStatus(update)
|
||||
if err != nil {
|
||||
_, err2 := manifestDB.Delete(&manifest)
|
||||
if err2 != nil {
|
||||
err = errors.Join(err, err2)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (t *TBOXManifestSender) SendConfig(vin string, manifest common.UpdateConfigManifest) (err error) {
|
||||
err = t.Redis.SafeQueueMessage(common.TRex.Key(vin), common.Message{
|
||||
Handler: "config_update",
|
||||
Data: manifest,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.At(logger.Info(), common.TRex.Key(vin), "update").Msgf("TBOXManifestSender sent %v %s %d", common.TRex, vin, manifest.CarUpdateID)
|
||||
|
||||
// For now, do not check on config update if the car wakes up correctly
|
||||
if manifest.Type == common.ManifestTypeForced && t.sms != nil{
|
||||
_, err = carcommand.QueueSMSWakeUp(vin, false, t.Redis, t.db.GetCars(), t.sms)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
180
pkg/manifestsender/tbox_manifest_sender.go
Normal file
180
pkg/manifestsender/tbox_manifest_sender.go
Normal file
@@ -0,0 +1,180 @@
|
||||
package manifestsender
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"fiskerinc.com/modules/carcommand"
|
||||
"fiskerinc.com/modules/common"
|
||||
"fiskerinc.com/modules/common/manifestfingerprintparams"
|
||||
"fiskerinc.com/modules/db/queries"
|
||||
q "fiskerinc.com/modules/db/queries"
|
||||
"fiskerinc.com/modules/grpc/sms"
|
||||
"fiskerinc.com/modules/logger"
|
||||
"fiskerinc.com/modules/redis"
|
||||
uhelpers "fiskerinc.com/modules/usecase_helpers"
|
||||
"fiskerinc.com/modules/validator"
|
||||
vconfig "fiskerinc.com/modules/vehicleconfig"
|
||||
errorspkg "github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var FailedToGetCDS = errors.New("did not send tbox as we had failed to get cds")
|
||||
|
||||
type ManifestSenderDB interface {
|
||||
GetUpdateManifests() q.UpdateManifestsInterface
|
||||
GetCars() q.CarsInterface
|
||||
GetCarUpdates() q.CarUpdatesInterface
|
||||
}
|
||||
|
||||
func NewTBOXManifestSender(
|
||||
r redis.Client,
|
||||
conf vconfig.ConfigServiceInterface,
|
||||
db ManifestSenderDB,
|
||||
sms sms.SMSServiceClient,
|
||||
cds map[string]string,
|
||||
) *TBOXManifestSender {
|
||||
t := &TBOXManifestSender{
|
||||
Redis: r,
|
||||
db: db,
|
||||
conf: conf,
|
||||
sms: sms,
|
||||
cds: cds,
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
type TBOXManifestSender struct {
|
||||
Redis redis.Client
|
||||
db ManifestSenderDB
|
||||
conf vconfig.ConfigServiceInterface
|
||||
sms sms.SMSServiceClient
|
||||
cds map[string]string // I think this can/should be removed. Unused in config route
|
||||
}
|
||||
|
||||
func (t *TBOXManifestSender) Close() {
|
||||
t.Redis = nil
|
||||
}
|
||||
|
||||
func (t *TBOXManifestSender) addRollback(manifest *common.UpdateManifest, vin string) error {
|
||||
if !manifest.RollbackEnabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
db := t.db.GetUpdateManifests()
|
||||
for _, ecu := range manifest.ECUs {
|
||||
var rollbacks []*common.UpdateManifestECU
|
||||
rollbacks, err = db.ECURollback(ecu, vin)
|
||||
if err != nil {
|
||||
return errorspkg.WithStack(err)
|
||||
}
|
||||
|
||||
ecu.Rollback = rollbacks
|
||||
}
|
||||
|
||||
manifest.RemoveOriginalS19HexFilesRollbacks()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Prepare a manifest, gets cds data if need be
|
||||
// This is called in two different locations. One form send_manifest.go and another from car_update_progress.go
|
||||
// send_manifest.go includes all the fields one could want, the car_update_progress is not
|
||||
func (t *TBOXManifestSender) ProcessSoftwareUpdate(vin string, manifest *common.UpdateManifest, ccd queries.CarConfigDataInterface) (smsID string, err error) {
|
||||
// Add rollbacks to manifest
|
||||
err = t.addRollback(manifest, vin)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// No CDS means some tasks in the send_manifest has not been run
|
||||
// like VOD, CDS, ECU sorting, removing original s19 hex files, and current versions
|
||||
if t.cds == nil {
|
||||
var cds map[string]string
|
||||
cds, err = t.getVODCDS(vin, ccd)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
t.cds = cds
|
||||
manifest.SortECUs()
|
||||
manifest.RemoveOriginalS19HexFiles()
|
||||
manifest.RemoveOriginalS19HexFilesRollbacks()
|
||||
|
||||
err = uhelpers.PopulateECUsCurrentVersion(t.db.GetCars(), vin, manifest.ECUs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Definitely need to transform the ECU's before the CDS are added so the names all match
|
||||
manifest.TransformECUNames()
|
||||
manifest.AddCDSToECUs(t.cds)
|
||||
manifest.FilterCompatibleECUs(vin)
|
||||
|
||||
err = t.checkSUMS(manifest)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fpparams := manifestfingerprintparams.GetFPParams()
|
||||
manifest.GenerateFingerprint(fpparams.CurTime(), fpparams.ManifestSerial())
|
||||
manifest.Scrub(common.TRex)
|
||||
|
||||
return t.Send(vin, *manifest)
|
||||
}
|
||||
|
||||
func (t *TBOXManifestSender) checkSUMS(manifest *common.UpdateManifest) error {
|
||||
if manifest.ManifestType == common.ConfigUpdateType {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := validator.ValidateField(manifest.SUMS, "required,sums_version")
|
||||
if err == nil {
|
||||
err = manifest.AddSUMSToVOD()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Send the update_manifest out redis to Trex, assume the manifest is all ready to go
|
||||
// If we try to send a wakeup sms and the car does not have an ICCID we do not fail, as hopefully it it a test trex
|
||||
func (t *TBOXManifestSender) Send(vin string, manifest common.UpdateManifest) (smsID string, err error) {
|
||||
logger.Debug().Msgf("Sending redis queue- %s, key- %s, hander- %s, data- %v", "manifestsender", vin, "update_manifest", manifest)
|
||||
err = t.Redis.SafeQueueMessage(common.TRex.Key(vin), common.Message{
|
||||
Handler: "update_manifest",
|
||||
Data: manifest,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Here need to wake it up again
|
||||
logger.At(logger.Info(), common.TRex.Key(vin), "update").Msgf("TBOXManifestSender sent %v %s %d", common.TRex, vin, manifest.CarUpdateID)
|
||||
if manifest.Type == common.ManifestTypeForced {
|
||||
var queueResponse *sms.SMSQueueResponse
|
||||
queueResponse, err = carcommand.QueueSMSWakeUp(vin, true, t.Redis, t.db.GetCars(), t.sms)
|
||||
if err != nil {
|
||||
if errors.Is(err, carcommand.ErrNoICCIDForWakeUp) {
|
||||
err = nil
|
||||
queueResponse.SentSuccessful = true
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if queueResponse.SentSuccessful {
|
||||
smsID = queueResponse.SmsMsgID
|
||||
} else {
|
||||
err = fmt.Errorf("failed to awake car for Send TBOXManifestSender for vin: %s, car update: %d", vin, manifest.CarUpdateID)
|
||||
}
|
||||
}
|
||||
|
||||
return smsID, err
|
||||
}
|
||||
|
||||
func (t *TBOXManifestSender) getVODCDS(vin string, db queries.CarConfigDataInterface) (map[string]string, error) {
|
||||
return uhelpers.GetCDS(t.conf, db, vin)
|
||||
}
|
||||
Reference in New Issue
Block a user