package manifestsender import ( "fmt" "time" "errors" "github.com/fiskerinc/cloud-services/pkg/carcommand" "github.com/fiskerinc/cloud-services/pkg/common" "github.com/fiskerinc/cloud-services/pkg/common/carupdatestatus" "github.com/fiskerinc/cloud-services/pkg/db/queries" "github.com/fiskerinc/cloud-services/pkg/logger" "github.com/fiskerinc/cloud-services/pkg/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 }