Skip to content

Commit af89012

Browse files
authored
Intg-1798 carvx decoder (#296)
* implement carvx decoding api, pending use side * implement usage and lint * add secrets * improve selection process for picking decoder
1 parent 54f84d2 commit af89012

14 files changed

Lines changed: 393 additions & 218 deletions

File tree

charts/device-definitions-api/templates/secret.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ spec:
8989
- remoteRef:
9090
key: {{ .Release.Namespace }}/definitions/17vin/password
9191
secretKey: JAPAN17_VIN_PASSWORD
92+
- remoteRef:
93+
key: {{ .Release.Namespace }}/definitions/carvx/userid
94+
secretKey: CAR_VX_USER_ID
95+
- remoteRef:
96+
key: {{ .Release.Namespace }}/definitions/carvx/apikey
97+
secretKey: CAR_VX_API_KEY
9298
secretStoreRef:
9399
kind: ClusterSecretStore
94100
name: aws-secretsmanager-secret-store

cmd/device-definitions-api/bulk_update_powertrain.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,6 @@ func (p *bulkUpdatePowertrain) Execute(ctx context.Context, _ *flag.FlagSet, _ .
150150
update, err := onChainSvc.Update(ctx, manufName, updateContract)
151151
if err != nil {
152152
fmt.Printf("%s: Error updating device definition: %v\n", definitionID, err)
153-
if strings.Contains(err.Error(), "nonce too low:") {
154-
time.Sleep(10 * time.Second)
155-
update, err = onChainSvc.Update(ctx, manufName, updateContract)
156-
if err != nil {
157-
fmt.Printf("%s: Error updating device definition: %v\n", definitionID, err)
158-
}
159-
}
160153
return subcommands.ExitFailure
161154
}
162155
fmt.Printf("%s: Updated device definition trx id: %s\nWaiting 10 seconds before next update\n", definitionID, *update)

cmd/device-definitions-api/decode_vin.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,23 @@ type decodeVINCmd struct {
3636
japan17vin bool
3737
fromFile bool
3838
persistToDB bool
39+
carvx bool
3940
}
4041

4142
func (*decodeVINCmd) Name() string { return "decodevin" }
4243
func (*decodeVINCmd) Synopsis() string {
4344
return "tries decoding a vin with chosen provider - does not insert in our db"
4445
}
4546
func (*decodeVINCmd) Usage() string {
46-
return `decodevin [-dat|-drivly|-vincario|-japan17vin|-from-file] <vin 17 chars OR filaname in /tmp> <country two letter iso>`
47+
return `decodevin [-dat|-drivly|-vincario|-japan17vin|carvx|-from-file] <vin 17 chars OR filaname in /tmp> <country two letter iso>`
4748
}
4849

4950
func (p *decodeVINCmd) SetFlags(f *flag.FlagSet) {
5051
f.BoolVar(&p.datGroup, "dat", false, "use dat group vin decoder")
5152
f.BoolVar(&p.drivly, "drivly", false, "use drivly vin decoder")
5253
f.BoolVar(&p.vincario, "vincario", false, "use vincario vin decoder")
5354
f.BoolVar(&p.japan17vin, "japan17vin", false, "use japan17vin vin decoder")
55+
f.BoolVar(&p.carvx, "carvx", false, "use carvx vin decoder")
5456
f.BoolVar(&p.fromFile, "from-file", false, "read vin from file in /tmp directory")
5557
f.BoolVar(&p.persistToDB, "persist-to-db", false, "persist successful vin decodings to db, table vin_numbers")
5658
}
@@ -106,15 +108,15 @@ func (p *decodeVINCmd) Execute(ctx context.Context, f *flag.FlagSet, _ ...interf
106108
if wmi != nil {
107109
dbVin.ManufacturerName = wmi.ManufacturerName
108110
}
109-
dt, err := models.DeviceTypes(models.DeviceTypeWhere.ID.EQ(common.DefaultDeviceType)).One(ctx, pdb.DBS().Reader)
111+
_, err := models.DeviceTypes(models.DeviceTypeWhere.ID.EQ(common.DefaultDeviceType)).One(ctx, pdb.DBS().Reader)
110112
if err != nil {
111113
fmt.Println(err.Error())
112114
return subcommands.ExitFailure
113115
}
114116
vinInfo := &coremodels.VINDecodingInfoData{VIN: vin}
115117

116118
if p.datGroup {
117-
vinInfo, err = vinDecodingService.GetVIN(ctx, vin, dt, coremodels.DATGroupProvider, country)
119+
vinInfo, err = vinDecodingService.GetVIN(ctx, vin, coremodels.DATGroupProvider, country)
118120
// use the dat group service to decode
119121
if err != nil {
120122
fmt.Println(err.Error())
@@ -124,7 +126,7 @@ func (p *decodeVINCmd) Execute(ctx context.Context, f *flag.FlagSet, _ ...interf
124126
fmt.Printf("\n\nVIN Response: %+v\n", vinInfo)
125127
}
126128
if p.drivly {
127-
vinInfo, err = vinDecodingService.GetVIN(ctx, vin, dt, coremodels.DrivlyProvider, country)
129+
vinInfo, err = vinDecodingService.GetVIN(ctx, vin, coremodels.DrivlyProvider, country)
128130
if err != nil {
129131
fmt.Println(err.Error())
130132
continue
@@ -133,16 +135,23 @@ func (p *decodeVINCmd) Execute(ctx context.Context, f *flag.FlagSet, _ ...interf
133135
fmt.Printf("VIN Response: %+v\n", vinInfo)
134136
}
135137
if p.vincario {
136-
vinInfo, err = vinDecodingService.GetVIN(ctx, vin, dt, coremodels.VincarioProvider, country)
138+
vinInfo, err = vinDecodingService.GetVIN(ctx, vin, coremodels.VincarioProvider, country)
139+
if err != nil {
140+
fmt.Println(err.Error())
141+
continue
142+
}
143+
fmt.Printf("VIN Response: %+v\n", vinInfo)
144+
}
145+
if p.carvx {
146+
vinInfo, err = vinDecodingService.GetVIN(ctx, vin, coremodels.CarVXVIN, country)
137147
if err != nil {
138148
fmt.Println(err.Error())
139149
continue
140150
}
141-
142151
fmt.Printf("VIN Response: %+v\n", vinInfo)
143152
}
144153
if p.japan17vin {
145-
vinInfo, err = vinDecodingService.GetVIN(ctx, vin, dt, coremodels.Japan17VIN, country)
154+
vinInfo, err = vinDecodingService.GetVIN(ctx, vin, coremodels.Japan17VIN, country)
146155
if err != nil {
147156
fmt.Println(err.Error())
148157
continue
@@ -240,6 +249,7 @@ func instantiateVINDecodingSvc(ctx context.Context, settings *config.Settings, l
240249
drivlyAPI := gateways.NewDrivlyAPIService(settings)
241250
vincarioAPI := gateways.NewVincarioAPIService(settings, logger)
242251
jp17vinAPI := gateways.NewJapan17VINAPI(logger, settings)
252+
carvxAPI := gateways.NewCarVxVINAPI(logger, settings)
243253

244254
send, err := createSender(ctx, settings, logger)
245255
if err != nil {
@@ -257,7 +267,7 @@ func instantiateVINDecodingSvc(ctx context.Context, settings *config.Settings, l
257267
}
258268
deviceDefinitionOnChainService := gateways.NewDeviceDefinitionOnChainService(settings, logger, ethClient, chainID, send, pdb.DBS)
259269

260-
vinDecodingService := services.NewVINDecodingService(drivlyAPI, vincarioAPI, nil, logger, deviceDefinitionOnChainService, datAPI, pdb.DBS, jp17vinAPI)
270+
vinDecodingService := services.NewVINDecodingService(drivlyAPI, vincarioAPI, nil, logger, deviceDefinitionOnChainService, datAPI, pdb.DBS, jp17vinAPI, carvxAPI)
261271

262272
return vinDecodingService
263273
}

internal/api/api.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ func Run(ctx context.Context, logger zerolog.Logger, settings *config.Settings,
6161
fuelAPIService := gateways.NewFuelAPIService(settings, &logger)
6262
autoIsoAPIService := gateways.NewAutoIsoAPIService(settings.AutoIsoAPIUid, settings.AutoIsoAPIKey)
6363
japan17VINAPI := gateways.NewJapan17VINAPI(&logger, settings)
64+
carvxAPI := gateways.NewCarVxVINAPI(&logger, settings)
6465
registryInstance, err := contracts.NewRegistry(settings.EthereumRegistryAddress, ethClient)
6566
if err != nil {
6667
logger.Fatal().Err(err).Msg("Failed to create registry query instance.")
@@ -74,7 +75,7 @@ func Run(ctx context.Context, logger zerolog.Logger, settings *config.Settings,
7475
vinRepository := repositories.NewVINRepository(pdb.DBS, registryInstance, identityAPI)
7576

7677
//cache services
77-
vincDecodingService := services.NewVINDecodingService(drivlyAPIService, vincarioAPIService, autoIsoAPIService, &logger, ddOnChainService, datGroupWSService, pdb.DBS, japan17VINAPI)
78+
vincDecodingService := services.NewVINDecodingService(drivlyAPIService, vincarioAPIService, autoIsoAPIService, &logger, ddOnChainService, datGroupWSService, pdb.DBS, japan17VINAPI, carvxAPI)
7879
powerTrainTypeService, err := services.NewPowerTrainTypeService("powertrain_type_rule.yaml", &logger, ddOnChainService)
7980
searchService := search.NewTypesenseAPIService(settings, &logger)
8081
if err != nil {

internal/config/settings.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ type Settings struct {
5353
GoogleSheetsCredentials string `yaml:"GOOGLE_SHEETS_CREDENTIALS"`
5454
Japan17VINUser string `yaml:"JAPAN17_VIN_USER"`
5555
Japan17VINPassword string `yaml:"JAPAN17_VIN_PASSWORD"`
56+
CarVxUserID string `yaml:"CAR_VX_USER_ID"`
57+
CarVxAPIKey string `yaml:"CAR_VX_API_KEY"`
5658
}
5759

5860
func (s *Settings) IsProd() bool {

internal/core/models/vin_decoding_models.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const (
1919
AllProviders DecodeProviderEnum = ""
2020
TeslaProvider DecodeProviderEnum = "tesla"
2121
Japan17VIN DecodeProviderEnum = "japan17vin"
22+
CarVXVIN DecodeProviderEnum = "carvxvin"
2223
)
2324

2425
type VINDecodingInfoData struct {
@@ -413,3 +414,22 @@ type Japan17MMY struct {
413414
ModelName string `json:"modelName"`
414415
Year int `json:"year"`
415416
}
417+
418+
// nolint
419+
type CarVxResponse struct {
420+
Data []struct {
421+
Make string `json:"make"`
422+
Model string `json:"model"`
423+
Grade string `json:"grade"`
424+
Body string `json:"body"`
425+
Engine string `json:"engine"`
426+
Drive string `json:"drive"`
427+
Transmission string `json:"transmission"`
428+
Fuel string `json:"fuel"`
429+
ManufactureDate struct {
430+
Year string `json:"year"`
431+
Month string `json:"month"`
432+
} `json:"manufacture_date"`
433+
} `json:"data"`
434+
Error string `json:"error"`
435+
}

internal/core/queries/decode_vin.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ func (dc DecodeVINQueryHandler) Handle(ctx context.Context, query mediator.Messa
186186
return resp, nil
187187
}
188188

189-
dt, err := models.DeviceTypes(models.DeviceTypeWhere.ID.EQ(common.DefaultDeviceType)).One(ctx, dc.dbs().Reader)
189+
_, err = models.DeviceTypes(models.DeviceTypeWhere.ID.EQ(common.DefaultDeviceType)).One(ctx, dc.dbs().Reader)
190190
if err != nil {
191191
metrics.InternalError.With(prometheus.Labels{"method": VinErrors}).Inc()
192192
return nil, errors.Wrap(err, "failed to get device_type")
@@ -201,13 +201,13 @@ func (dc DecodeVINQueryHandler) Handle(ctx context.Context, query mediator.Messa
201201
dbWMI, err := models.Wmis(models.WmiWhere.Wmi.EQ(wmi)).One(ctx, dc.dbs().Reader)
202202
if err == nil && dbWMI != nil {
203203
if dbWMI.ManufacturerName == "Tesla" {
204-
vinInfo, err = dc.vinDecodingService.GetVIN(ctx, vin.String(), dt, coremodels.TeslaProvider, qry.Country)
204+
vinInfo, err = dc.vinDecodingService.GetVIN(ctx, vin.String(), coremodels.TeslaProvider, qry.Country)
205205
resp.Manufacturer = "Tesla"
206206
}
207207
}
208208
// not a tesla, regular decode path
209209
if vinInfo == nil || vinInfo.Model == "" {
210-
vinInfo, err = dc.vinDecodingService.GetVIN(ctx, vin.String(), dt, coremodels.AllProviders, qry.Country) // this will try drivly first unless of japan
210+
vinInfo, err = dc.vinDecodingService.GetVIN(ctx, vin.String(), coremodels.AllProviders, qry.Country) // this will try drivly first unless of japan
211211
}
212212

213213
// if no luck decoding VIN, try buildingVinInfo from known data passed in, typically smartcar or software connections

internal/core/queries/decode_vin_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_WithExistingDD_UpdatesAt
147147
metaData, _ := json.Marshal(metaDataInfo)
148148
vinDecodingInfoData.MetaData = null.JSONFrom(metaData)
149149
definitionID := dd.ID
150-
s.mockVINService.EXPECT().GetVIN(ctx, vin, gomock.Any(), coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil)
150+
s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil)
151151
s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return("ICE")
152152
s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return(
153153
buildTestTblDD(definitionID, dd.Model, int(dd.Year)), nil, nil)
@@ -262,7 +262,7 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_CreatesDD_WithMismatchWM
262262
styleLevelPT := "PHEV"
263263
s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return(
264264
nil, nil, nil) // should return nil b/c doesn't exist
265-
s.mockVINService.EXPECT().GetVIN(ctx, vin, gomock.Any(), coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil)
265+
s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil)
266266
s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return(styleLevelPT)
267267

268268
trxHashHex := "0xa90868fe9364dbf41695b3b87e630f6455cfd63a4711f56b64f631b828c02b35"
@@ -416,7 +416,7 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_CreatesDD() {
416416
styleLevelPT := "PHEV"
417417
s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return(
418418
nil, nil, nil) // should return nil b/c doesn't exist
419-
s.mockVINService.EXPECT().GetVIN(ctx, vin, gomock.Any(), coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil)
419+
s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil)
420420
s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return(styleLevelPT)
421421

422422
trxHashHex := "0xa90868fe9364dbf41695b3b87e630f6455cfd63a4711f56b64f631b828c02b35"
@@ -530,7 +530,7 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_WithExistingDD_AndStyleA
530530
vinDecodingInfoData.MetaData = null.JSONFrom(metaData)
531531
definitionID := dd.ID
532532

533-
s.mockVINService.EXPECT().GetVIN(ctx, vin, gomock.Any(), coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil)
533+
s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil)
534534
s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return("HEV")
535535
s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return(
536536
buildTestTblDD(definitionID, dd.Model, int(dd.Year)), nil, nil)
@@ -624,7 +624,7 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_WithExistingWMI() {
624624
vinDecodingInfoData.MetaData = null.JSONFrom(metaData)
625625
definitionID := dd.ID
626626

627-
s.mockVINService.EXPECT().GetVIN(ctx, vin, gomock.Any(), coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil)
627+
s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil)
628628
s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return("HEV")
629629
s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return(
630630
buildTestTblDD(definitionID, dd.Model, int(dd.Year)), nil, nil)
@@ -677,7 +677,7 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_TeslaDecode() {
677677

678678
definitionID := dd.ID
679679

680-
s.mockVINService.EXPECT().GetVIN(ctx, vin, gomock.Any(), coremodels.TeslaProvider, "USA").Times(1).Return(vinDecodingInfoData, nil)
680+
s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.TeslaProvider, "USA").Times(1).Return(vinDecodingInfoData, nil)
681681
s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return("BEV")
682682
s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return(
683683
buildTestTblDD(definitionID, dd.Model, dd.Year), nil, nil)
@@ -775,7 +775,7 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_InvalidVINYear_AutoIso()
775775
Model: "Escape",
776776
}
777777
definitionID := "ford_escape_2017"
778-
s.mockVINService.EXPECT().GetVIN(ctx, vin, gomock.Any(), coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil)
778+
s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil)
779779
s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo("", "").Return("ICE") // normally this would return ""
780780
s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return(
781781
buildTestTblDD(definitionID, "Escape", 2021), nil, nil)
@@ -817,7 +817,7 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_InvalidStyleName_AutoIso
817817
StyleName: "1",
818818
}
819819
definitionID := "ford_escape_2017"
820-
s.mockVINService.EXPECT().GetVIN(ctx, vin, gomock.Any(), coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil)
820+
s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil)
821821
s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo("1", "").Return("ICE")
822822
s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return(
823823
buildTestTblDD(definitionID, "Escape", 2017), nil, nil)
@@ -857,7 +857,7 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Fail_DecodeErr() {
857857
_ = dbtesthelper.SetupCreateAutoPiIntegration(s.T(), s.pdb)
858858
_ = dbtesthelper.SetupCreateMake("Ford")
859859

860-
s.mockVINService.EXPECT().GetVIN(ctx, vin, gomock.Any(), coremodels.AllProviders, "USA").Times(1).Return(nil, fmt.Errorf("unable to decode"))
860+
s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(nil, fmt.Errorf("unable to decode"))
861861

862862
qryResult, err := s.queryHandler.Handle(s.ctx, &DecodeVINQuery{VIN: vin, Country: country})
863863
assert.Nil(s.T(), qryResult)
@@ -873,7 +873,7 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_DecodeKnownFallback() {
873873
_ = dbtesthelper.SetupCreateWMI(s.T(), "1FM", dm.Name, s.pdb)
874874

875875
definitionID := "ford_bronco_2022"
876-
s.mockVINService.EXPECT().GetVIN(ctx, vin, gomock.Any(), coremodels.AllProviders, "USA").Times(1).Return(nil, fmt.Errorf("unable to decode"))
876+
s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(nil, fmt.Errorf("unable to decode"))
877877
s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo("", "").Return("ICE")
878878

879879
s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return(

internal/core/services/mocks/vin_decoding_service_mock.go

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)