diff --git a/charts/device-definitions-api/templates/secret.yaml b/charts/device-definitions-api/templates/secret.yaml index 20e89724..7c7c7548 100644 --- a/charts/device-definitions-api/templates/secret.yaml +++ b/charts/device-definitions-api/templates/secret.yaml @@ -6,17 +6,14 @@ metadata: spec: data: - remoteRef: - key: {{ .Release.Namespace }}/definitions/ethereum/rpc_url - secretKey: ETHEREUM_RPC_URL + key: {{ .Release.Namespace }}/definitions/worker/token + secretKey: DEFINITIONS_WORKER_TOKEN - remoteRef: key: {{ .Release.Namespace }}/definitions/aws/access_key_id secretKey: AWS_ACCESS_KEY_ID - remoteRef: key: {{ .Release.Namespace }}/definitions/aws/secret_access_key secretKey: AWS_SECRET_ACCESS_KEY - - remoteRef: - key: {{ .Release.Namespace }}/definitions/kms/key_id - secretKey: KMS_KEY_ID - remoteRef: key: {{ .Release.Namespace }}/definitions/db/host secretKey: DB_HOST @@ -77,9 +74,6 @@ spec: - remoteRef: key: {{ .Release.Namespace }}/definitions/typesense/apiurl secretKey: SEARCH_SERVICE_API_URL - - remoteRef: - key: {{ .Release.Namespace }}/definitions/polygonscan/apikey - secretKey: POLYGON_SCAN_API_KEY - remoteRef: key: {{ .Release.Namespace }}/definitions/googlesheets/credentials secretKey: GOOGLE_SHEETS_CREDENTIALS diff --git a/charts/device-definitions-api/values-prod.yaml b/charts/device-definitions-api/values-prod.yaml index 313192f4..8a77fa45 100644 --- a/charts/device-definitions-api/values-prod.yaml +++ b/charts/device-definitions-api/values-prod.yaml @@ -20,10 +20,13 @@ env: REDIS_CLUSTER_MODE: true REDIS_TLS: true KAFKA_BROKERS: kafka-prod-dimo-kafka-kafka-brokers:9092 - ETHEREUM_SEND_TRANSACTION: true - TABLELAND_API_GATEWAY: http://tableland-node-prod.prod.svc.cluster.local:8080/ - ETHEREUM_REGISTRY_ADDRESS: '0xFA8beC73cebB9D88FF88a2f75E7D7312f2Fd39EC' - SEARCH_SERVICE_DEVICE_DEFINITION_INDEX: definitions_prod + # One hostname on purpose: definitions-worker is what serves + # definitions.dimo.org, so there is no separate origin to read through. + # A read that must not be served from the edge cache misses it by cache + # key instead -- see fetchTemplateDocFresh's cache-busting parameter. + DEFINITIONS_CATALOG_URL: https://definitions.dimo.org + DEFINITIONS_WORKER_URL: https://definitions.dimo.org + SEARCH_SERVICE_DEVICE_DEFINITION_INDEX: definitions_v2_prod IDENTITY_API_URL: https://identity-api.dimo.zone/query ingress: enabled: true @@ -58,9 +61,4 @@ tolerations: [] affinity: {} podDisruptionBudget: minAvailable: 1 -jobs: - - name: device-definitions-search-sync - schedule: 0 13 * * * - args: - - '-c' - - /device-definitions-api sync-device-definitions-search; CODE=$?; echo "daily device definitions typesense search sync completed"; wget -q --post-data "hello=shutdown" http://localhost:4191/shutdown &> /dev/null; exit $CODE; +jobs: [] diff --git a/charts/device-definitions-api/values.yaml b/charts/device-definitions-api/values.yaml index 9abed512..3e5bac98 100644 --- a/charts/device-definitions-api/values.yaml +++ b/charts/device-definitions-api/values.yaml @@ -51,10 +51,13 @@ env: VINCARIO_API_URL: https://api.vindecoder.eu/3.2 DAT_GROUP_URL: https://www.datgroup.com/myClaim/soap/v2/VehicleIdentificationService PRIVATE_KEY_MODE: false - ETHEREUM_SEND_TRANSACTION: true - TABLELAND_API_GATEWAY: http://tableland-node-dev.dev.svc.cluster.local:8080/ - ETHEREUM_REGISTRY_ADDRESS: '0x5eAA326fB2fc97fAcCe6A79A304876daD0F2e96c' - SEARCH_SERVICE_DEVICE_DEFINITION_INDEX: definitions_dev + # One hostname on purpose: definitions-worker is what serves + # definitions.dev.dimo.org, so there is no separate origin to read through. + # A read that must not be served from the edge cache misses it by cache + # key instead -- see fetchTemplateDocFresh's cache-busting parameter. + DEFINITIONS_CATALOG_URL: https://definitions.dev.dimo.org + DEFINITIONS_WORKER_URL: https://definitions.dev.dimo.org + SEARCH_SERVICE_DEVICE_DEFINITION_INDEX: definitions_v2_dev IDENTITY_API_URL: https://identity-api.dev.dimo.zone/query service: type: ClusterIP @@ -119,9 +122,4 @@ serviceMonitor: path: /metrics port: mon-http interval: 30s -jobs: - - name: search-index-load - schedule: 0 0 * * * - args: - - '-c' - - /device-definitions-api sync-device-definitions-search; CODE=$?; echo "weekly typesense mmy search index sync completed"; wget -q --post-data "hello=shutdown" http://localhost:4191/shutdown &> /dev/null; exit $CODE; +jobs: [] diff --git a/cmd/device-definitions-api/add_vin.go b/cmd/device-definitions-api/add_vin.go index d53c2b30..a9e54c48 100644 --- a/cmd/device-definitions-api/add_vin.go +++ b/cmd/device-definitions-api/add_vin.go @@ -14,8 +14,6 @@ import ( "github.com/DIMO-Network/device-definitions-api/internal/core/common" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/sender" - "github.com/ethereum/go-ethereum/ethclient" "github.com/DIMO-Network/device-definitions-api/internal/config" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/db/models" @@ -32,8 +30,6 @@ import ( type addVINCmd struct { logger zerolog.Logger settings config.Settings - - sender sender.Sender } func (*addVINCmd) Name() string { return "addvin" } @@ -61,16 +57,7 @@ func (p *addVINCmd) Execute(ctx context.Context, _ *flag.FlagSet, _ ...interface pdb := db.NewDbConnectionFromSettings(ctx, &p.settings.DB, true) pdb.WaitForDB(p.logger) - ethClient, err := ethclient.Dial(p.settings.EthereumRPCURL.String()) - if err != nil { - p.logger.Fatal().Err(err).Msg("Failed to create Ethereum client.") - } - - chainID, err := ethClient.ChainID(ctx) - if err != nil { - p.logger.Fatal().Err(err).Msg("Couldn't retrieve chain id.") - } - onChainSvc := gateways.NewDeviceDefinitionOnChainService(&p.settings, &p.logger, ethClient, chainID, p.sender, pdb.DBS) + catalogSvc := gateways.NewDeviceDefinitionCatalogService(&p.settings, &p.logger) vinDecodeNumber, err := models.FindVinNumber(ctx, pdb.DBS().Reader, vin) if err != nil && !errors.Is(err, sql.ErrNoRows) { @@ -117,18 +104,30 @@ func (p *addVINCmd) Execute(ctx context.Context, _ *flag.FlagSet, _ ...interface return subcommands.ExitFailure } - manufacturer, err := onChainSvc.GetManufacturer(stringutils.SlugString(wmi.ManufacturerName)) + manufacturer, err := catalogSvc.GetManufacturer(stringutils.SlugString(wmi.ManufacturerName)) if err != nil { fmt.Println(err.Error()) return subcommands.ExitFailure } - definitionID := common.DeviceDefinitionSlug(stringutils.SlugString(wmi.ManufacturerName), stringutils.SlugString(model), int16(vinNumber.Year)) - deviceDefinition, err := onChainSvc.GetDefinitionTableland(ctx, big.NewInt(int64(manufacturer.TokenID)), definitionID) + definitionID, err := common.DeviceDefinitionSlug(stringutils.SlugString(wmi.ManufacturerName), stringutils.SlugString(model), int16(vinNumber.Year)) + if err != nil { + // No template can exist at this id, so the lookup below would 404 and + // the row would point at a definition that can never be created. + fmt.Println(err.Error()) + return subcommands.ExitFailure + } + deviceDefinition, err := catalogSvc.GetDefinition(ctx, big.NewInt(int64(manufacturer.TokenID)), definitionID) if err != nil { fmt.Println(err.Error() + " " + model + " " + strconv.Itoa(vinNumber.Year)) return subcommands.ExitFailure } + if deviceDefinition == nil { + // (nil, nil) is returned both for a missing definition and for one + // owned by a different manufacturer; dereferencing panics. + fmt.Println("no device definition found for " + definitionID) + return subcommands.ExitFailure + } vinNumber.DefinitionID = deviceDefinition.ID err = vinNumber.Insert(ctx, pdb.DBS().Writer, boil.Infer()) diff --git a/cmd/device-definitions-api/add_vins_csv.go b/cmd/device-definitions-api/add_vins_csv.go index 6dce3edb..b9630dc0 100644 --- a/cmd/device-definitions-api/add_vins_csv.go +++ b/cmd/device-definitions-api/add_vins_csv.go @@ -13,7 +13,6 @@ import ( "github.com/DIMO-Network/device-definitions-api/internal/config" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/db/models" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/sender" "github.com/DIMO-Network/shared/pkg/db" "github.com/DIMO-Network/shared/pkg/logfields" vinutils "github.com/DIMO-Network/shared/pkg/vin" @@ -28,7 +27,6 @@ type addVINsCSVCmd struct { logger zerolog.Logger settings config.Settings - sender sender.Sender identity gateways.IdentityAPI } diff --git a/cmd/device-definitions-api/bulk_update_powertrain.go b/cmd/device-definitions-api/bulk_update_powertrain.go deleted file mode 100644 index 23d1a077..00000000 --- a/cmd/device-definitions-api/bulk_update_powertrain.go +++ /dev/null @@ -1,166 +0,0 @@ -package main - -import ( - "context" - "encoding/csv" - "encoding/json" - "flag" - "fmt" - "os" - "strings" - "time" - - "github.com/DIMO-Network/device-definitions-api/internal/contracts" - "github.com/DIMO-Network/device-definitions-api/internal/core/common" - "github.com/DIMO-Network/device-definitions-api/internal/core/models" - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/sender" - "github.com/ethereum/go-ethereum/ethclient" - - "github.com/DIMO-Network/device-definitions-api/internal/config" - "github.com/DIMO-Network/shared/pkg/db" - "github.com/google/subcommands" - "github.com/rs/zerolog" -) - -type bulkUpdatePowertrain struct { - logger zerolog.Logger - settings config.Settings - - sender sender.Sender -} - -func (*bulkUpdatePowertrain) Name() string { return "bulk-update-powertrain" } -func (*bulkUpdatePowertrain) Synopsis() string { - return "updates definitions from csv file with corresponding definitionId,powertrain pair per row" -} -func (*bulkUpdatePowertrain) Usage() string { - return `bulk-update-powertrain ` -} - -func (p *bulkUpdatePowertrain) SetFlags(_ *flag.FlagSet) { -} - -func (p *bulkUpdatePowertrain) Execute(ctx context.Context, _ *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { - filename := "" - for _, arg := range os.Args { - if strings.Contains(arg, ".csv") { - filename = arg - } - } - file, err := os.Open(filename) - if err != nil { - fmt.Printf("Error opening file: %v\n", err) - return subcommands.ExitFailure - } - defer file.Close() - - reader := csv.NewReader(file) - - records, err := reader.ReadAll() - if err != nil { - fmt.Printf("Error reading CSV: %v\n", err) - return subcommands.ExitFailure - } - - pdb := db.NewDbConnectionFromSettings(ctx, &p.settings.DB, true) - pdb.WaitForDB(p.logger) - - ethClient, err := ethclient.Dial(p.settings.EthereumRPCURL.String()) - if err != nil { - p.logger.Fatal().Err(err).Msg("Failed to create Ethereum client.") - } - - chainID, err := ethClient.ChainID(ctx) - if err != nil { - p.logger.Fatal().Err(err).Msg("Couldn't retrieve chain id.") - } - onChainSvc := gateways.NewDeviceDefinitionOnChainService(&p.settings, &p.logger, ethClient, chainID, p.sender, pdb.DBS) - - notFoundDefinitions := make([]string, 0) - - for i, record := range records { - if len(record) < 2 { - fmt.Printf("Skipping malformed line %d: %v\n", i+1, record) - continue - } - definitionID := strings.ToLower(record[0]) - powertrain := strings.ToUpper(record[1]) - if definitionID == "" || powertrain == "" { - fmt.Printf("Skipping malformed line %d: %v\n", i+1, record) - continue - } - if powertrain != models.HEV.String() && powertrain != models.PHEV.String() && powertrain != models.BEV.String() && powertrain != models.ICE.String() { - fmt.Printf("Invalid powertrain: %d: %s\n", i+1, powertrain) - continue - } - if len(strings.Split(definitionID, "_")) != 3 { - fmt.Printf("Invalid definitionID: %s\n", definitionID) - notFoundDefinitions = append(notFoundDefinitions, definitionID) - continue - } - fmt.Printf("DefinitionID: %s, Powertrain: %s\n", definitionID, powertrain) - - deviceDefinition, manufID, err := onChainSvc.GetDefinitionByID(ctx, definitionID) - if err != nil { - fmt.Printf("%s: Error getting device definition: %v\n", definitionID, err) - notFoundDefinitions = append(notFoundDefinitions, definitionID) - continue - } - if deviceDefinition == nil { - fmt.Printf("%s: Device definition not found\n", definitionID) - notFoundDefinitions = append(notFoundDefinitions, definitionID) - continue - } - - manufName, err := onChainSvc.GetManufacturerNameByID(ctx, manufID) - if err != nil { - fmt.Printf("%s: Error getting manufacturer name: %v\n", manufID, err) - continue - } - set := false - if deviceDefinition.Metadata != nil { - deviceDefinition.Metadata = &models.DeviceDefinitionMetadata{ - DeviceAttributes: make([]models.DeviceTypeAttribute, 0), - } - } - for i2, attribute := range deviceDefinition.Metadata.DeviceAttributes { - if attribute.Name == common.PowerTrainType { - deviceDefinition.Metadata.DeviceAttributes[i2].Value = powertrain - set = true - break - } - } - - if !set { - deviceDefinition.Metadata.DeviceAttributes = append(deviceDefinition.Metadata.DeviceAttributes, models.DeviceTypeAttribute{ - Name: common.PowerTrainType, - Value: powertrain, - }) - } - md, _ := json.Marshal(deviceDefinition.Metadata) - updateContract := contracts.DeviceDefinitionUpdateInput{ - Id: deviceDefinition.ID, - Metadata: string(md), - Ksuid: deviceDefinition.KSUID, - DeviceType: deviceDefinition.DeviceType, - ImageURI: deviceDefinition.ImageURI, - } - - update, err := onChainSvc.Update(ctx, manufName, updateContract) - if err != nil { - fmt.Printf("%s: Error updating device definition: %v\n", definitionID, err) - return subcommands.ExitFailure - } - fmt.Printf("%s: Updated device definition trx id: %s\nWaiting 10 seconds before next update\n", definitionID, *update) - - time.Sleep(10 * time.Second) - } - - fmt.Printf("Not found definitions: %d\n", len(notFoundDefinitions)) - for _, definitionID := range notFoundDefinitions { - fmt.Printf("%s\n", definitionID) - } - - return subcommands.ExitSuccess -} diff --git a/cmd/device-definitions-api/decode_vin.go b/cmd/device-definitions-api/decode_vin.go index dd4057ba..11713184 100644 --- a/cmd/device-definitions-api/decode_vin.go +++ b/cmd/device-definitions-api/decode_vin.go @@ -16,7 +16,6 @@ import ( vinutil "github.com/DIMO-Network/shared/pkg/vin" "github.com/aarondl/null/v8" "github.com/aarondl/sqlboiler/v4/boil" - "github.com/ethereum/go-ethereum/ethclient" "github.com/goccy/go-json" @@ -181,7 +180,16 @@ func (p *decodeVINCmd) Execute(ctx context.Context, f *flag.FlagSet, _ ...interf dbVin.ManufacturerName = vinInfo.Make } dbVin.DatgroupData = null.JSONFrom(vinInfo.Raw) - dbVin.DefinitionID = common.DeviceDefinitionSlug(vinInfo.Make, vinInfo.Model, int16(vinInfo.Year)) + definitionID, errID := common.DeviceDefinitionSlug(vinInfo.Make, vinInfo.Model, int16(vinInfo.Year)) + if errID != nil { + // Inserting the row anyway is what the validator's contract + // forbids: every later DecodeVIN of this VIN would read the + // cached row, look its definition up in the catalog, 404 + // forever, and answer with an empty trim and match quality. + fmt.Println("skipping, no definition id can be built: " + errID.Error()) + continue + } + dbVin.DefinitionID = definitionID dbVin.DecodeProvider = null.StringFrom(string(vinInfo.Source)) // todo future change to add field with StyleName @@ -254,7 +262,7 @@ func readVINFile(filename string) ([]string, error) { return values, nil } -func instantiateVINDecodingSvc(ctx context.Context, settings *config.Settings, logger *zerolog.Logger, pdb db.Store) services.VINDecodingService { +func instantiateVINDecodingSvc(_ context.Context, settings *config.Settings, logger *zerolog.Logger, pdb db.Store) services.VINDecodingService { datAPI := gateways.NewDATGroupAPIService(settings, logger) drivlyAPI := gateways.NewDrivlyAPIService(settings) vincarioAPI := gateways.NewVincarioAPIService(settings, logger) @@ -265,21 +273,7 @@ func instantiateVINDecodingSvc(ctx context.Context, settings *config.Settings, l return services.NewVINDecodingService(drivlyAPI, vincarioAPI, nil, logger, nil, datAPI, pdb.DBS, jp17vinAPI, carvxAPI, elevaAPI) } - send, err := createSender(ctx, settings, logger) - if err != nil { - logger.Fatal().Err(err).Msg("Failed to create sender.") - } - - ethClient, err := ethclient.Dial(settings.EthereumRPCURL.String()) - if err != nil { - logger.Fatal().Err(err).Msg("Failed to create Ethereum client.") - } - - chainID, err := ethClient.ChainID(ctx) - if err != nil { - logger.Fatal().Err(err).Msg("Couldn't retrieve chain id.") - } - deviceDefinitionOnChainService := gateways.NewDeviceDefinitionOnChainService(settings, logger, ethClient, chainID, send, pdb.DBS) + deviceDefinitionCatalogService := gateways.NewDeviceDefinitionCatalogService(settings, logger) - return services.NewVINDecodingService(drivlyAPI, vincarioAPI, nil, logger, deviceDefinitionOnChainService, datAPI, pdb.DBS, jp17vinAPI, carvxAPI, elevaAPI) + return services.NewVINDecodingService(drivlyAPI, vincarioAPI, nil, logger, deviceDefinitionCatalogService, datAPI, pdb.DBS, jp17vinAPI, carvxAPI, elevaAPI) } diff --git a/cmd/device-definitions-api/delete_dd.go b/cmd/device-definitions-api/delete_dd.go index a9871a35..95cb982b 100644 --- a/cmd/device-definitions-api/delete_dd.go +++ b/cmd/device-definitions-api/delete_dd.go @@ -7,13 +7,10 @@ import ( "fmt" "os" "strings" - "time" "github.com/DIMO-Network/device-definitions-api/internal/config" - dd_common "github.com/DIMO-Network/device-definitions-api/internal/core/common" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" "github.com/DIMO-Network/shared/pkg/db" - "github.com/ethereum/go-ethereum/ethclient" "github.com/google/subcommands" "github.com/rs/zerolog" ) @@ -52,50 +49,17 @@ func (p *deleteDefinition) Execute(ctx context.Context, _ *flag.FlagSet, _ ...in pdb := db.NewDbConnectionFromSettings(ctx, &p.settings.DB, true) pdb.WaitForDB(p.logger) - send, err := createSender(ctx, &p.settings, &p.logger) - if err != nil { - p.logger.Fatal().Err(err).Msg("Failed to create sender.") - } - ethClient, err := ethclient.Dial(p.settings.EthereumRPCURL.String()) - if err != nil { - p.logger.Fatal().Err(err).Msg("Failed to create Ethereum client.") - } - - chainID, err := ethClient.ChainID(ctx) - if err != nil { - p.logger.Fatal().Err(err).Msg("Couldn't retrieve chain id.") - } - deviceDefinitionOnChainService := gateways.NewDeviceDefinitionOnChainService(&p.settings, &p.logger, ethClient, chainID, send, pdb.DBS) + deviceDefinitionCatalogService := gateways.NewDeviceDefinitionCatalogService(&p.settings, &p.logger) id := os.Args[len(os.Args)-1] - trx, err := deviceDefinitionOnChainService.Delete(ctx, manufacturer, id) + deleted, err := deviceDefinitionCatalogService.Delete(ctx, manufacturer, id) if err != nil { p.logger.Fatal().Err(err).Msg("Failed to delete.") } - - if len(*trx) > 0 { - trxFinished := false - loops := 0 - for !trxFinished { - loops++ - time.Sleep(time.Second * 2) - trxFinished, err = dd_common.CheckTransactionStatus(*trx, p.settings.PolygonScanAPIKey, !p.settings.IsProd()) - if err != nil { - fmt.Println("Error checking transaction status: ", err) - } - fmt.Println("Transaction status: ", trxFinished) - if loops > 10 { - // get device definition from on chain to see if maybe got created but trx still showing false - onchainDD, _, err := deviceDefinitionOnChainService.GetDefinitionByID(ctx, id) - fmt.Println("onchainDD: ", onchainDD, err) - if onchainDD != nil { - break - } - } - } - } + // The worker delete is synchronous; nothing to poll. + fmt.Println("Deleted device definition: ", *deleted) return subcommands.ExitSuccess } diff --git a/cmd/device-definitions-api/main.go b/cmd/device-definitions-api/main.go index 4ccfbaec..be72cd7c 100644 --- a/cmd/device-definitions-api/main.go +++ b/cmd/device-definitions-api/main.go @@ -7,9 +7,6 @@ import ( "os" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/sender" - awsconfig "github.com/aws/aws-sdk-go-v2/config" - "github.com/aws/aws-sdk-go-v2/service/kms" "github.com/google/subcommands" @@ -43,7 +40,6 @@ func main() { Str("app", settings.ServiceName). Str("git-sha1", gitSha1). Logger() - sigSender, err := createSender(ctx, &settings, &logger) identity := gateways.NewIdentityAPIService(&logger, &settings) subcommands.Register(subcommands.HelpCommand(), "") @@ -51,45 +47,16 @@ func main() { subcommands.Register(subcommands.CommandsCommand(), "") subcommands.Register(&migrateDBCmd{logger: logger, settings: settings}, "") subcommands.Register(&addVINCmd{logger: logger, settings: settings}, "") - subcommands.Register(&addVINsCSVCmd{logger: logger, settings: settings, sender: sigSender, identity: identity}, "") + subcommands.Register(&addVINsCSVCmd{logger: logger, settings: settings, identity: identity}, "") subcommands.Register(&decodeVINCmd{logger: &logger, settings: &settings}, "") - subcommands.Register(&syncDeviceDefinitionSearchCmd{logger: logger, settings: settings, sender: sigSender}, "") subcommands.Register(&deleteDefinition{logger: logger, settings: settings}, "") - subcommands.Register(&bulkUpdatePowertrain{logger: logger, settings: settings, sender: sigSender}, "") if len(os.Args) == 1 { // Run API & everythying else - if err != nil { - logger.Fatal().Err(err).Msg("Failed to create sender.") - } - api.Run(ctx, logger, &settings, sigSender) + api.Run(ctx, logger, &settings) } else { flag.Parse() os.Exit(int(subcommands.Execute(ctx))) } } - -func createSender(ctx context.Context, settings *config.Settings, logger *zerolog.Logger) (sender.Sender, error) { - if settings.PrivateKeyMode { - logger.Warn().Msg("Using injected private key. Never do this in production.") - send, err := sender.FromKey(settings.SenderPrivateKey) - if err != nil { - return nil, err - } - logger.Info().Str("address", send.Address().Hex()).Msg("Loaded private key account.") - return send, nil - } - - awsconf, err := awsconfig.LoadDefaultConfig(ctx) - if err != nil { - return nil, err - } - kmsc := kms.NewFromConfig(awsconf) - send, err := sender.FromKMS(ctx, kmsc, settings.KMSKeyID) - if err != nil { - return nil, err - } - logger.Info().Msgf("Loaded KMS key %s, address %s.", settings.KMSKeyID, send.Address().Hex()) - return send, nil -} diff --git a/cmd/device-definitions-api/search_indexer.go b/cmd/device-definitions-api/search_indexer.go deleted file mode 100644 index 8ac1b3e3..00000000 --- a/cmd/device-definitions-api/search_indexer.go +++ /dev/null @@ -1,53 +0,0 @@ -package main - -import ( - "context" - "fmt" - - "github.com/pkg/errors" - "github.com/typesense/typesense-go/typesense" - "github.com/typesense/typesense-go/typesense/api" -) - -//go:generate mockgen -source search_indexer.go -destination search_indexer_mock_test.go -package main -type SearchIndexer interface { - RecreateIndex(ctx context.Context, schema *api.CollectionSchema) error - UpsertDocuments(ctx context.Context, collectionName string, docs []SearchEntryItem) error -} - -type typesenseSearchIndexer struct { - client *typesense.Client -} - -func NewTypesenseSearchIndexer(client *typesense.Client) SearchIndexer { - return &typesenseSearchIndexer{client: client} -} - -func (t *typesenseSearchIndexer) RecreateIndex(ctx context.Context, schema *api.CollectionSchema) error { - if _, err := t.client.Collection(schema.Name).Delete(ctx); err != nil { - // Deletion failure is non-fatal (index may not exist yet) — caller logs. - fmt.Printf("RecreateIndex: delete returned %v (continuing)\n", err) - } - if _, err := t.client.Collections().Create(ctx, schema); err != nil { - return errors.Wrap(err, "failed to create collection") - } - return nil -} - -func (t *typesenseSearchIndexer) UpsertDocuments(ctx context.Context, collectionName string, docs []SearchEntryItem) error { - if len(docs) == 0 { - return nil - } - payload := make([]interface{}, 0, len(docs)) - for _, d := range docs { - payload = append(payload, d) - } - action := "upsert" - _, err := t.client.Collection(collectionName).Documents().Import(ctx, payload, &api.ImportDocumentsParams{ - Action: &action, - }) - if err != nil { - return errors.Wrap(err, "failed to import documents") - } - return nil -} diff --git a/cmd/device-definitions-api/search_indexer_mock_test.go b/cmd/device-definitions-api/search_indexer_mock_test.go deleted file mode 100644 index 26d30244..00000000 --- a/cmd/device-definitions-api/search_indexer_mock_test.go +++ /dev/null @@ -1,70 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: search_indexer.go -// -// Generated by this command: -// -// mockgen -source search_indexer.go -destination search_indexer_mock_test.go -package main -// - -// Package main is a generated GoMock package. -package main - -import ( - context "context" - reflect "reflect" - - api "github.com/typesense/typesense-go/typesense/api" - gomock "go.uber.org/mock/gomock" -) - -// MockSearchIndexer is a mock of SearchIndexer interface. -type MockSearchIndexer struct { - ctrl *gomock.Controller - recorder *MockSearchIndexerMockRecorder - isgomock struct{} -} - -// MockSearchIndexerMockRecorder is the mock recorder for MockSearchIndexer. -type MockSearchIndexerMockRecorder struct { - mock *MockSearchIndexer -} - -// NewMockSearchIndexer creates a new mock instance. -func NewMockSearchIndexer(ctrl *gomock.Controller) *MockSearchIndexer { - mock := &MockSearchIndexer{ctrl: ctrl} - mock.recorder = &MockSearchIndexerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockSearchIndexer) EXPECT() *MockSearchIndexerMockRecorder { - return m.recorder -} - -// RecreateIndex mocks base method. -func (m *MockSearchIndexer) RecreateIndex(ctx context.Context, schema *api.CollectionSchema) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RecreateIndex", ctx, schema) - ret0, _ := ret[0].(error) - return ret0 -} - -// RecreateIndex indicates an expected call of RecreateIndex. -func (mr *MockSearchIndexerMockRecorder) RecreateIndex(ctx, schema any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecreateIndex", reflect.TypeOf((*MockSearchIndexer)(nil).RecreateIndex), ctx, schema) -} - -// UpsertDocuments mocks base method. -func (m *MockSearchIndexer) UpsertDocuments(ctx context.Context, collectionName string, docs []SearchEntryItem) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpsertDocuments", ctx, collectionName, docs) - ret0, _ := ret[0].(error) - return ret0 -} - -// UpsertDocuments indicates an expected call of UpsertDocuments. -func (mr *MockSearchIndexerMockRecorder) UpsertDocuments(ctx, collectionName, docs any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertDocuments", reflect.TypeOf((*MockSearchIndexer)(nil).UpsertDocuments), ctx, collectionName, docs) -} diff --git a/cmd/device-definitions-api/sync_device_definition_search.go b/cmd/device-definitions-api/sync_device_definition_search.go deleted file mode 100644 index 24a4284d..00000000 --- a/cmd/device-definitions-api/sync_device_definition_search.go +++ /dev/null @@ -1,204 +0,0 @@ -package main - -import ( - "context" - "flag" - "fmt" - - coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/sender" - stringutils "github.com/DIMO-Network/shared/pkg/strings" - - "github.com/ethereum/go-ethereum/ethclient" - - "github.com/DIMO-Network/device-definitions-api/internal/config" - "github.com/DIMO-Network/device-definitions-api/internal/core/common" - "github.com/DIMO-Network/shared/pkg/db" - "github.com/google/subcommands" - "github.com/rs/zerolog" - "github.com/typesense/typesense-go/typesense" - "github.com/typesense/typesense-go/typesense/api" - "github.com/typesense/typesense-go/typesense/api/pointer" -) - -const ( - minSearchYear = 2007 - tablelandPageSize = 500 - searchDefaultScore = 1 -) - -type syncDeviceDefinitionSearchCmd struct { - logger zerolog.Logger - settings config.Settings - - createIndex bool - sender sender.Sender -} - -func (*syncDeviceDefinitionSearchCmd) Name() string { return "sync-device-definitions-search" } -func (*syncDeviceDefinitionSearchCmd) Synopsis() string { - return "sync device definitions search index" -} -func (*syncDeviceDefinitionSearchCmd) Usage() string { - return `sync-device-definitions-search` -} - -func (p *syncDeviceDefinitionSearchCmd) SetFlags(f *flag.FlagSet) { - f.BoolVar(&p.createIndex, "create-index", false, "create or recreate index") -} - -func (p *syncDeviceDefinitionSearchCmd) Execute(ctx context.Context, _ *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { - pdb := db.NewDbConnectionFromSettings(ctx, &p.settings.DB, true) - pdb.WaitForDB(p.logger) - - ethClient, err := ethclient.Dial(p.settings.EthereumRPCURL.String()) - if err != nil { - p.logger.Fatal().Err(err).Msg("Failed to create Ethereum client.") - } - chainID, err := ethClient.ChainID(ctx) - if err != nil { - p.logger.Fatal().Err(err).Msg("Couldn't retrieve chain id.") - } - - onChainSvc := gateways.NewDeviceDefinitionOnChainService(&p.settings, &p.logger, ethClient, chainID, p.sender, pdb.DBS) - identity := gateways.NewIdentityAPIService(&p.logger, &p.settings) - - client := typesense.NewClient( - typesense.WithServer(p.settings.SearchServiceAPIURL.String()), - typesense.WithAPIKey(p.settings.SearchServiceAPIKey)) - indexer := NewTypesenseSearchIndexer(client) - - collectionName := p.settings.SearchServiceIndexName - - if p.createIndex { - if err := indexer.RecreateIndex(ctx, deviceDefinitionSearchSchema(collectionName)); err != nil { - p.logger.Error().Err(err).Send() - return subcommands.ExitFailure - } - fmt.Printf("Index %s created\n", collectionName) - } - - if err := runSearchSync(ctx, identity, onChainSvc, indexer, collectionName); err != nil { - p.logger.Error().Err(err).Msg("sync failed") - return subcommands.ExitFailure - } - fmt.Print("Index Updated") - return subcommands.ExitSuccess -} - -// runSearchSync fetches every manufacturer, builds its definition documents, and -// upserts them to the search index one manufacturer at a time. This caps the -// steady-state memory footprint to a single manufacturer's definitions rather -// than the full catalog. -func runSearchSync( - ctx context.Context, - identity gateways.IdentityAPI, - onChainSvc gateways.DeviceDefinitionOnChainService, - indexer SearchIndexer, - collectionName string, -) error { - makes, err := identity.GetManufacturers() - if err != nil { - return fmt.Errorf("get manufacturers: %w", err) - } - fmt.Printf("Found %d manufacturers\n", len(makes)) - - for _, dm := range makes { - docs, err := buildManufacturerDocuments(ctx, onChainSvc, dm) - if err != nil { - return fmt.Errorf("build documents for %s: %w", dm.Name, err) - } - if len(docs) == 0 { - fmt.Printf("%s: no definitions to sync\n", dm.Name) - continue - } - if err := indexer.UpsertDocuments(ctx, collectionName, docs); err != nil { - return fmt.Errorf("upsert %s: %w", dm.Name, err) - } - fmt.Printf("%s: upserted %d definitions\n", dm.Name, len(docs)) - } - return nil -} - -// buildManufacturerDocuments pulls every tableland definition for a manufacturer -// and converts the ones from model year >= minSearchYear into SearchEntryItems. -func buildManufacturerDocuments( - ctx context.Context, - onChainSvc gateways.DeviceDefinitionOnChainService, - dm coremodels.Manufacturer, -) ([]SearchEntryItem, error) { - makeSlug := stringutils.SlugString(dm.Name) - var docs []SearchEntryItem - - pageIndex := 0 - for { - page, err := onChainSvc.QueryDefinitionsCustom(ctx, dm.TokenID, "", pageIndex) - if err != nil { - return nil, err - } - for _, dd := range page { - if dd.Year < minSearchYear { - continue - } - docs = append(docs, SearchEntryItem{ - ID: dd.ID, - DeviceDefinitionID: dd.ID, - DefinitionID: dd.ID, - Name: common.BuildDeviceDefinitionName(int16(dd.Year), dm.Name, dd.Model), - Make: dm.Name, - MakeSlug: makeSlug, - ManufacturerTokenID: dm.TokenID, - Model: dd.Model, - ModelSlug: stringutils.SlugString(dd.Model), - Year: dd.Year, - ImageURL: dd.ImageURI, - Score: searchDefaultScore, - }) - } - if len(page) < tablelandPageSize { - break - } - pageIndex++ - } - return docs, nil -} - -func deviceDefinitionSearchSchema(collectionName string) *api.CollectionSchema { - hasFacet := true - nestedFields := false - sort := true - return &api.CollectionSchema{ - Name: collectionName, - EnableNestedFields: &nestedFields, - DefaultSortingField: pointer.String("score"), - Fields: []api.Field{ - {Name: "device_definition_id", Type: "string"}, - {Name: "name", Type: "string", Sort: &sort}, - {Name: "make", Type: "string", Facet: &hasFacet}, - {Name: "make_slug", Type: "string", Facet: &hasFacet}, - {Name: "make_token_id", Type: "int32", Facet: &hasFacet}, - {Name: "model", Type: "string", Facet: &hasFacet}, - {Name: "model_slug", Type: "string", Facet: &hasFacet}, - {Name: "year", Type: "int32", Facet: &hasFacet}, - {Name: "image_url", Type: "string"}, - {Name: "score", Type: "int32"}, - {Name: "definition_id", Type: "string"}, - }, - } -} - -type SearchEntryItem struct { - ID string `json:"id"` - DeviceDefinitionID string `json:"device_definition_id"` //nolint - Name string `json:"name"` - Make string `json:"make"` - MakeSlug string `json:"make_slug"` //nolint - ManufacturerTokenID int `json:"make_token_id"` //nolint - Model string `json:"model"` - ModelSlug string `json:"model_slug"` //nolint - Year int `json:"year"` - ImageURL string `json:"image_url"` //nolint - Score int `json:"score"` - DefinitionID string `json:"definition_id"` //nolint -} diff --git a/cmd/device-definitions-api/sync_device_definition_search_test.go b/cmd/device-definitions-api/sync_device_definition_search_test.go deleted file mode 100644 index 1f6dd0eb..00000000 --- a/cmd/device-definitions-api/sync_device_definition_search_test.go +++ /dev/null @@ -1,214 +0,0 @@ -package main - -import ( - "context" - "errors" - "testing" - - coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" - mock_gateways "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways/mocks" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" -) - -func defToyota(year int, model, id string) coremodels.DeviceDefinitionTablelandModel { - return coremodels.DeviceDefinitionTablelandModel{ - ID: id, - Model: model, - Year: year, - ImageURI: "https://img/" + id, - } -} - -func TestBuildManufacturerDocuments_FiltersPre2007(t *testing.T) { - ctrl := gomock.NewController(t) - onChain := mock_gateways.NewMockDeviceDefinitionOnChainService(ctrl) - dm := coremodels.Manufacturer{TokenID: 42, Name: "Toyota"} - - onChain.EXPECT(). - QueryDefinitionsCustom(gomock.Any(), 42, "", 0). - Return([]coremodels.DeviceDefinitionTablelandModel{ - defToyota(2006, "Camry", "id-old"), - defToyota(2007, "Camry", "id-keep"), - defToyota(2020, "Prius", "id-new"), - }, nil) - - docs, err := buildManufacturerDocuments(context.Background(), onChain, dm) - require.NoError(t, err) - require.Len(t, docs, 2) - assert.Equal(t, "id-keep", docs[0].ID) - assert.Equal(t, "id-new", docs[1].ID) -} - -func TestBuildManufacturerDocuments_PopulatesFields(t *testing.T) { - ctrl := gomock.NewController(t) - onChain := mock_gateways.NewMockDeviceDefinitionOnChainService(ctrl) - dm := coremodels.Manufacturer{TokenID: 7, Name: "Land Rover"} - - onChain.EXPECT(). - QueryDefinitionsCustom(gomock.Any(), 7, "", 0). - Return([]coremodels.DeviceDefinitionTablelandModel{ - {ID: "ddid-1", Model: "Range Rover", Year: 2021, ImageURI: "https://img/rr"}, - }, nil) - - docs, err := buildManufacturerDocuments(context.Background(), onChain, dm) - require.NoError(t, err) - require.Len(t, docs, 1) - - d := docs[0] - assert.Equal(t, "ddid-1", d.ID) - assert.Equal(t, "ddid-1", d.DeviceDefinitionID) - assert.Equal(t, "ddid-1", d.DefinitionID) - assert.Equal(t, "Land Rover", d.Make) - assert.Equal(t, "land-rover", d.MakeSlug) - assert.Equal(t, 7, d.ManufacturerTokenID) - assert.Equal(t, "Range Rover", d.Model) - assert.Equal(t, "range-rover", d.ModelSlug) - assert.Equal(t, 2021, d.Year) - assert.Equal(t, "2021 Land Rover Range Rover", d.Name) - assert.Equal(t, "https://img/rr", d.ImageURL) - assert.Equal(t, searchDefaultScore, d.Score) -} - -func TestBuildManufacturerDocuments_TerminatesOnShortPage(t *testing.T) { - ctrl := gomock.NewController(t) - onChain := mock_gateways.NewMockDeviceDefinitionOnChainService(ctrl) - dm := coremodels.Manufacturer{TokenID: 1, Name: "Honda"} - - // 10 rows on page 0 is < 500 → loop should break without requesting page 1. - page := make([]coremodels.DeviceDefinitionTablelandModel, 10) - for i := range page { - page[i] = defToyota(2020, "Civic", "id") - } - onChain.EXPECT(). - QueryDefinitionsCustom(gomock.Any(), 1, "", 0). - Return(page, nil). - Times(1) - - docs, err := buildManufacturerDocuments(context.Background(), onChain, dm) - require.NoError(t, err) - assert.Len(t, docs, 10) -} - -func TestBuildManufacturerDocuments_PagesUntilShortPage(t *testing.T) { - ctrl := gomock.NewController(t) - onChain := mock_gateways.NewMockDeviceDefinitionOnChainService(ctrl) - dm := coremodels.Manufacturer{TokenID: 1, Name: "Honda"} - - full := make([]coremodels.DeviceDefinitionTablelandModel, tablelandPageSize) - for i := range full { - full[i] = defToyota(2020, "Civic", "id") - } - short := []coremodels.DeviceDefinitionTablelandModel{defToyota(2020, "Accord", "id-last")} - - gomock.InOrder( - onChain.EXPECT().QueryDefinitionsCustom(gomock.Any(), 1, "", 0).Return(full, nil), - onChain.EXPECT().QueryDefinitionsCustom(gomock.Any(), 1, "", 1).Return(full, nil), - onChain.EXPECT().QueryDefinitionsCustom(gomock.Any(), 1, "", 2).Return(short, nil), - ) - - docs, err := buildManufacturerDocuments(context.Background(), onChain, dm) - require.NoError(t, err) - assert.Len(t, docs, 2*tablelandPageSize+1) -} - -func TestBuildManufacturerDocuments_PropagatesError(t *testing.T) { - ctrl := gomock.NewController(t) - onChain := mock_gateways.NewMockDeviceDefinitionOnChainService(ctrl) - dm := coremodels.Manufacturer{TokenID: 1, Name: "Honda"} - - boom := errors.New("tableland down") - onChain.EXPECT(). - QueryDefinitionsCustom(gomock.Any(), 1, "", 0). - Return(nil, boom) - - _, err := buildManufacturerDocuments(context.Background(), onChain, dm) - require.ErrorIs(t, err, boom) -} - -func TestRunSearchSync_FlushesPerManufacturer(t *testing.T) { - ctrl := gomock.NewController(t) - identity := mock_gateways.NewMockIdentityAPI(ctrl) - onChain := mock_gateways.NewMockDeviceDefinitionOnChainService(ctrl) - indexer := NewMockSearchIndexer(ctrl) - - identity.EXPECT().GetManufacturers().Return([]coremodels.Manufacturer{ - {TokenID: 1, Name: "Honda"}, - {TokenID: 2, Name: "Toyota"}, - }, nil) - - onChain.EXPECT().QueryDefinitionsCustom(gomock.Any(), 1, "", 0). - Return([]coremodels.DeviceDefinitionTablelandModel{defToyota(2020, "Civic", "h1")}, nil) - onChain.EXPECT().QueryDefinitionsCustom(gomock.Any(), 2, "", 0). - Return([]coremodels.DeviceDefinitionTablelandModel{defToyota(2020, "Camry", "t1")}, nil) - - // One upsert per manufacturer, each with exactly that make's docs. - indexer.EXPECT().UpsertDocuments(gomock.Any(), "dd-search", gomock.Any()). - DoAndReturn(func(_ context.Context, _ string, docs []SearchEntryItem) error { - require.Len(t, docs, 1) - assert.Equal(t, "Honda", docs[0].Make) - return nil - }) - indexer.EXPECT().UpsertDocuments(gomock.Any(), "dd-search", gomock.Any()). - DoAndReturn(func(_ context.Context, _ string, docs []SearchEntryItem) error { - require.Len(t, docs, 1) - assert.Equal(t, "Toyota", docs[0].Make) - return nil - }) - - err := runSearchSync(context.Background(), identity, onChain, indexer, "dd-search") - require.NoError(t, err) -} - -func TestRunSearchSync_SkipsMakeWithNoEligibleDefs(t *testing.T) { - ctrl := gomock.NewController(t) - identity := mock_gateways.NewMockIdentityAPI(ctrl) - onChain := mock_gateways.NewMockDeviceDefinitionOnChainService(ctrl) - indexer := NewMockSearchIndexer(ctrl) - - identity.EXPECT().GetManufacturers().Return([]coremodels.Manufacturer{ - {TokenID: 9, Name: "Studebaker"}, - }, nil) - - // All pre-2007 → filtered out → builder returns zero docs. - onChain.EXPECT().QueryDefinitionsCustom(gomock.Any(), 9, "", 0). - Return([]coremodels.DeviceDefinitionTablelandModel{defToyota(1950, "Champion", "s1")}, nil) - - // No UpsertDocuments expectation → gomock will fail the test if it's called. - - err := runSearchSync(context.Background(), identity, onChain, indexer, "dd-search") - require.NoError(t, err) -} - -func TestRunSearchSync_PropagatesManufacturersError(t *testing.T) { - ctrl := gomock.NewController(t) - identity := mock_gateways.NewMockIdentityAPI(ctrl) - onChain := mock_gateways.NewMockDeviceDefinitionOnChainService(ctrl) - indexer := NewMockSearchIndexer(ctrl) - - boom := errors.New("identity down") - identity.EXPECT().GetManufacturers().Return(nil, boom) - - err := runSearchSync(context.Background(), identity, onChain, indexer, "dd-search") - require.ErrorIs(t, err, boom) -} - -func TestRunSearchSync_PropagatesUpsertError(t *testing.T) { - ctrl := gomock.NewController(t) - identity := mock_gateways.NewMockIdentityAPI(ctrl) - onChain := mock_gateways.NewMockDeviceDefinitionOnChainService(ctrl) - indexer := NewMockSearchIndexer(ctrl) - - identity.EXPECT().GetManufacturers().Return([]coremodels.Manufacturer{ - {TokenID: 1, Name: "Honda"}, - }, nil) - onChain.EXPECT().QueryDefinitionsCustom(gomock.Any(), 1, "", 0). - Return([]coremodels.DeviceDefinitionTablelandModel{defToyota(2020, "Civic", "h1")}, nil) - - boom := errors.New("typesense down") - indexer.EXPECT().UpsertDocuments(gomock.Any(), "dd-search", gomock.Any()).Return(boom) - - err := runSearchSync(context.Background(), identity, onChain, indexer, "dd-search") - require.ErrorIs(t, err, boom) -} diff --git a/docs/superpowers/2026-08-28-dd-api-followups.md b/docs/superpowers/2026-08-28-dd-api-followups.md new file mode 100644 index 00000000..cb3d4511 --- /dev/null +++ b/docs/superpowers/2026-08-28-dd-api-followups.md @@ -0,0 +1,168 @@ +# dd-api follow-ups after `resolved-decode` + +What the `resolved-decode` branch does **not** fix, and what gates its deploy. +Written at the final whole-branch review of `28152d9..HEAD` (branch +`resolved-decode`, stacked on `r2-device-definitions` / PR #314). + +Plan: `docs/superpowers/plans/2026-08-28-resolved-decode.md` +Ledger: `.superpowers/sdd/2026-08-28-resolved-decode/progress.md` +Contract: `../definitions-worker/schema/{template,resolved}.schema.json` + +--- + +## 1. Deploy blocker: CLEARED on branch `shrink-dd-api` + +**Status: fixed.** This section described the blocker; it is resolved by the +`shrink-dd-api` branch stacked on `resolved-decode`. Recorded here rather than +deleted, because the failure mode is worth keeping. + +**What it was.** The worker's route table is `/t/:id`, `/schema/:doc`, +`POST /admin/{import,build,build/publish}`, `GET /admin/history`, and a 404 for +everything else. There is no `/definitions/:id` and no `/manifest.json`, and +dd-api called both. `Create()` read `GET /definitions/`, got the catch-all +404, and `fetchDocFrom` translated that to `(nil, nil)` -- "does not exist" -- +so the existence guard always passed; it then `PUT` to a route that does not +exist. Loud, not corrupting, but every catalog miss on the decode path and +every search sync would have failed. + +**What changed.** + +| Was | Now | +|---|---| +| `Create()` → `PUT /definitions/` | `PUT /t/`, a template with one `Base` trim | +| `Delete()` → `DELETE /definitions/` | `DELETE /t/` | +| existence check → `fetchDocFresh` | `GetTemplateByIDFresh`, on the `ErrTemplateNotFound` sentinel | +| `GetDeviceDefinitionByID` → `/definitions/.json` | template read, flattened to shared attributes only | +| `manifest()`, `CatalogIDs`, `PinCatalogSnapshot` | deleted with the search sync | +| `GetDeviceDefinitions` + its two handlers | deleted; both handlers were registered and dispatched by nothing | + +dd-api now requests only `/t/…` and `/schema/…`. + +**Two decisions inside it.** + +- Created templates carry attributes folded onto the DeviceType vocabulary by + `internal/core/vocabulary`, a port of the extraction's `vocabulary.mjs`. The + two write into the same contract, so they are held to parity by a test + against the JavaScript's own output on the real vocabulary. A vocabulary that + cannot be fetched aborts the create rather than writing fewer attributes. +- The legacy flat shape carries only attributes **shared by every trim**. + Filling its single slot per attribute from an arbitrary trim is what produced + the blended record in the first place. + +**Cutover ordering this imposes.** The worker must have built and published an +index before dd-api ships without its sync, and the Typesense collection +currently squatting the alias name has to be dropped so the alias can take it. + +## 2. Not fixed, recorded + +### 2.1 `bulk_validate_vin.go` has a guaranteed panic — pre-existing, in dead code + +`internal/core/commands/bulk_validate_vin.go:68` does an unchecked +`devideDefinition.(*coremodels.GetDeviceDefinitionQueryResult)` on the result +of `GetDeviceDefinitionByIDQueryHandler.Handle`, which returns +`*coremodels.Template`. It returned `*DeviceDefinitionTablelandModel` before +this branch, so the assertion was **already wrong on `28152d9`** — this branch +changes which wrong type it panics on, not whether it panics. Line 79 then +indexes `.DeviceStyles[0]` on a slice that could be empty. + +`BulkValidateVinCommand` is registered in `api.go:96` but **nothing dispatches +it** — no HTTP route, no gRPC method, no other caller. It is unreachable, and +fiber's `recover.New()` would turn the panic into a 500 if it ever became +reachable. Delete the command, or fix and wire it — do not leave it as a +tripwire for whoever adds the route. + +### 2.2 `GetDeviceStyleByID` lost every trim-varying attribute + +`get_ds_by_id.go:76` builds `DeviceAttributes` from `dd.Attributes` — the +**template-level** attributes only. For a multi-trim template those are exactly +the attributes every trim agrees on, so `fuel_tank_capacity_gal`, `mpg_city` +and the rest are now absent from this response where the flat definition used +to carry them (blended and often wrong, but present). + +The handler has the style's `Name` and could narrow via a `styleName` selector +— but the extraction emits `manufacturerCode` selectors only today (see 2.3), +and the style row carries no manufacturer code, so it could only ever resolve +`model-only`. **Blocked on the worker emitting `styleName` selectors.** When +that lands, run `MatchTrim` here with `MatchSignals{StyleName: ds.Name}` and +source the attributes from the resolved result. + +### 2.3 Trim matching reaches drivly-decoded VINs only + +Adjudicated in the ledger and unchanged: `manufacturerCode` is populated by +`buildFromDrivly` alone; vincario, autoiso, DATGroup, Japan17VIN, CarVX and +Tesla all leave it empty. Templates key trims on `manufacturerCode` only, so +every non-drivly decode returns `model-only`. That is visible in the response +rather than silent, and now countable — +`device_definitions_api_vin_trim_match_quality_total{quality,source}` was added +by this review for exactly this. + +**Watch when the follow-up lands:** whatever `styleName` values the extraction +emits must agree with what dd-api sends. dd-api's drivly style name is +`strings.TrimSpace(trim + " " + subModel)` (`buildDrivlyStyleName`); other +providers build it differently again (`autoiso` → `SubModel`, `DATGroup` → +`SubModelName`). Matching is case-insensitive but otherwise exact, so a +format disagreement produces `model-only` across the board with no error. + +### 2.4 `docs/swagger.json` is stale + +`GET /device-definitions/{id}` now returns `models.Template`. The handler +annotation was corrected on this branch; `docs/swagger.json` and +`docs/swagger.yaml` still describe `DeviceDefinitionTablelandModel`. They are +generated (`make gen-swag`) and `swag` is not installed in this environment, so +regeneration was left out rather than hand-edited. **Run `make gen-swag` before +merge or as the first commit after it.** + +Separately: this is an **undeclared response-shape change on a public REST +endpoint**. Any consumer reading `metadata.device_attributes` from it breaks. +That is a consequence of the migration, not a defect, but it needs announcing. + +### 2.5 `POST /device-definitions/decode-vin` surfaces none of the new fields + +`device_definition_handler.go`'s `DecodeVINResponse` returns only +`deviceDefinitionId` and `newTransactionHash`. Trim, match quality, candidates, +matched-by and hardware template id reach gRPC consumers only. Pre-existing +shape, but materially more lossy now. Widen it if any REST consumer needs the +trim. + +### 2.6 `GetTemplateByIDFresh` has no production caller + +Its only caller was `bulk_update_powertrain`, deleted by this branch's own +commit `675c939` along with the legacy `Update()` write path. Kept because it +is the read half of the `Create()` migration in item 1; its comment now says so +explicitly. **If that migration lands without adopting it, delete it** — do not +keep it alive on the strength of a comment. + +### 2.7 Minor, inherited + +- `get_dd_dynamic_filter.go:141` (`buildDeviceDefinitionQueryResponseFromTemplate`) + ignores `GetManufacturer`'s error and then dereferences `manufacturer.TokenID`. + Identity's client can return `(nil, nil)`, so this can nil-panic. It mirrors + the pre-existing `buildDeviceDefinitionQueryResponse` at line 102 exactly — + fix both together or neither. +- `MatchTrim` has no nil-`tmpl` guard. Both call sites check; note it if a + third is added. +- The attribute merge in `MatchTrim` is a shallow copy, so a mutable reference + value would alias the template. Unreachable while the contract restricts + attribute values to string/number/integer/boolean. +- `decode_vin.go` still creates a definition when `GetTemplateByID` returns a + nil template with a nil error. Unreachable through the real gateway — + `fetchTemplateDocFrom` returns either an error or a non-nil template — so it + is defensive only. + +--- + +## 3. What is *not* a follow-up — verified holding + +Recorded so a later reader does not have to re-derive them. + +- **`processDeviceStyle` still receives the independently-derived powertrain.** + `pt` is assigned only at `decode_vin.go:257` and `:260`, both from + `powerTrainTypeService`, and read at `:263` and at the `processDeviceStyle` + call. The resolved-trim block resets `resp.Powertrain` and never touches + `pt`. Resolved-trim data does not reach `device_styles`, so today's decode + cannot shape tomorrow's templates through the extraction pipeline's input. +- **Proto changes are additive.** Fields 1–15 are byte-identical; 16 and 17 are + appended. Regenerated with the pinned `protoc-gen-go` v1.30.0. +- **No fallback to `definitions/.json` on the template read.** Asserted by + a test that pins the exact request path, on both `GetTemplateByID` and + `GetTemplateByIDFresh`. diff --git a/docs/superpowers/plans/2026-08-28-resolved-decode.md b/docs/superpowers/plans/2026-08-28-resolved-decode.md new file mode 100644 index 00000000..e9030557 --- /dev/null +++ b/docs/superpowers/plans/2026-08-28-resolved-decode.md @@ -0,0 +1,446 @@ +# Resolved Decode Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Make a VIN decode narrow a multi-trim template to one trim and say how confident it is, instead of asserting one flat record for every configuration of a car. + +**Architecture:** The catalog service reads the new template shape (`t/.json`) instead of the flat definition. A pure matcher narrows a template's trims against signals the VIN decoder already produces, returning a trim plus a match quality. `decode_vin` emits that, and `DecodeVinResponse` gains fields for the trim, the template version it came from, and the match quality. A decode that cannot narrow says so rather than picking. + +**Tech Stack:** Go 1.24, gomock, protobuf/gRPC. `go test -race ./...`. + +**Spec:** `../definitions-worker/docs/superpowers/specs/2026-08-27-open-trim-registry.md` +**Contract:** `../definitions-worker/schema/resolved.schema.json` and `template.schema.json` + +## Global Constraints + +- **No fallback to `definitions/.json`.** The template import is a prerequisite of this deploy, not a runtime concern. A dual read path would be a second thing to maintain and would mask an incomplete import — the failure this whole migration exists to stop. +- **Proto changes are additive only.** New field numbers. Never renumber or remove an existing field; consumers are deployed independently. +- **A decode that cannot narrow must say so.** `match.quality` is `exact`, `ambiguous`, or `model-only`. On `ambiguous`, emit only the attributes every candidate trim agrees on and name the candidates. Never pick one arbitrarily — that is precisely the bug this replaces. +- Attribute values are typed; absent, never empty. +- **Commit messages must contain no `Co-Authored-By` trailer and no Claude or AI attribution of any kind.** + +## Why this exists + +`toyota_camry_2020` in production declares `powertrain_type: ICE` while carrying the hybrid's fuel economy, tank size and OEM code. Every 2020 Camry resolves to it. The extraction pipeline now emits that model-year as ten trims — three HEV at 13.2 gal against seven ICE at 16. This task is what lets a decode pick the right one. + +## File Structure + +| File | Responsibility | +|---|---| +| `internal/core/models/template.go` *(new)* | `Template`, `Trim`, `TrimSelectors`, `Resolved`, `MatchQuality` — mirroring the JSON Schemas | +| `internal/core/services/trim_match.go` *(new)* | `MatchTrim(tmpl, signals) (Resolved, error)` — pure | +| `internal/infrastructure/gateways/device_definition_catalog_service.go` *(modify)* | Read `t/.json`, decode `Template` | +| `internal/core/queries/decode_vin.go` *(modify)* | Call the matcher, populate the new response fields | +| `pkg/grpc/decoder.proto` *(modify)* | Additive fields | + +--- + +### Task 1: Template types and catalog read + +**Files:** +- Create: `internal/core/models/template.go` +- Modify: `internal/infrastructure/gateways/device_definition_catalog_service.go` +- Test: `internal/infrastructure/gateways/device_definition_catalog_service_test.go` + +**Interfaces:** +- Produces: `models.Template`, `models.Trim`, `models.TrimSelectors`, `models.TemplateManufacturer`. + `GetTemplateByID(ctx, id) (*models.Template, *big.Int, error)` on `DeviceDefinitionCatalogService`, replacing `GetDefinitionByID`. `GetDefinitionByIDFresh` becomes `GetTemplateByIDFresh` with the same read-through semantics. + +- [ ] **Step 1: Write the failing test** + +Add to `device_definition_catalog_service_test.go`. Use the real emitted shape — this is a verbatim trim of the Camry the pipeline produces: + +```go +const templateJSON = `{ + "id": "toyota_camry_2020", + "deviceType": "vehicle", + "manufacturer": {"slug": "toyota", "name": "Toyota", "tokenId": 131}, + "model": "Camry", + "year": 2020, + "attributes": {"number_of_doors": 4, "vehicle_type": "sedan"}, + "trims": [ + {"name": "LE", "selectors": {"manufacturerCode": ["2532"]}, + "attributes": {"powertrain_type": "ICE", "fuel_type": "gasoline", "fuel_tank_capacity_gal": 16, "mpg_city": 28}}, + {"name": "Hybrid LE", "selectors": {"manufacturerCode": ["2559"]}, + "attributes": {"powertrain_type": "HEV", "fuel_type": "gasoline", "fuel_tank_capacity_gal": 13.2, "mpg_city": 51}} + ], + "version": 3, + "createdAt": "2026-08-27T00:00:00.000Z", + "updatedAt": "2026-08-28T00:00:00.000Z" +}` + +func TestTemplateUnmarshal(t *testing.T) { + var tmpl coremodels.Template + require.NoError(t, json.Unmarshal([]byte(templateJSON), &tmpl)) + + assert.Equal(t, "toyota_camry_2020", tmpl.ID) + assert.Equal(t, 2020, tmpl.Year) + assert.Equal(t, 3, tmpl.Version) + assert.Equal(t, "Toyota", tmpl.Manufacturer.Name) + assert.Equal(t, 131, tmpl.Manufacturer.TokenID) + + // Attributes are typed, not stringified. + assert.Equal(t, float64(4), tmpl.Attributes["number_of_doors"]) + + require.Len(t, tmpl.Trims, 2) + assert.Equal(t, "LE", tmpl.Trims[0].Name) + assert.Equal(t, []string{"2532"}, tmpl.Trims[0].Selectors.ManufacturerCode) + assert.Equal(t, "ICE", tmpl.Trims[0].Attributes["powertrain_type"]) + assert.Equal(t, 16.0, tmpl.Trims[0].Attributes["fuel_tank_capacity_gal"]) + assert.Equal(t, 13.2, tmpl.Trims[1].Attributes["fuel_tank_capacity_gal"]) +} + +func TestTemplateHasNoLegacyFields(t *testing.T) { + // ksuid and tableId were removed from the model deliberately; a template + // carrying them would mean the worker regressed. + var raw map[string]any + require.NoError(t, json.Unmarshal([]byte(templateJSON), &raw)) + assert.NotContains(t, raw, "ksuid") + assert.NotContains(t, raw, "tableId") +} + +func TestGetTemplateByIDReadsTheTemplateKey(t *testing.T) { + var gotPath string + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + gotPath = r.URL.Path + w.Header().Set("content-type", "application/json") + _, _ = w.Write([]byte(templateJSON)) + })) + defer srv.Close() + + logger := zerolog.Nop() + svc := NewDeviceDefinitionCatalogService(&config.Settings{DefinitionsCatalogURL: srv.URL}, &logger) + + tmpl, tokenID, err := svc.GetTemplateByID(context.Background(), "toyota_camry_2020") + require.NoError(t, err) + assert.Equal(t, "/t/toyota_camry_2020.json", gotPath) + assert.Equal(t, "toyota_camry_2020", tmpl.ID) + assert.Equal(t, int64(131), tokenID.Int64()) +} + +func TestGetTemplateByIDDoesNotFallBackToTheOldKey(t *testing.T) { + // A 404 on t/.json means the import has not run. Falling back to + // definitions/.json would serve the pre-migration flat record and hide + // an incomplete import behind apparently-working decodes. + var paths []string + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + paths = append(paths, r.URL.Path) + w.WriteHeader(http.StatusNotFound) + })) + defer srv.Close() + + logger := zerolog.Nop() + svc := NewDeviceDefinitionCatalogService(&config.Settings{DefinitionsCatalogURL: srv.URL}, &logger) + + _, _, err := svc.GetTemplateByID(context.Background(), "toyota_camry_2020") + require.Error(t, err) + assert.Equal(t, []string{"/t/toyota_camry_2020.json"}, paths) +} +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `go test ./internal/infrastructure/gateways/ -run 'Template' -v` +Expected: compile failure — `coremodels.Template` undefined. + +- [ ] **Step 3: Write minimal implementation** + +```go +// internal/core/models/template.go +package models + +// Template mirrors definitions-worker/schema/template.schema.json. Attribute +// values are typed in the contract — a number arrives as a number — so they +// are decoded as any rather than string. +type Template struct { + ID string `json:"id"` + DeviceType string `json:"deviceType"` + Manufacturer TemplateManufacturer `json:"manufacturer"` + Model string `json:"model"` + Year int `json:"year"` + ImageURI string `json:"imageURI,omitempty"` + // HardwareTemplateID is DIMO hardware configuration, not a vehicle + // attribute, which is why it sits outside Attributes and is never + // validated against the vehicle vocabulary. + HardwareTemplateID string `json:"hardwareTemplateId,omitempty"` + Attributes map[string]any `json:"attributes"` + Trims []Trim `json:"trims"` + Version int `json:"version"` + Author string `json:"author,omitempty"` + CreatedAt string `json:"createdAt,omitempty"` + UpdatedAt string `json:"updatedAt,omitempty"` +} + +type TemplateManufacturer struct { + Slug string `json:"slug"` + Name string `json:"name"` + TokenID int `json:"tokenId,omitempty"` +} + +type Trim struct { + Name string `json:"name"` + Selectors TrimSelectors `json:"selectors"` + HardwareTemplateID string `json:"hardwareTemplateId,omitempty"` + Attributes map[string]any `json:"attributes"` +} + +type TrimSelectors struct { + ManufacturerCode []string `json:"manufacturerCode,omitempty"` + StyleName []string `json:"styleName,omitempty"` + VINPattern string `json:"vinPattern,omitempty"` +} +``` + +In the catalog service, replace `fetchDoc`'s key with `"/t/" + url.PathEscape(id) + ".json"`, decode into `models.Template`, and return it. Rename `GetDefinitionByID` → `GetTemplateByID` and `GetDefinitionByIDFresh` → `GetTemplateByIDFresh` throughout, regenerating the gomock file. + +- [ ] **Step 4: Run test to verify it passes** + +Run: `go test ./internal/infrastructure/gateways/ -run 'Template' -v && go build ./...` + +- [ ] **Step 5: Regenerate mocks and fix every caller** + +Run: `go generate ./... && go build ./... && go test -race ./... 2>&1 | tail -30` +Every compile error is a caller of the renamed methods. Fix them; do not add adapters. + +- [ ] **Step 6: Commit** + +```bash +git add -A internal pkg +git commit -m "feat(catalog): read vehicle templates instead of flat definitions" +``` + +--- + +### Task 2: The trim matcher + +**Files:** +- Create: `internal/core/services/trim_match.go` +- Test: `internal/core/services/trim_match_test.go` + +**Interfaces:** +- Consumes: `models.Template` (Task 1). +- Produces: +```go +type MatchSignals struct { + ManufacturerCode string + StyleName string + VIN string +} +type MatchQuality string +const ( + MatchExact MatchQuality = "exact" + MatchAmbiguous MatchQuality = "ambiguous" + MatchModelOnly MatchQuality = "model-only" +) +type Resolved struct { + DefinitionID string + TemplateVersion int + Trim string + Quality MatchQuality + MatchedBy []string + Candidates []string + Attributes map[string]any + HardwareTemplateID string +} +func MatchTrim(tmpl *models.Template, sig MatchSignals) Resolved +``` + +- [ ] **Step 1: Write the failing test** + +```go +package services + +import ( + "testing" + + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func camry() *coremodels.Template { + return &coremodels.Template{ + ID: "toyota_camry_2020", DeviceType: "vehicle", + Manufacturer: coremodels.TemplateManufacturer{Slug: "toyota", Name: "Toyota", TokenID: 131}, + Model: "Camry", Year: 2020, Version: 3, + Attributes: map[string]any{"number_of_doors": float64(4)}, + Trims: []coremodels.Trim{ + {Name: "LE", Selectors: coremodels.TrimSelectors{ManufacturerCode: []string{"2532"}}, + Attributes: map[string]any{"powertrain_type": "ICE", "fuel_tank_capacity_gal": 16.0, "driven_wheels": "FWD"}}, + {Name: "Hybrid LE", Selectors: coremodels.TrimSelectors{ManufacturerCode: []string{"2559"}}, + Attributes: map[string]any{"powertrain_type": "HEV", "fuel_tank_capacity_gal": 13.2, "driven_wheels": "FWD"}}, + }, + } +} + +func TestMatchTrim_ExactOnManufacturerCode(t *testing.T) { + r := MatchTrim(camry(), MatchSignals{ManufacturerCode: "2559"}) + assert.Equal(t, MatchExact, r.Quality) + assert.Equal(t, "Hybrid LE", r.Trim) + assert.Equal(t, []string{"manufacturerCode"}, r.MatchedBy) + assert.Equal(t, "HEV", r.Attributes["powertrain_type"]) + assert.Equal(t, 13.2, r.Attributes["fuel_tank_capacity_gal"]) + // Template-level attributes merge in. + assert.Equal(t, float64(4), r.Attributes["number_of_doors"]) + assert.Equal(t, 3, r.TemplateVersion) +} + +func TestMatchTrim_TheBlendedCamryIsNoLongerPossible(t *testing.T) { + // The production record declares ICE while carrying the hybrid's 13.2 gal + // tank. Whichever trim matches, powertrain and tank must come from the + // SAME trim. + for _, tc := range []struct{ code, pt string; tank float64 }{ + {"2532", "ICE", 16.0}, + {"2559", "HEV", 13.2}, + } { + r := MatchTrim(camry(), MatchSignals{ManufacturerCode: tc.code}) + assert.Equal(t, tc.pt, r.Attributes["powertrain_type"]) + assert.Equal(t, tc.tank, r.Attributes["fuel_tank_capacity_gal"]) + } +} + +func TestMatchTrim_AmbiguousEmitsOnlyAgreedAttributes(t *testing.T) { + tmpl := camry() + // Both trims claim the same code: a template defect, not a decode failure. + tmpl.Trims[1].Selectors.ManufacturerCode = []string{"2532"} + r := MatchTrim(tmpl, MatchSignals{ManufacturerCode: "2532"}) + assert.Equal(t, MatchAmbiguous, r.Quality) + assert.ElementsMatch(t, []string{"LE", "Hybrid LE"}, r.Candidates) + assert.Empty(t, r.Trim) + // They disagree on powertrain and tank, agree on drive. + assert.NotContains(t, r.Attributes, "powertrain_type") + assert.NotContains(t, r.Attributes, "fuel_tank_capacity_gal") + assert.Equal(t, "FWD", r.Attributes["driven_wheels"]) +} + +func TestMatchTrim_ModelOnlyWhenNothingMatches(t *testing.T) { + r := MatchTrim(camry(), MatchSignals{ManufacturerCode: "9999"}) + assert.Equal(t, MatchModelOnly, r.Quality) + assert.Empty(t, r.Trim) + // Only template-level attributes survive; no trim's values leak in. + assert.Equal(t, float64(4), r.Attributes["number_of_doors"]) + assert.NotContains(t, r.Attributes, "powertrain_type") +} + +func TestMatchTrim_SingleTrimTemplateMatchesWithoutSelectors(t *testing.T) { + tmpl := camry() + tmpl.Trims = tmpl.Trims[:1] + tmpl.Trims[0].Selectors = coremodels.TrimSelectors{} + r := MatchTrim(tmpl, MatchSignals{}) + assert.Equal(t, MatchExact, r.Quality) + assert.Equal(t, "LE", r.Trim) +} + +func TestMatchTrim_StyleNameIsCaseInsensitive(t *testing.T) { + tmpl := camry() + tmpl.Trims[0].Selectors = coremodels.TrimSelectors{StyleName: []string{"LE 4dr Sedan"}} + r := MatchTrim(tmpl, MatchSignals{StyleName: "le 4dr sedan"}) + assert.Equal(t, MatchExact, r.Quality) + assert.Equal(t, "LE", r.Trim) +} + +func TestMatchTrim_TrimOverridesTemplateHardwareTemplateID(t *testing.T) { + tmpl := camry() + tmpl.HardwareTemplateID = "130" + tmpl.Trims[1].HardwareTemplateID = "115" + r := MatchTrim(tmpl, MatchSignals{ManufacturerCode: "2559"}) + assert.Equal(t, "115", r.HardwareTemplateID) + r2 := MatchTrim(tmpl, MatchSignals{ManufacturerCode: "2532"}) + assert.Equal(t, "130", r2.HardwareTemplateID) +} + +func TestMatchTrim_EmptyTemplateIsModelOnlyNotAPanic(t *testing.T) { + tmpl := camry() + tmpl.Trims = nil + r := MatchTrim(tmpl, MatchSignals{ManufacturerCode: "2532"}) + assert.Equal(t, MatchModelOnly, r.Quality) + require.NotNil(t, r.Attributes) +} +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `go test ./internal/core/services/ -run MatchTrim -v` +Expected: compile failure. + +- [ ] **Step 3: Write minimal implementation** + +Match every trim whose selectors all agree with the signals. Exactly one match is `exact`; several is `ambiguous`; none is `model-only`. Merge template attributes first, then the matched trim's. For `ambiguous`, include only attributes on which every candidate agrees. `HardwareTemplateID` takes the matched trim's if set, else the template's. + +- [ ] **Step 4: Run test to verify it passes** + +Run: `go test -race ./internal/core/services/ -run MatchTrim -v` + +- [ ] **Step 5: Commit** + +```bash +git add internal/core/services/trim_match.go internal/core/services/trim_match_test.go +git commit -m "feat(decode): narrow a template to one trim, or say why not" +``` + +--- + +### Task 3: Emit the resolved decode + +**Files:** +- Modify: `pkg/grpc/decoder.proto`, `internal/core/queries/decode_vin.go` +- Test: `internal/core/queries/decode_vin_test.go` + +**Interfaces:** +- Consumes: `MatchTrim` (Task 2), `GetTemplateByID` (Task 1). +- Proto gains, additively: `string trim = 12;`, `int32 template_version = 13;`, `string match_quality = 14;`, `repeated string match_candidates = 15;`. + +- [ ] **Step 1: Add the proto fields and regenerate** + +Append to `DecodeVinResponse` — **new field numbers only**, nothing renumbered or removed: + +```protobuf + // Trim the VIN narrowed to. Empty when match_quality is not "exact". + string trim = 12; + // Version of the template this answer came from, so a caller can pin, + // cache and reproduce a decode. + int32 template_version = 13; + // "exact", "ambiguous", or "model-only". + string match_quality = 14; + // Trim names still in contention when match_quality is "ambiguous". + repeated string match_candidates = 15; +``` + +Run: `make gen` (or the repo's protoc target) and `go build ./...` + +- [ ] **Step 2: Write the failing test** + +Add to `decode_vin_test.go`, following its existing gomock setup: a decode whose upstream returns a style matching `2559` populates `Trim: "Hybrid LE"`, `MatchQuality: "exact"`, `TemplateVersion: 3`, and `Powertrain: "HEV"`; a decode matching nothing yields `MatchQuality: "model-only"` with an empty `Trim` and no powertrain from any trim; and an ambiguous template yields `MatchQuality: "ambiguous"` with `MatchCandidates` populated. + +- [ ] **Step 3: Run test to verify it fails** + +Run: `go test ./internal/core/queries/ -run DecodeVIN -v` + +- [ ] **Step 4: Wire the matcher into `decode_vin`** + +Replace the `GetDefinitionByID` call with `GetTemplateByID`, build `MatchSignals` from what the decoder already produces — `vinInfo.StyleName`, the VIN itself, and the OEM code where a source supplies one — call `MatchTrim`, and populate the new response fields from the result. Keep `resp.Powertrain` populated from the resolved attributes rather than from `ResolvePowerTrainFromVinInfo`, which was the old derivation. + +**Leave `processDeviceStyle` alone.** It writes to Postgres and is the source the extraction pipeline reads; changing it is a separate decision. + +- [ ] **Step 5: Run the full suite** + +Run: `go test -race ./... 2>&1 | tail -20` and `golangci-lint run ./... 2>&1 | tail -20` + +- [ ] **Step 6: Commit** + +```bash +git add -A pkg internal +git commit -m "feat(decode): return the matched trim and how confident the match is" +``` + +--- + +## Self-review + +**Spec coverage.** `resolved.schema.json`'s `match.quality`, `templateVersion`, `trim` and candidate reporting are implemented in Tasks 2 and 3. The template contract is Task 1. `hardwareTemplateId`'s template-default-with-trim-override resolution is covered in Task 2 — the spec item that no previous plan implemented. + +**Deliberately not covered.** Dropping dd-api's search, CRUD and Typesense sync belongs to its own plan; it is a large deletion with its own review surface. `processDeviceStyle` keeps writing styles to Postgres, because that table is the extraction pipeline's input and stopping the writes is a data decision, not a refactor. + +**The riskiest assumption** is that `manufacturerCode` reaches `decode_vin` as a usable signal. The templates key trims on it, and the extraction measured 12,275 drivly rows carrying it, but whether the *decoder* surfaces it per-VIN is unverified in this repo. If it does not, matching falls back to `styleName` and quality degrades to `model-only` more often than it should — which is visible in the response rather than silent, but Task 3 must report how often it happens on real decodes. + +**Type consistency.** `models.Template` and its children are defined in Task 1 and consumed unchanged in Tasks 2 and 3. `Resolved` and `MatchQuality` are defined in Task 2 and consumed in Task 3. Attribute values are `any` throughout, matching the typed-value contract. diff --git a/go.mod b/go.mod index 94708597..8f33fb37 100644 --- a/go.mod +++ b/go.mod @@ -3,15 +3,14 @@ module github.com/DIMO-Network/device-definitions-api go 1.24 require ( + github.com/DATA-DOG/go-sqlmock v1.4.1 github.com/DIMO-Network/shared v1.0.7 github.com/aarondl/null/v8 v8.1.3 github.com/aarondl/sqlboiler/v4 v4.19.5 github.com/aarondl/strmangle v0.0.9 github.com/antchfx/xmlquery v1.4.4 github.com/arsmn/fiber-swagger/v2 v2.31.1 - github.com/aws/aws-sdk-go-v2/config v1.29.17 github.com/docker/go-connections v0.5.0 - github.com/ethereum/go-ethereum v1.16.1 github.com/friendsofgo/errors v0.9.2 github.com/goccy/go-json v0.10.5 github.com/gofiber/adaptor/v2 v2.2.1 @@ -34,7 +33,6 @@ require ( github.com/tidwall/sjson v1.2.5 github.com/typesense/typesense-go v1.1.0 go.uber.org/mock v0.5.2 - golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b google.golang.org/api v0.240.0 google.golang.org/grpc v1.73.0 google.golang.org/protobuf v1.36.6 @@ -46,36 +44,20 @@ require ( cloud.google.com/go/compute/metadata v0.7.0 // indirect dario.cat/mergo v1.0.2 // indirect github.com/DIMO-Network/yaml v0.1.0 // indirect - github.com/DataDog/zstd v1.5.2 // indirect github.com/MicahParks/keyfunc/v2 v2.1.0 // indirect github.com/antchfx/xpath v1.3.4 // indirect github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.22.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/consensys/gnark-crypto v0.18.0 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v0.2.1 // indirect github.com/cpuguy83/dockercfg v0.3.2 // indirect - github.com/crate-crypto/go-eth-kzg v1.3.0 // indirect - github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect - github.com/deckarep/golang-set/v2 v2.8.0 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/distribution/reference v0.6.0 // indirect github.com/ebitengine/purego v0.8.4 // indirect - github.com/ethereum/c-kzg-4844/v2 v2.1.1 // indirect - github.com/ethereum/go-verkle v0.2.2 // indirect + github.com/ethereum/go-ethereum v1.16.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-logr/logr v1.4.3 // indirect @@ -86,7 +68,6 @@ require ( github.com/google/s2a-go v0.1.9 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/googleapis/gax-go/v2 v2.14.2 // indirect - github.com/gorilla/websocket v1.5.3 // indirect github.com/holiman/uint256 v1.3.2 // indirect github.com/lib/pq v1.10.9 // indirect github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect @@ -111,11 +92,8 @@ require ( github.com/prometheus/procfs v0.17.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/sethvargo/go-retry v0.3.0 // indirect - github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil/v4 v4.25.6 // indirect github.com/sony/gobreaker v1.0.0 // indirect - github.com/supranational/blst v0.3.15 // indirect - github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/tinylib/msgp v1.3.0 // indirect @@ -131,6 +109,7 @@ require ( go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.39.0 // indirect + golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.15.0 // indirect golang.org/x/time v0.12.0 // indirect @@ -145,16 +124,11 @@ require ( github.com/aarondl/randomize v0.0.2 // indirect github.com/andybalholm/brotli v1.2.0 // indirect github.com/avast/retry-go/v4 v4.6.1 // indirect - github.com/aws/aws-sdk-go-v2 v1.36.5 - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect - github.com/aws/aws-sdk-go-v2/service/kms v1.41.2 - github.com/aws/smithy-go v1.22.4 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/docker v28.3.1+incompatible // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 + github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 // indirect github.com/go-openapi/jsonpointer v0.21.1 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/spec v0.21.0 // indirect diff --git a/go.sum b/go.sum index 7e2db77c..c56a9679 100644 --- a/go.sum +++ b/go.sum @@ -18,8 +18,6 @@ github.com/DIMO-Network/shared v1.0.7 h1:LfSgsqJ6R7EUyfo2GTfuhrCpoDcweJqe7eVOa4j github.com/DIMO-Network/shared v1.0.7/go.mod h1:lDHUKwwT2LW6Zvd42Nb33dXklRNTmfyOlbUNx2dQfGY= github.com/DIMO-Network/yaml v0.1.0 h1:KQ3oKHUZETchR6Pxbmmol3e4ewrPv/q8cEwqxfwyZbU= github.com/DIMO-Network/yaml v0.1.0/go.mod h1:KkiehcbkVzH8Pf8f9dja8B2aW81gYYZSqfwzSj9yN68= -github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= -github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/MicahParks/keyfunc/v2 v2.1.0 h1:6ZXKb9Rp6qp1bDbJefnG7cTH8yMN1IC/4nf+GVjO99k= @@ -29,8 +27,6 @@ github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= -github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= -github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= github.com/aarondl/inflect v0.0.2 h1:XvH8K5g1wKS921tMmDOUsZ3zS1Eo8WwK5RHC0IGGT2s= github.com/aarondl/inflect v0.0.2/go.mod h1:zjmCfdXHUDQ9jFOV6SeHknpo0Au6rQhV8GchS4Vzv/0= github.com/aarondl/null/v8 v8.1.3 h1:ZJcvvj34BkXAguqU7xzDqEmzG86cSBgM8HYxcqeK0+8= @@ -57,67 +53,18 @@ github.com/arsmn/fiber-swagger/v2 v2.31.1 h1:VmX+flXiGGNqLX3loMEEzL3BMOZFSPwBEWR github.com/arsmn/fiber-swagger/v2 v2.31.1/go.mod h1:ZHhMprtB3M6jd2mleG03lPGhHH0lk9u3PtfWS1cBhMA= github.com/avast/retry-go/v4 v4.6.1 h1:VkOLRubHdisGrHnTu89g08aQEWEgRU7LVEop3GbIcMk= github.com/avast/retry-go/v4 v4.6.1/go.mod h1:V6oF8njAwxJ5gRo1Q7Cxab24xs5NCWZBeaHHBklR8mA= -github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0= -github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0= -github.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0= -github.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8= -github.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0= -github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 h1:KAXP9JSHO1vKGCr5f4O6WmlVKLFFXgWYAGoJosorxzU= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 h1:SsytQyTMHMDPspp+spo7XwXTP44aJZZAC7fBV2C5+5s= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 h1:i2vNHQiXUvKhs3quBR6aqlgJaiaexz/aNvdCktW/kAM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4= -github.com/aws/aws-sdk-go-v2/service/kms v1.41.2 h1:zJeUxFP7+XP52u23vrp4zMcVhShTWbNO8dHV6xCSvFo= -github.com/aws/aws-sdk-go-v2/service/kms v1.41.2/go.mod h1:Pqd9k4TuespkireN206cK2QBsaBTL6X+VPAez5Qcijk= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E= -github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0= -github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w= -github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw= -github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4= -github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= -github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= -github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= -github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= -github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= -github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= -github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v1.1.5 h1:5AAWCBWbat0uE0blr8qzufZP5tBjkRyy/jWe1QWLnvw= -github.com/cockroachdb/pebble v1.1.5/go.mod h1:17wO9el1YEigxkP/YtV8NtCivQDgoCyBg5c4VR/eOWo= -github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= -github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= -github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= -github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= -github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= @@ -130,26 +77,12 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= -github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/crate-crypto/go-eth-kzg v1.3.0 h1:05GrhASN9kDAidaFJOda6A4BEvgvuXbazXg/0E3OOdI= -github.com/crate-crypto/go-eth-kzg v1.3.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= -github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= -github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set/v2 v2.8.0 h1:swm0rlPCmdWn9mESxKOjWk8hXSqoxOp+ZlfuyaAdFlQ= -github.com/deckarep/golang-set/v2 v2.8.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= -github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= -github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= -github.com/deepmap/oapi-codegen v1.6.0 h1:w/d1ntwh91XI0b/8ja7+u5SvA4IFfM0UNNLmiDR1gg0= -github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= @@ -170,29 +103,16 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ericlagergren/decimal v0.0.0-20181231230500-73749d4874d5 h1:HQGCJNlqt1dUs/BhtEKmqWd6LWS+DWYVxi9+Jo4r0jE= github.com/ericlagergren/decimal v0.0.0-20181231230500-73749d4874d5/go.mod h1:1yj25TwtUlJ+pfOu9apAVaM1RWfZGg+aFpd4hPQZekQ= -github.com/ethereum/c-kzg-4844/v2 v2.1.1 h1:KhzBVjmURsfr1+S3k/VE35T02+AW2qU9t9gr4R6YpSo= -github.com/ethereum/c-kzg-4844/v2 v2.1.1/go.mod h1:TC48kOKjJKPbN7C++qIgt0TJzZ70QznYR7Ob+WXl57E= github.com/ethereum/go-ethereum v1.16.1 h1:7684NfKCb1+IChudzdKyZJ12l1Tq4ybPZOITiCDXqCk= github.com/ethereum/go-ethereum v1.16.1/go.mod h1:ngYIvmMAYdo4sGW9cGzLvSsPGhDOOzL0jK5S5iXpj0g= -github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= -github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk= -github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/friendsofgo/errors v0.9.2 h1:X6NYxef4efCBdwI7BgS820zFaN7Cphrmb+Pljdzjtgk= github.com/friendsofgo/errors v0.9.2/go.mod h1:yCvFW5AkDIL9qn7suHVLiI/gH228n7PC4Pn44IGoTOI= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= -github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= -github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -221,7 +141,6 @@ github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDq github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -232,15 +151,11 @@ github.com/gofiber/contrib/jwt v1.1.2/go.mod h1:CpIwrkUQ3Q6IP8y9n3f0wP9bOnSKx39E github.com/gofiber/fiber/v2 v2.31.0/go.mod h1:1Ega6O199a3Y7yDGuM9FyXDPYQfv+7/y48wl6WCwUF4= github.com/gofiber/fiber/v2 v2.52.8 h1:xl4jJQ0BV5EJTA2aWiKw/VddRpHrKeZLF0QPUxqn0x4= github.com/gofiber/fiber/v2 v2.52.8/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= -github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= -github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= -github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -251,30 +166,12 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE= @@ -286,10 +183,6 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7 github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= -github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= -github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 h1:sGm2vDRFUrQJO/Veii4h4zG2vvqG6uWNkBHSTqXOZk0= @@ -298,26 +191,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92Bcuy github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= -github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= -github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= -github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4= -github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= -github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= -github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= -github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k= -github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= -github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= -github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU= -github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= -github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= -github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jarcoal/httpmock v1.1.0 h1:F47ChZj1Y2zFsCXxNkBPwNNKnAyOATcdQibk0qEdVCE= github.com/jarcoal/httpmock v1.1.0/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jinzhu/copier v0.3.4 h1:mfU6jI9PtCeUjkjQ322dlff9ELjGDu975C2p/nrubVI= @@ -331,8 +206,6 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -343,8 +216,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= -github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -368,12 +239,8 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY= github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg= -github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= -github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= -github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= @@ -397,29 +264,18 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro= github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= -github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= @@ -428,20 +284,8 @@ github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT9 github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= -github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= -github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= -github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= -github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= -github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= -github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= -github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= -github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c= -github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= -github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM= -github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -469,21 +313,14 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= -github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= -github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE= github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas= -github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= -github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs= github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -505,22 +342,16 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/supranational/blst v0.3.15 h1:rd9viN6tfARE5wv3KZJ9H8e1cg0jXW8syFCcsbHa76o= -github.com/supranational/blst v0.3.15/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ= github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= -github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= -github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/testcontainers/testcontainers-go v0.37.0 h1:L2Qc0vkTw2EHWQ08djon0D2uw7Z/PtHS/QzZZ5Ra/hg= github.com/testcontainers/testcontainers-go v0.37.0/go.mod h1:QPzbxZhQ6Bclip9igjLFj6z0hs01bU8lrl2dHQmgFGM= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -542,16 +373,12 @@ github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XV github.com/typesense/typesense-go v1.1.0 h1:QocehDarVXRArMIosPIdawiVFZZbnRkPJxwnAGOFkzw= github.com/typesense/typesense-go v1.1.0/go.mod h1:KcPODU7ltrcUFC/gygMTkAAfZ9M8/q6ayrdl1MnE1kI= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= -github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.34.0/go.mod h1:epZA5N+7pY6ZaEKRmstzOuYJx9HI8DI1oaCGZpdH4h0= github.com/valyala/fasthttp v1.63.0 h1:DisIL8OjB7ul2d7cBaMRcKTQDYnrGy56R4FCiuDP0Ns= github.com/valyala/fasthttp v1.63.0/go.mod h1:REc4IeW+cAEyLrRPa5A81MIjvz0QE1laoTX2EaPHKJM= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -618,21 +445,17 @@ golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -661,20 +484,13 @@ golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -683,7 +499,6 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -732,7 +547,6 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= @@ -745,7 +559,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/api v0.240.0 h1:PxG3AA2UIqT1ofIzWV2COM3j3JagKTKSwy7L6RHNXNU= @@ -768,14 +581,6 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -783,17 +588,12 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= -gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/api/api.go b/internal/api/api.go index 93c65b8d..ea0d5d00 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -3,15 +3,11 @@ package api import ( "context" - "github.com/DIMO-Network/device-definitions-api/internal/contracts" jwtware "github.com/gofiber/contrib/jwt" "github.com/gofiber/fiber/v2/middleware/cors" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/search" - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/sender" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/DIMO-Network/device-definitions-api/internal/core/mediator" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/metrics" @@ -35,7 +31,7 @@ import ( "github.com/rs/zerolog" ) -func Run(ctx context.Context, logger zerolog.Logger, settings *config.Settings, send sender.Sender) { +func Run(ctx context.Context, logger zerolog.Logger, settings *config.Settings) { //db pdb := db.NewDbConnectionFromSettings(ctx, &settings.DB, true) @@ -44,16 +40,6 @@ func Run(ctx context.Context, logger zerolog.Logger, settings *config.Settings, // redis //redisCache := redis.NewRedisCacheService(settings.IsProd(), settings.Redis) - ethClient, err := ethclient.Dial(settings.EthereumRPCURL.String()) - if err != nil { - logger.Fatal().Err(err).Msg("Failed to create Ethereum client.") - } - - chainID, err := ethClient.ChainID(ctx) - if err != nil { - logger.Fatal().Err(err).Msg("Couldn't retrieve chain id.") - } - //infra identityAPI := gateways.NewIdentityAPIService(&logger, settings) drivlyAPIService := gateways.NewDrivlyAPIService(settings) @@ -63,46 +49,40 @@ func Run(ctx context.Context, logger zerolog.Logger, settings *config.Settings, japan17VINAPI := gateways.NewJapan17VINAPI(&logger, settings) carvxAPI := gateways.NewCarVxVINAPI(&logger, settings) elevaAPI := gateways.NewElevaAPI(settings) - registryInstance, err := contracts.NewRegistry(settings.EthereumRegistryAddress, ethClient) - if err != nil { - logger.Fatal().Err(err).Msg("Failed to create registry query instance.") - } - ddOnChainService := gateways.NewDeviceDefinitionOnChainService(settings, &logger, ethClient, chainID, send, pdb.DBS) + ddCatalogService := gateways.NewDeviceDefinitionCatalogService(settings, &logger) datGroupWSService := gateways.NewDATGroupAPIService(settings, &logger) //repos //makeRepository := repositories.NewDeviceMakeRepository(pdb.DBS) deviceStyleRepository := repositories.NewDeviceStyleRepository(pdb.DBS) - vinRepository := repositories.NewVINRepository(pdb.DBS, registryInstance, identityAPI) + vinRepository := repositories.NewVINRepository(pdb.DBS, identityAPI) //cache services - vincDecodingService := services.NewVINDecodingService(drivlyAPIService, vincarioAPIService, autoIsoAPIService, &logger, ddOnChainService, datGroupWSService, pdb.DBS, japan17VINAPI, carvxAPI, elevaAPI) - powerTrainTypeService, err := services.NewPowerTrainTypeService("powertrain_type_rule.yaml", &logger, ddOnChainService) + vincDecodingService := services.NewVINDecodingService(drivlyAPIService, vincarioAPIService, autoIsoAPIService, &logger, ddCatalogService, datGroupWSService, pdb.DBS, japan17VINAPI, carvxAPI, elevaAPI) + powerTrainTypeService, err := services.NewPowerTrainTypeService("powertrain_type_rule.yaml", &logger, ddCatalogService) searchService := search.NewTypesenseAPIService(settings, &logger) if err != nil { logger.Fatal().Err(err).Send() } - decodeVINHandler := queries.NewDecodeVINQueryHandler(pdb.DBS, vincDecodingService, vinRepository, &logger, fuelAPIService, powerTrainTypeService, ddOnChainService, identityAPI) - upsertVINHandler := queries.NewUpsertDecodingQueryHandler(pdb.DBS, &logger, ddOnChainService) + decodeVINHandler := queries.NewDecodeVINQueryHandler(pdb.DBS, vincDecodingService, vinRepository, &logger, fuelAPIService, powerTrainTypeService, ddCatalogService, identityAPI) + upsertVINHandler := queries.NewUpsertDecodingQueryHandler(pdb.DBS, &logger, ddCatalogService) //custom commands m, _ := mediator.New( //mediator.WithBehaviour(common.NewLoggingBehavior(&logger, settings)), //mediator.WithBehaviour(common.NewValidationBehavior(&logger, settings)), //mediator.WithBehaviour(common.NewErrorHandlingBehavior(&logger, settings)), - mediator.WithHandler(&queries.GetDeviceDefinitionByIDQuery{}, queries.NewGetDeviceDefinitionByIDQueryHandler(ddOnChainService, pdb.DBS)), - mediator.WithHandler(&queries.GetDeviceDefinitionByMakeModelYearQuery{}, queries.NewGetDeviceDefinitionByMakeModelYearQueryHandler(ddOnChainService, pdb.DBS, identityAPI)), - mediator.WithHandler(&queries.GetDeviceDefinitionByDynamicFilterQuery{}, queries.NewGetDeviceDefinitionByDynamicFilterQueryHandler(pdb.DBS, ddOnChainService)), + mediator.WithHandler(&queries.GetDeviceDefinitionByIDQuery{}, queries.NewGetDeviceDefinitionByIDQueryHandler(ddCatalogService, pdb.DBS)), mediator.WithHandler(&queries.GetAllIntegrationQuery{}, queries.NewGetAllIntegrationQueryHandler(pdb.DBS)), mediator.WithHandler(&queries.GetIntegrationByIDQuery{}, queries.NewGetIntegrationByIDQueryHandler(pdb.DBS)), - mediator.WithHandler(&queries.GetDeviceStyleByIDQuery{}, queries.NewGetDeviceStyleByIDQueryHandler(pdb.DBS, ddOnChainService)), + mediator.WithHandler(&queries.GetDeviceStyleByIDQuery{}, queries.NewGetDeviceStyleByIDQueryHandler(pdb.DBS, ddCatalogService)), mediator.WithHandler(&queries.GetDeviceStyleByFilterQuery{}, queries.NewGetDeviceStyleByFilterQueryHandler(pdb.DBS)), mediator.WithHandler(&queries.GetDeviceStyleByDeviceDefinitionIDQuery{}, queries.NewGetDeviceStyleByDeviceDefinitionIDQueryHandler(pdb.DBS)), mediator.WithHandler(&queries.GetDeviceStyleByExternalIDQuery{}, queries.NewGetDeviceStyleByExternalIDQueryHandler(pdb.DBS)), mediator.WithHandler(&queries.GetDeviceTypeByIDQuery{}, queries.NewGetDeviceTypeByIDQueryHandler(pdb.DBS)), mediator.WithHandler(&queries.GetDeviceDefinitionImagesByIDsQuery{}, queries.NewGetDeviceDefinitionImagesByIDsQueryHandler(pdb.DBS, &logger)), - mediator.WithHandler(&commands.CreateDeviceDefinitionCommand{}, commands.NewCreateDeviceDefinitionCommandHandler(ddOnChainService, pdb.DBS, powerTrainTypeService, fuelAPIService, &logger, identityAPI)), + mediator.WithHandler(&commands.CreateDeviceDefinitionCommand{}, commands.NewCreateDeviceDefinitionCommandHandler(ddCatalogService, pdb.DBS, powerTrainTypeService, fuelAPIService, &logger, identityAPI)), mediator.WithHandler(&commands.CreateDeviceStyleCommand{}, commands.NewCreateDeviceStyleCommandHandler(deviceStyleRepository)), mediator.WithHandler(&commands.UpdateDeviceStyleCommand{}, commands.NewUpdateDeviceStyleCommandHandler(pdb.DBS)), mediator.WithHandler(&queries.GetAllDeviceTypeQuery{}, queries.NewGetAllDeviceTypeQueryHandler(pdb.DBS)), @@ -114,7 +94,7 @@ func Run(ctx context.Context, logger zerolog.Logger, settings *config.Settings, mediator.WithHandler(&commands.BulkValidateVinCommand{}, commands.NewBulkValidateVinCommandHandler( pdb.DBS, decodeVINHandler, - queries.NewGetDeviceDefinitionByIDQueryHandler(ddOnChainService, pdb.DBS), + queries.NewGetDeviceDefinitionByIDQueryHandler(ddCatalogService, pdb.DBS), )), mediator.WithHandler(&queries.GetIntegrationByTokenIDQuery{}, queries.NewGetIntegrationByTokenIDQueryHandler(pdb.DBS, &logger)), @@ -122,7 +102,7 @@ func Run(ctx context.Context, logger zerolog.Logger, settings *config.Settings, mediator.WithHandler(&queries.GetR1CompatibilitySearch{}, queries.NewGetR1CompatibilitySearchQueryHandler(searchService)), mediator.WithHandler(&queries.GetAllDeviceDefinitionByAutocompleteQuery{}, queries.NewGetAllDeviceDefinitionByAutocompleteQueryHandler(searchService)), mediator.WithHandler(&queries.GetCompatibilityR1SheetQuery{}, queries.NewCompatibilityR1SheetQueryHandler(settings)), - mediator.WithHandler(&queries.GetDeviceDefinitionByIDQueryV2{}, queries.NewGetDeviceDefinitionByIDQueryV2Handler(ddOnChainService, pdb.DBS)), + mediator.WithHandler(&queries.GetDeviceDefinitionByIDQueryV2{}, queries.NewGetDeviceDefinitionByIDQueryV2Handler(ddCatalogService, pdb.DBS)), mediator.WithHandler(&queries.GetVINProfileQuery{}, queries.NewGetVINProfileQueryHandler(pdb.DBS, &logger, powerTrainTypeService)), mediator.WithHandler(&queries.UpsertDecodingQuery{}, upsertVINHandler), @@ -152,7 +132,7 @@ func Run(ctx context.Context, logger zerolog.Logger, settings *config.Settings, app.Get("/v1/swagger/*", swagger.HandlerDefault) - go StartGrpcServer(logger, settings, *m, pdb.DBS, ddOnChainService, registryInstance, identityAPI, &decodeVINHandler, &upsertVINHandler) + go StartGrpcServer(logger, settings, *m, pdb.DBS, &decodeVINHandler, &upsertVINHandler) // Start Server from a different go routine go func() { diff --git a/internal/api/grpc_definitions_service.go b/internal/api/grpc_definitions_service.go index 918891a7..f7567524 100644 --- a/internal/api/grpc_definitions_service.go +++ b/internal/api/grpc_definitions_service.go @@ -2,158 +2,27 @@ package api import ( "context" - "encoding/json" - stringutils "github.com/DIMO-Network/shared/pkg/strings" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" "google.golang.org/protobuf/types/known/emptypb" - "github.com/DIMO-Network/device-definitions-api/internal/contracts" "github.com/DIMO-Network/device-definitions-api/internal/core/commands" "github.com/DIMO-Network/device-definitions-api/internal/core/mediator" coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" "github.com/DIMO-Network/device-definitions-api/internal/core/queries" - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" p_grpc "github.com/DIMO-Network/device-definitions-api/pkg/grpc" "github.com/DIMO-Network/shared/pkg/db" - "github.com/friendsofgo/errors" "github.com/rs/zerolog" ) type GrpcDefinitionsService struct { p_grpc.DeviceDefinitionServiceServer - Mediator mediator.Mediator - logger *zerolog.Logger - dbs *db.ReaderWriter - onChainDeviceDefs gateways.DeviceDefinitionOnChainService - queryInstance *contracts.Registry - identity gateways.IdentityAPI -} - -func NewGrpcService(mediator mediator.Mediator, logger *zerolog.Logger, dbs func() *db.ReaderWriter, - onChainDefs gateways.DeviceDefinitionOnChainService, queryInstance *contracts.Registry, identity gateways.IdentityAPI) p_grpc.DeviceDefinitionServiceServer { - return &GrpcDefinitionsService{Mediator: mediator, logger: logger, dbs: dbs(), onChainDeviceDefs: onChainDefs, queryInstance: queryInstance, identity: identity} + Mediator mediator.Mediator + logger *zerolog.Logger + dbs *db.ReaderWriter } -//** Device Definitions - -// GetFilteredDeviceDefinition used by: admin, cs-support-platform -func (s *GrpcDefinitionsService) GetFilteredDeviceDefinition(ctx context.Context, in *p_grpc.FilterDeviceDefinitionRequest) (*p_grpc.GetFilteredDeviceDefinitionsResponse, error) { - - qryResult, _ := s.Mediator.Send(ctx, &queries.GetDeviceDefinitionByDynamicFilterQuery{ - DefinitionID: in.DefinitionId, - MakeSlug: in.MakeSlug, - Year: int(in.Year), - Model: in.Model, - VerifiedVinList: in.VerifiedVinList, - PageIndex: int(in.PageIndex), - PageSize: int(in.PageSize), - }) - - ddResult := qryResult.([]queries.DeviceDefinitionQueryResponse) - - result := &p_grpc.GetFilteredDeviceDefinitionsResponse{} - - for _, deviceDefinition := range ddResult { - var ei map[string]string - var extIDs []*p_grpc.ExternalID - if err := deviceDefinition.ExternalIDs.Unmarshal(&ei); err != nil { - for vendor, id := range ei { - extIDs = append(extIDs, &p_grpc.ExternalID{ - Vendor: vendor, - Id: id, - }) - } - } - result.Items = append(result.Items, &p_grpc.FilterDeviceDefinitionsReponse{ - Id: deviceDefinition.ID, - NameSlug: deviceDefinition.NameSlug, - Model: deviceDefinition.Model, - Year: int32(deviceDefinition.Year), - ImageUrl: deviceDefinition.ImageURL.String, - CreatedAt: deviceDefinition.CreatedAt.UnixMilli(), - UpdatedAt: deviceDefinition.UpdatedAt.UnixMilli(), - Metadata: string(deviceDefinition.Metadata.JSON), - Verified: deviceDefinition.Verified, - DeviceMakeId: deviceDefinition.DeviceMakeID, - Make: deviceDefinition.Make, - ExternalIds: extIDs, - }) - } - - return result, nil -} - -// CreateDeviceDefinition used by: dimo-admin -func (s *GrpcDefinitionsService) CreateDeviceDefinition(ctx context.Context, in *p_grpc.CreateDeviceDefinitionRequest) (*p_grpc.CreateDeviceDefinitionResponse, error) { - // todo we could call the command directly, but maintain testability, what about the update, could it share logic - command := &commands.CreateDeviceDefinitionCommand{ - Source: in.Source, - Make: in.Make, - Model: in.Model, - Year: int(in.Year), - DeviceTypeID: in.DeviceTypeId, - HardwareTemplateID: in.HardwareTemplateId, - Verified: in.Verified, - } - - if len(in.DeviceAttributes) > 0 { - for _, attribute := range in.DeviceAttributes { - command.DeviceAttributes = append(command.DeviceAttributes, &coremodels.UpdateDeviceTypeAttribute{ - Name: attribute.Name, - Value: attribute.Value, - }) - } - } - - commandResult, _ := s.Mediator.Send(ctx, command) - result := commandResult.(commands.CreateDeviceDefinitionCommandResult) - - return &p_grpc.CreateDeviceDefinitionResponse{Id: result.ID, NameSlug: result.NameSlug}, nil -} - -// UpdateDeviceDefinition is used by admin tool to update tableland properties of a dd, and a couple augmented properties -func (s *GrpcDefinitionsService) UpdateDeviceDefinition(ctx context.Context, in *p_grpc.UpdateDeviceDefinitionRequest) (*p_grpc.BaseResponse, error) { - // if verified = true, send update request to tableland - dm, err := s.identity.GetManufacturer(stringutils.SlugString(in.ManufacturerName)) - if err != nil { - return nil, errors.Wrap(err, "failed to find device make") - } - // get manufacturer from chain - manufacturerID, err := s.queryInstance.GetManufacturerIdByName(&bind.CallOpts{Context: ctx, Pending: true}, dm.Name) - if err != nil { - return nil, errors.Wrapf(err, "failed to GetManufacturerIdByName for update: %s", dm.Name) - } - ddTbland, err := s.onChainDeviceDefs.GetDefinitionTableland(ctx, manufacturerID, in.DeviceDefinitionId) // repurposed for definitionID - if err != nil { - return nil, errors.Wrapf(err, "failed to find device definition in tableland for update: %s", in.DeviceDefinitionId) - } - shouldUpdate := false - metadata := gateways.BuildDeviceTypeAttributesTbland(in.DeviceAttributes) - tblMetadata, err := json.Marshal(ddTbland.Metadata) - if err != nil { - s.logger.Err(err).Msgf("failed to unmarshall metadata for: %s", in.DeviceDefinitionId) - } - // check for any changes - if string(tblMetadata) != metadata || ddTbland.DeviceType != in.DeviceTypeId || ddTbland.ImageURI != in.ImageUrl { - shouldUpdate = true - } - if shouldUpdate { - // on chain portion of update - _, err = s.onChainDeviceDefs.Update(ctx, dm.Name, contracts.DeviceDefinitionUpdateInput{ - Id: in.DeviceDefinitionId, // name slug - Metadata: metadata, - Ksuid: ddTbland.KSUID, - DeviceType: in.DeviceTypeId, - ImageURI: in.ImageUrl, - }) - if err != nil { - return nil, errors.Wrap(err, "failed to update device definition on chain") - } - } - - return &p_grpc.BaseResponse{Id: in.DeviceDefinitionId}, nil +func NewGrpcService(mediator mediator.Mediator, logger *zerolog.Logger, dbs func() *db.ReaderWriter) p_grpc.DeviceDefinitionServiceServer { + return &GrpcDefinitionsService{Mediator: mediator, logger: logger, dbs: dbs()} } //** Integrations diff --git a/internal/api/grpc_server.go b/internal/api/grpc_server.go index cbcbc803..0dfcd519 100644 --- a/internal/api/grpc_server.go +++ b/internal/api/grpc_server.go @@ -5,9 +5,6 @@ import ( "github.com/DIMO-Network/device-definitions-api/internal/core/queries" - "github.com/DIMO-Network/device-definitions-api/internal/contracts" - - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" "github.com/DIMO-Network/shared/pkg/db" "github.com/DIMO-Network/device-definitions-api/internal/api/common" @@ -26,14 +23,13 @@ import ( ) func StartGrpcServer(logger zerolog.Logger, s *config.Settings, m mediator.Mediator, dbs func() *db.ReaderWriter, - onChainDeviceDefs gateways.DeviceDefinitionOnChainService, registryInstance *contracts.Registry, identity gateways.IdentityAPI, decodeVINHandler *queries.DecodeVINQueryHandler, upsertVINHandler *queries.UpsertDecodingQueryHandler) { lis, err := net.Listen("tcp", ":"+s.GRPCPort) if err != nil { logger.Fatal().Msgf("Failed to listen on port %v: %v", s.GRPCPort, err) } - deviceDefinitionService := NewGrpcService(m, &logger, dbs, onChainDeviceDefs, registryInstance, identity) + deviceDefinitionService := NewGrpcService(m, &logger, dbs) integrationService := NewGrpcIntegrationService(m, &logger) decodeService := NewGrpcVinDecoderService(&logger, decodeVINHandler, upsertVINHandler) diff --git a/internal/api/handlers/device_definition_handler.go b/internal/api/handlers/device_definition_handler.go index 23c80f2b..d599deb4 100644 --- a/internal/api/handlers/device_definition_handler.go +++ b/internal/api/handlers/device_definition_handler.go @@ -63,13 +63,13 @@ type DecodeVINResponse struct { } // GetDeviceDefinitionByID godoc -// @Summary gets a device definition, from tableland on-chain records. Only support mmy style id's eg. ford_escape_2025 +// @Summary gets a vehicle template from the definitions catalog. Only supports mmy style id's eg. ford_escape_2025 // @ID GetDeviceDefinitionByID -// @Description gets a device definition +// @Description gets a vehicle template: the model-year plus every trim it shipped in. This replaced the flat on-chain device definition; the response now carries typed `attributes` and a `trims` array instead of `metadata.device_attributes`. // @Tags device-definitions // @Param id path string true "mmy definition_id eg. ford_escape_2020" // @Produce json -// @Success 200 {object} models.DeviceDefinitionTablelandModel +// @Success 200 {object} models.Template // @Failure 404 // @Failure 400 // @Failure 500 @@ -166,6 +166,15 @@ func GetR1CompatibilitySearch(m mediator.Mediator) fiber.Handler { pageInt, _ := strconv.Atoi(page) pageSizeInt, _ := strconv.Atoi(pageSize) + // Same clamp as the definitions search below: Query's default applies + // only when the parameter is absent, so pageSize=0 reaches the handler + // as 0 and divides by zero computing totalPages. + if pageSizeInt <= 0 { + pageSizeInt = defaultPageSize + } + if pageInt <= 0 { + pageInt = defaultPage + } query := &queries.GetR1CompatibilitySearch{Query: q, PageSize: pageSizeInt, Page: pageInt} @@ -226,6 +235,15 @@ func GetDeviceDefinitionSearch(m mediator.Mediator) fiber.Handler { pageInt, _ := strconv.Atoi(page) pageSizeInt, _ := strconv.Atoi(pageSize) + // c.Query's default only applies when the parameter is absent, so an + // explicit pageSize=0 (or an unparseable one) reaches the handler as 0 + // and divides by zero when totalPages is computed. + if pageSizeInt <= 0 { + pageSizeInt = defaultPageSize + } + if pageInt <= 0 { + pageInt = defaultPage + } query := &queries.GetAllDeviceDefinitionBySearchQuery{Query: q, Make: mk, Model: model, Year: yrInt, PageSize: pageSizeInt, Page: pageInt} diff --git a/internal/api/handlers/device_definition_handler_test.go b/internal/api/handlers/device_definition_handler_test.go new file mode 100644 index 00000000..32ae3fa2 --- /dev/null +++ b/internal/api/handlers/device_definition_handler_test.go @@ -0,0 +1,62 @@ +package handlers + +import ( + "io" + "net/http" + "testing" + + "github.com/DIMO-Network/device-definitions-api/internal/api/common" + "github.com/DIMO-Network/device-definitions-api/internal/core/mediator" + "github.com/DIMO-Network/device-definitions-api/internal/core/queries" + "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" + mock_gateways "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways/mocks" + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/recover" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +// GET /device-definitions/:id end to end over the pieces that decide its +// status code: the mediator panics with the handler's error, fiber's recover +// hands that value to the error handler untouched when it is an error, and +// FiberConfig maps it by type assertion. A wrapped sentinel satisfies none of +// that and falls through to 500. +func definitionByIDApp(t *testing.T, catalogErr error) *fiber.App { + t.Helper() + ctrl := gomock.NewController(t) + t.Cleanup(ctrl.Finish) + catalog := mock_gateways.NewMockDeviceDefinitionCatalogService(ctrl) + catalog.EXPECT().GetTemplateByID(gomock.Any(), "ford_escapexx_2020").Return(nil, nil, catalogErr) + + m, err := mediator.New( + mediator.WithHandler(&queries.GetDeviceDefinitionByIDQueryV2{}, queries.NewGetDeviceDefinitionByIDQueryV2Handler(catalog, nil)), + ) + require.NoError(t, err) + + app := fiber.New(common.FiberConfig(true)) + app.Use(recover.New()) + app.Get("/device-definitions/:id", GetDeviceDefinitionByID(*m)) + return app +} + +func TestGetDeviceDefinitionByIDIsA404ForAnUnknownID(t *testing.T) { + app := definitionByIDApp(t, errors.Wrapf(gateways.ErrTemplateNotFound, "template %q", "ford_escapexx_2020")) + + resp, err := app.Test(BuildRequest("GET", "/device-definitions/ford_escapexx_2020", "")) + require.NoError(t, err) + body, _ := io.ReadAll(resp.Body) //nolint + + assert.Equal(t, http.StatusNotFound, resp.StatusCode, "an id with no template is not found, not a server error: %s", body) +} + +func TestGetDeviceDefinitionByIDIsA500WhenTheCatalogIsUnreachable(t *testing.T) { + app := definitionByIDApp(t, errors.New("unexpected status 502 from catalog")) + + resp, err := app.Test(BuildRequest("GET", "/device-definitions/ford_escapexx_2020", "")) + require.NoError(t, err) + body, _ := io.ReadAll(resp.Body) //nolint + + assert.Equal(t, http.StatusInternalServerError, resp.StatusCode, "a catalog outage must not read as a missing definition: %s", body) +} diff --git a/internal/config/settings.go b/internal/config/settings.go index 5a2baed0..023fa511 100644 --- a/internal/config/settings.go +++ b/internal/config/settings.go @@ -5,7 +5,6 @@ import ( "net/url" "github.com/DIMO-Network/shared/pkg/db" - "github.com/ethereum/go-ethereum/common" "github.com/DIMO-Network/shared/pkg/redis" ) @@ -32,13 +31,9 @@ type Settings struct { VincarioAPISecret string `yaml:"VINCARIO_API_SECRET"` AutoIsoAPIUid string `yaml:"AUTO_ISO_API_UID"` AutoIsoAPIKey string `yaml:"AUTO_ISO_API_KEY"` - EthereumRPCURL url.URL `yaml:"ETHEREUM_RPC_URL"` - PrivateKeyMode bool `yaml:"PRIVATE_KEY_MODE"` - SenderPrivateKey string `yaml:"SENDER_PRIVATE_KEY"` - KMSKeyID string `yaml:"KMS_KEY_ID"` - EthereumSendTransaction bool `yaml:"ETHEREUM_SEND_TRANSACTION"` - EthereumRegistryAddress common.Address `yaml:"ETHEREUM_REGISTRY_ADDRESS"` - TablelandAPIGateway string `yaml:"TABLELAND_API_GATEWAY"` + DefinitionsCatalogURL string `yaml:"DEFINITIONS_CATALOG_URL"` + DefinitionsWorkerURL string `yaml:"DEFINITIONS_WORKER_URL"` + DefinitionsWorkerToken string `yaml:"DEFINITIONS_WORKER_TOKEN"` DatGroupURL url.URL `yaml:"DAT_GROUP_URL"` DatGroupCustomerLogin string `yaml:"DAT_GROUP_CUSTOMER_LOGIN"` DatGroupCustomerNumber string `yaml:"DAT_GROUP_CUSTOMER_NUMBER"` @@ -49,7 +44,6 @@ type Settings struct { SearchServiceIndexName string `yaml:"SEARCH_SERVICE_DEVICE_DEFINITION_INDEX"` JwtKeySetURL string `yaml:"JWT_KEY_SET_URL"` IdentityAPIURL url.URL `yaml:"IDENTITY_API_URL"` - PolygonScanAPIKey string `yaml:"POLYGON_SCAN_API_KEY"` GoogleSheetsCredentials string `yaml:"GOOGLE_SHEETS_CREDENTIALS"` Japan17VINUser string `yaml:"JAPAN17_VIN_USER"` Japan17VINPassword string `yaml:"JAPAN17_VIN_PASSWORD"` diff --git a/internal/contracts/registry.go b/internal/contracts/registry.go deleted file mode 100644 index 0d5a0b80..00000000 --- a/internal/contracts/registry.go +++ /dev/null @@ -1,12686 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package contracts - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -// AftermarketDeviceIdAddressPair is an auto generated low-level Go binding around an user-defined struct. -type AftermarketDeviceIdAddressPair struct { - AftermarketDeviceNodeId *big.Int - DeviceAddress common.Address -} - -// AftermarketDeviceInfos is an auto generated low-level Go binding around an user-defined struct. -type AftermarketDeviceInfos struct { - Addr common.Address - AttrInfoPairs []AttributeInfoPair -} - -// AftermarketDeviceOwnerPair is an auto generated low-level Go binding around an user-defined struct. -type AftermarketDeviceOwnerPair struct { - AftermarketDeviceNodeId *big.Int - Owner common.Address -} - -// AttributeInfoPair is an auto generated low-level Go binding around an user-defined struct. -type AttributeInfoPair struct { - Attribute string - Info string -} - -// DevAdminIdManufacturerName is an auto generated low-level Go binding around an user-defined struct. -type DevAdminIdManufacturerName struct { - TokenId *big.Int - Name string -} - -// DevAdminVehicleIdDeviceDefinitionId is an auto generated low-level Go binding around an user-defined struct. -type DevAdminVehicleIdDeviceDefinitionId struct { - VehicleId *big.Int - DeviceDefinitionId string -} - -// DeviceDefinitionInput is an auto generated low-level Go binding around an user-defined struct. -type DeviceDefinitionInput struct { - Id string - Model string - Year *big.Int - Metadata string - Ksuid string - DeviceType string - ImageURI string -} - -// DeviceDefinitionUpdateInput is an auto generated low-level Go binding around an user-defined struct. -type DeviceDefinitionUpdateInput struct { - Id string - Metadata string - Ksuid string - DeviceType string - ImageURI string -} - -// MintSyntheticDeviceBatchInput is an auto generated low-level Go binding around an user-defined struct. -type MintSyntheticDeviceBatchInput struct { - VehicleNode *big.Int - SyntheticDeviceAddr common.Address - AttrInfoPairs []AttributeInfoPair -} - -// MintSyntheticDeviceInput is an auto generated low-level Go binding around an user-defined struct. -type MintSyntheticDeviceInput struct { - IntegrationNode *big.Int - VehicleNode *big.Int - SyntheticDeviceSig []byte - VehicleOwnerSig []byte - SyntheticDeviceAddr common.Address - AttrInfoPairs []AttributeInfoPair -} - -// MintVehicleAndSdInput is an auto generated low-level Go binding around an user-defined struct. -type MintVehicleAndSdInput struct { - ManufacturerNode *big.Int - Owner common.Address - AttrInfoPairsVehicle []AttributeInfoPair - IntegrationNode *big.Int - VehicleOwnerSig []byte - SyntheticDeviceSig []byte - SyntheticDeviceAddr common.Address - AttrInfoPairsDevice []AttributeInfoPair -} - -// MintVehicleAndSdWithDdInput is an auto generated low-level Go binding around an user-defined struct. -type MintVehicleAndSdWithDdInput struct { - ManufacturerNode *big.Int - Owner common.Address - DeviceDefinitionId string - AttrInfoPairsVehicle []AttributeInfoPair - IntegrationNode *big.Int - VehicleOwnerSig []byte - SyntheticDeviceSig []byte - SyntheticDeviceAddr common.Address - AttrInfoPairsDevice []AttributeInfoPair -} - -// TablelandPolicy is an auto generated low-level Go binding around an user-defined struct. -type TablelandPolicy struct { - AllowInsert bool - AllowUpdate bool - AllowDelete bool - WhereClause string - WithCheck string - UpdatableColumns []string -} - -// RegistryMetaData contains all meta data concerning the Registry contract. -var RegistryMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"UintUtils__InsufficientHexLength\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"moduleAddr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4[]\",\"name\":\"selectors\",\"type\":\"bytes4[]\"}],\"name\":\"ModuleAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"moduleAddr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4[]\",\"name\":\"selectors\",\"type\":\"bytes4[]\"}],\"name\":\"ModuleRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldImplementation\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4[]\",\"name\":\"oldSelectors\",\"type\":\"bytes4[]\"},{\"indexed\":false,\"internalType\":\"bytes4[]\",\"name\":\"newSelectors\",\"type\":\"bytes4[]\"}],\"name\":\"ModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"},{\"internalType\":\"bytes4[]\",\"name\":\"selectors\",\"type\":\"bytes4[]\"}],\"name\":\"addModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"},{\"internalType\":\"bytes4[]\",\"name\":\"selectors\",\"type\":\"bytes4[]\"}],\"name\":\"removeModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"oldImplementation\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes4[]\",\"name\":\"oldSelectors\",\"type\":\"bytes4[]\"},{\"internalType\":\"bytes4[]\",\"name\":\"newSelectors\",\"type\":\"bytes4[]\"}],\"name\":\"updateModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"AdNotClaimed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"AdPaired\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"InvalidNode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"VehiclePaired\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"AftermarketDeviceAttributeSetDevAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"adNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceNodeBurnedDevAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDevicePaired\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceTransferredDevAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"}],\"name\":\"AftermarketDeviceUnclaimedDevAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceUnpairedDevAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"ddId\",\"type\":\"string\"}],\"name\":\"DeviceDefinitionIdSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"SyntheticDeviceAttributeSetDevAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"syntheticDeviceNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SyntheticDeviceNodeBurnedDevAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"VehicleAttributeRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"VehicleAttributeSetDevAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"VehicleNodeBurnedDevAdmin\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"adminBurnAftermarketDevices\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"adminBurnAftermarketDevicesAndDeletePairings\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"adminBurnSyntheticDevicesAndDeletePairings\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"adminBurnVehicles\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"adminBurnVehiclesAndDeletePairings\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"adminCacheDimoStreamrEns\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newParentNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"nodeIdList\",\"type\":\"uint256[]\"}],\"name\":\"adminChangeParentNode\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"}],\"name\":\"adminPairAftermarketDevice\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"adminRemoveVehicleAttribute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"deviceDefinitionId\",\"type\":\"string\"}],\"internalType\":\"structDevAdmin.VehicleIdDeviceDefinitionId[]\",\"name\":\"vehicleIdDdId\",\"type\":\"tuple[]\"}],\"name\":\"adminSetVehicleDDs\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"internalType\":\"structDevAdmin.IdManufacturerName[]\",\"name\":\"idManufacturerNames\",\"type\":\"tuple[]\"}],\"name\":\"renameManufacturers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferAftermarketDeviceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"aftermarketDeviceNodes\",\"type\":\"uint256[]\"}],\"name\":\"unclaimAftermarketDeviceNode\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"aftermarketDeviceNodes\",\"type\":\"uint256[]\"}],\"name\":\"unpairAftermarketDeviceByDeviceNode\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"vehicleNodes\",\"type\":\"uint256[]\"}],\"name\":\"unpairAftermarketDeviceByVehicleNode\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multiDelegateCall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multiStaticCall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"onERC721Received\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"AdNotPaired\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attr\",\"type\":\"string\"}],\"name\":\"AttributeExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attr\",\"type\":\"string\"}],\"name\":\"AttributeNotWhitelisted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"DeviceAlreadyClaimed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"DeviceAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAdSignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidLicense\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidOwnerSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"InvalidParentNode\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OwnersDoNotMatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"VehicleNotPaired\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"manufacturerId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"aftermarketDeviceAddress\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceAddressReset\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"AftermarketDeviceAttributeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"AftermarketDeviceAttributeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceIdProxySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceNodeBurned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"manufacturerId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"aftermarketDeviceAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceNodeMinted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceUnpaired\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"addAftermarketDeviceAttribute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNodeId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"internalType\":\"structAftermarketDeviceOwnerPair[]\",\"name\":\"adOwnerPair\",\"type\":\"tuple[]\"}],\"name\":\"claimAftermarketDeviceBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"ownerSig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"aftermarketDeviceSig\",\"type\":\"bytes\"}],\"name\":\"claimAftermarketDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"name\":\"getAftermarketDeviceAddressById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getAftermarketDeviceIdByAddress\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"name\":\"isAftermarketDeviceClaimed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isClaimed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairs\",\"type\":\"tuple[]\"}],\"internalType\":\"structAftermarketDeviceInfos[]\",\"name\":\"adInfos\",\"type\":\"tuple[]\"}],\"name\":\"mintAftermarketDeviceByManufacturerBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"aftermarketDeviceSig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"vehicleOwnerSig\",\"type\":\"bytes\"}],\"name\":\"pairAftermarketDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"pairAftermarketDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"aftermarketDeviceNodeList\",\"type\":\"uint256[]\"}],\"name\":\"reprovisionAftermarketDeviceByManufacturerBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNodeId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"deviceAddress\",\"type\":\"address\"}],\"internalType\":\"structAftermarketDeviceIdAddressPair[]\",\"name\":\"adIdAddrs\",\"type\":\"tuple[]\"}],\"name\":\"resetAftermarketDeviceAddressByManufacturerBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setAftermarketDeviceIdProxyAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"}],\"name\":\"setAftermarketDeviceInfo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"}],\"name\":\"unpairAftermarketDevice\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"unpairAftermarketDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"controller\",\"type\":\"address\"}],\"name\":\"ControllerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"ManufacturerAttributeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"ManufacturerAttributeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"ManufacturerIdProxySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"ManufacturerNodeMinted\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"addManufacturerAttribute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"getManufacturerIdByName\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getManufacturerNameById\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isAllowedToOwnManufacturerNode\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isAllowed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isController\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isController\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isManufacturerMinted\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isManufacturerMinted\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairList\",\"type\":\"tuple[]\"}],\"name\":\"mintManufacturer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string[]\",\"name\":\"names\",\"type\":\"string[]\"}],\"name\":\"mintManufacturerBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_controller\",\"type\":\"address\"}],\"name\":\"setController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setManufacturerIdProxyAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoList\",\"type\":\"tuple[]\"}],\"name\":\"setManufacturerInfo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"updateManufacturerMinted\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"AlreadyController\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"IntegrationNameRegisterd\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"MustBeAdmin\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"NotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyNftProxy\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"IntegrationAttributeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"IntegrationAttributeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"IntegrationIdProxySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"IntegrationNodeMinted\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"addIntegrationAttribute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"getIntegrationIdByName\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getIntegrationNameById\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isAllowedToOwnIntegrationNode\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isAllowed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isIntegrationController\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isController\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isIntegrationMinted\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isIntegrationMinted\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairList\",\"type\":\"tuple[]\"}],\"name\":\"mintIntegration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string[]\",\"name\":\"names\",\"type\":\"string[]\"}],\"name\":\"mintIntegrationBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_controller\",\"type\":\"address\"}],\"name\":\"setIntegrationController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setIntegrationIdProxyAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoList\",\"type\":\"tuple[]\"}],\"name\":\"setIntegrationInfo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"updateIntegrationMinted\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"InvalidSdSignature\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"SyntheticDeviceAttributeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"SyntheticDeviceAttributeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"SyntheticDeviceIdProxySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"syntheticDeviceNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SyntheticDeviceNodeBurned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"integrationNode\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"syntheticDeviceNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"syntheticDeviceAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SyntheticDeviceNodeMinted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"VehicleAttributeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"VehicleNodeMinted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"manufacturerId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"deviceDefinitionId\",\"type\":\"string\"}],\"name\":\"VehicleNodeMintedWithDeviceDefinition\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"addSyntheticDeviceAttribute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"syntheticDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"ownerSig\",\"type\":\"bytes\"}],\"name\":\"burnSyntheticDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"name\":\"getSyntheticDeviceAddressById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getSyntheticDeviceIdByAddress\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"integrationNode\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"syntheticDeviceAddr\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairs\",\"type\":\"tuple[]\"}],\"internalType\":\"structMintSyntheticDeviceBatchInput[]\",\"name\":\"data\",\"type\":\"tuple[]\"}],\"name\":\"mintSyntheticDeviceBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"integrationNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"syntheticDeviceSig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"vehicleOwnerSig\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"syntheticDeviceAddr\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairs\",\"type\":\"tuple[]\"}],\"internalType\":\"structMintSyntheticDeviceInput\",\"name\":\"data\",\"type\":\"tuple\"}],\"name\":\"mintSyntheticDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setSyntheticDeviceIdProxyAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"}],\"name\":\"setSyntheticDeviceInfo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"VehicleAttributeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"VehicleIdProxySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"VehicleNodeBurned\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"addVehicleAttribute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"ownerSig\",\"type\":\"bytes\"}],\"name\":\"burnVehicleSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"}],\"name\":\"getDeviceDefinitionIdByVehicleId\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"ddId\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"}],\"name\":\"mintVehicle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"mintVehicleSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"deviceDefinitionId\",\"type\":\"string\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"}],\"name\":\"mintVehicleWithDeviceDefinition\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"deviceDefinitionId\",\"type\":\"string\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"mintVehicleWithDeviceDefinitionSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setVehicleIdProxyAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"}],\"name\":\"setVehicleInfo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"validateBurnAndResetNode\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getDataURI\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"data\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"getInfo\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getParentNode\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"parentNode\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"name\":\"BeneficiarySet\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"name\":\"getBeneficiary\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"sourceNode\",\"type\":\"uint256\"}],\"name\":\"getLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"targetNode\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddressSource\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"idProxyAddressTarget\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"sourceNode\",\"type\":\"uint256\"}],\"name\":\"getNodeLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"targetNode\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"name\":\"setAftermarketDeviceBeneficiary\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairsVehicle\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"integrationNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"vehicleOwnerSig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"syntheticDeviceSig\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"syntheticDeviceAddr\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairsDevice\",\"type\":\"tuple[]\"}],\"internalType\":\"structMintVehicleAndSdInput\",\"name\":\"data\",\"type\":\"tuple\"}],\"name\":\"mintVehicleAndSdSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"deviceDefinitionId\",\"type\":\"string\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairsVehicle\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"integrationNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"vehicleOwnerSig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"syntheticDeviceSig\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"syntheticDeviceAddr\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairsDevice\",\"type\":\"tuple[]\"}],\"internalType\":\"structMintVehicleAndSdWithDdInput\",\"name\":\"data\",\"type\":\"tuple\"}],\"name\":\"mintVehicleAndSdWithDeviceDefinitionSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"dataUri\",\"type\":\"string\"}],\"name\":\"BaseDataURISet\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_baseDataURI\",\"type\":\"string\"}],\"name\":\"setBaseDataURI\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"dimoCredit\",\"type\":\"address\"}],\"name\":\"DimoCreditSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"dimoToken\",\"type\":\"address\"}],\"name\":\"DimoTokenSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"foundation\",\"type\":\"address\"}],\"name\":\"FoundationSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"manufacturerLicense\",\"type\":\"address\"}],\"name\":\"ManufacturerLicenseSet\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"getDimoCredit\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"dimoCredit\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDimoToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"dimoToken\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFoundation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"foundation\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getManufacturerLicense\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"manufacturerLicense\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"dimoCredit\",\"type\":\"address\"}],\"name\":\"setDimoCredit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"dimoToken\",\"type\":\"address\"}],\"name\":\"setDimoToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"foundation\",\"type\":\"address\"}],\"name\":\"setFoundation\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"manufacturerLicense\",\"type\":\"address\"}],\"name\":\"setManufacturerLicense\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"dimoStreamrEns\",\"type\":\"string\"}],\"name\":\"DimoStreamrEnsSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"dimoStreamrNode\",\"type\":\"address\"}],\"name\":\"DimoStreamrNodeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"streamRegistry\",\"type\":\"address\"}],\"name\":\"StreamRegistrySet\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"dimoStreamrEns\",\"type\":\"string\"}],\"name\":\"setDimoBaseStreamId\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"dimoStreamrNode\",\"type\":\"address\"}],\"name\":\"setDimoStreamrNode\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"streamRegistry\",\"type\":\"address\"}],\"name\":\"setStreamRegistry\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"enumIStreamRegistry.PermissionType\",\"name\":\"permissionType\",\"type\":\"uint8\"}],\"name\":\"NoStreamrPermission\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"streamId\",\"type\":\"string\"}],\"name\":\"StreamDoesNotExist\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"streamId\",\"type\":\"string\"}],\"name\":\"VehicleStreamAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"}],\"name\":\"VehicleStreamNotSet\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"streamId\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"expirationTime\",\"type\":\"uint256\"}],\"name\":\"SubscribedToVehicleStream\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"streamId\",\"type\":\"string\"}],\"name\":\"VehicleStreamSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"streamId\",\"type\":\"string\"}],\"name\":\"VehicleStreamUnset\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"}],\"name\":\"createVehicleStream\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"}],\"name\":\"getVehicleStream\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"streamId\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"}],\"name\":\"onBurnVehicleStream\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"expirationTime\",\"type\":\"uint256\"}],\"name\":\"onSetSubscribePrivilege\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"}],\"name\":\"onTransferVehicleStream\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"expirationTime\",\"type\":\"uint256\"}],\"name\":\"setSubscriptionToVehicleStream\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"streamId\",\"type\":\"string\"}],\"name\":\"setVehicleStream\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expirationTime\",\"type\":\"uint256\"}],\"name\":\"subscribeToVehicleStream\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vehicleId\",\"type\":\"uint256\"}],\"name\":\"unsetVehicleStream\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"chainid\",\"type\":\"uint256\"}],\"name\":\"ChainNotSupported\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"InvalidManufacturerId\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerId\",\"type\":\"uint256\"}],\"name\":\"TableAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tableId\",\"type\":\"uint256\"}],\"name\":\"TableDoesNotExist\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tableId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"id\",\"type\":\"string\"}],\"name\":\"DeviceDefinitionDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tableId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"id\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"model\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"}],\"name\":\"DeviceDefinitionInserted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"tableOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"manufacturerId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tableId\",\"type\":\"uint256\"}],\"name\":\"DeviceDefinitionTableCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tableId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"id\",\"type\":\"string\"}],\"name\":\"DeviceDefinitionUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"manufacturerId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tableId\",\"type\":\"uint256\"}],\"name\":\"ManufacturerTableSet\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"tableOwner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"manufacturerId\",\"type\":\"uint256\"}],\"name\":\"createDeviceDefinitionTable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"tableOwner\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"manufacturerIds\",\"type\":\"uint256[]\"}],\"name\":\"createDeviceDefinitionTableBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"id\",\"type\":\"string\"}],\"name\":\"deleteDeviceDefinition\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerId\",\"type\":\"uint256\"}],\"name\":\"getDeviceDefinitionTableId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"tableId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerId\",\"type\":\"uint256\"}],\"name\":\"getDeviceDefinitionTableName\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"tableName\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"id\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"model\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"metadata\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"ksuid\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"deviceType\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"imageURI\",\"type\":\"string\"}],\"internalType\":\"structDeviceDefinitionInput\",\"name\":\"data\",\"type\":\"tuple\"}],\"name\":\"insertDeviceDefinition\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"id\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"model\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"year\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"metadata\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"ksuid\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"deviceType\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"imageURI\",\"type\":\"string\"}],\"internalType\":\"structDeviceDefinitionInput[]\",\"name\":\"data\",\"type\":\"tuple[]\"}],\"name\":\"insertDeviceDefinitionBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"tableId\",\"type\":\"uint256\"}],\"name\":\"setDeviceDefinitionTable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"id\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"metadata\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"ksuid\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"deviceType\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"imageURI\",\"type\":\"string\"}],\"internalType\":\"structDeviceDefinitionUpdateInput\",\"name\":\"data\",\"type\":\"tuple\"}],\"name\":\"updateDeviceDefinition\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"getPolicy\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"allowInsert\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"allowUpdate\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"allowDelete\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"whereClause\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"withCheck\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"updatableColumns\",\"type\":\"string[]\"}],\"internalType\":\"structTablelandPolicy\",\"name\":\"policy\",\"type\":\"tuple\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"operation\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"cost\",\"type\":\"uint256\"}],\"name\":\"OperationCostSet\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"operation\",\"type\":\"bytes32\"}],\"name\":\"getDcxOperationCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"cost\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"operation\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"cost\",\"type\":\"uint256\"}],\"name\":\"setDcxOperationCost\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", -} - -// RegistryABI is the input ABI used to generate the binding from. -// Deprecated: Use RegistryMetaData.ABI instead. -var RegistryABI = RegistryMetaData.ABI - -// Registry is an auto generated Go binding around an Ethereum contract. -type Registry struct { - RegistryCaller // Read-only binding to the contract - RegistryTransactor // Write-only binding to the contract - RegistryFilterer // Log filterer for contract events -} - -// RegistryCaller is an auto generated read-only Go binding around an Ethereum contract. -type RegistryCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// RegistryTransactor is an auto generated write-only Go binding around an Ethereum contract. -type RegistryTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// RegistryFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type RegistryFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// RegistrySession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type RegistrySession struct { - Contract *Registry // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// RegistryCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type RegistryCallerSession struct { - Contract *RegistryCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// RegistryTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type RegistryTransactorSession struct { - Contract *RegistryTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// RegistryRaw is an auto generated low-level Go binding around an Ethereum contract. -type RegistryRaw struct { - Contract *Registry // Generic contract binding to access the raw methods on -} - -// RegistryCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type RegistryCallerRaw struct { - Contract *RegistryCaller // Generic read-only contract binding to access the raw methods on -} - -// RegistryTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type RegistryTransactorRaw struct { - Contract *RegistryTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewRegistry creates a new instance of Registry, bound to a specific deployed contract. -func NewRegistry(address common.Address, backend bind.ContractBackend) (*Registry, error) { - contract, err := bindRegistry(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &Registry{RegistryCaller: RegistryCaller{contract: contract}, RegistryTransactor: RegistryTransactor{contract: contract}, RegistryFilterer: RegistryFilterer{contract: contract}}, nil -} - -// NewRegistryCaller creates a new read-only instance of Registry, bound to a specific deployed contract. -func NewRegistryCaller(address common.Address, caller bind.ContractCaller) (*RegistryCaller, error) { - contract, err := bindRegistry(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &RegistryCaller{contract: contract}, nil -} - -// NewRegistryTransactor creates a new write-only instance of Registry, bound to a specific deployed contract. -func NewRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*RegistryTransactor, error) { - contract, err := bindRegistry(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &RegistryTransactor{contract: contract}, nil -} - -// NewRegistryFilterer creates a new log filterer instance of Registry, bound to a specific deployed contract. -func NewRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*RegistryFilterer, error) { - contract, err := bindRegistry(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &RegistryFilterer{contract: contract}, nil -} - -// bindRegistry binds a generic wrapper to an already deployed contract. -func bindRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := RegistryMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_Registry *RegistryRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _Registry.Contract.RegistryCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_Registry *RegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Registry.Contract.RegistryTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_Registry *RegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Registry.Contract.RegistryTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_Registry *RegistryCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _Registry.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_Registry *RegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Registry.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_Registry *RegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Registry.Contract.contract.Transact(opts, method, params...) -} - -// GetAftermarketDeviceAddressById is a free data retrieval call binding the contract method 0x682a25e3. -// -// Solidity: function getAftermarketDeviceAddressById(uint256 nodeId) view returns(address addr) -func (_Registry *RegistryCaller) GetAftermarketDeviceAddressById(opts *bind.CallOpts, nodeId *big.Int) (common.Address, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getAftermarketDeviceAddressById", nodeId) - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// GetAftermarketDeviceAddressById is a free data retrieval call binding the contract method 0x682a25e3. -// -// Solidity: function getAftermarketDeviceAddressById(uint256 nodeId) view returns(address addr) -func (_Registry *RegistrySession) GetAftermarketDeviceAddressById(nodeId *big.Int) (common.Address, error) { - return _Registry.Contract.GetAftermarketDeviceAddressById(&_Registry.CallOpts, nodeId) -} - -// GetAftermarketDeviceAddressById is a free data retrieval call binding the contract method 0x682a25e3. -// -// Solidity: function getAftermarketDeviceAddressById(uint256 nodeId) view returns(address addr) -func (_Registry *RegistryCallerSession) GetAftermarketDeviceAddressById(nodeId *big.Int) (common.Address, error) { - return _Registry.Contract.GetAftermarketDeviceAddressById(&_Registry.CallOpts, nodeId) -} - -// GetAftermarketDeviceIdByAddress is a free data retrieval call binding the contract method 0x9796cf22. -// -// Solidity: function getAftermarketDeviceIdByAddress(address addr) view returns(uint256 nodeId) -func (_Registry *RegistryCaller) GetAftermarketDeviceIdByAddress(opts *bind.CallOpts, addr common.Address) (*big.Int, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getAftermarketDeviceIdByAddress", addr) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetAftermarketDeviceIdByAddress is a free data retrieval call binding the contract method 0x9796cf22. -// -// Solidity: function getAftermarketDeviceIdByAddress(address addr) view returns(uint256 nodeId) -func (_Registry *RegistrySession) GetAftermarketDeviceIdByAddress(addr common.Address) (*big.Int, error) { - return _Registry.Contract.GetAftermarketDeviceIdByAddress(&_Registry.CallOpts, addr) -} - -// GetAftermarketDeviceIdByAddress is a free data retrieval call binding the contract method 0x9796cf22. -// -// Solidity: function getAftermarketDeviceIdByAddress(address addr) view returns(uint256 nodeId) -func (_Registry *RegistryCallerSession) GetAftermarketDeviceIdByAddress(addr common.Address) (*big.Int, error) { - return _Registry.Contract.GetAftermarketDeviceIdByAddress(&_Registry.CallOpts, addr) -} - -// GetBeneficiary is a free data retrieval call binding the contract method 0x0a6cef46. -// -// Solidity: function getBeneficiary(address idProxyAddress, uint256 nodeId) view returns(address beneficiary) -func (_Registry *RegistryCaller) GetBeneficiary(opts *bind.CallOpts, idProxyAddress common.Address, nodeId *big.Int) (common.Address, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getBeneficiary", idProxyAddress, nodeId) - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// GetBeneficiary is a free data retrieval call binding the contract method 0x0a6cef46. -// -// Solidity: function getBeneficiary(address idProxyAddress, uint256 nodeId) view returns(address beneficiary) -func (_Registry *RegistrySession) GetBeneficiary(idProxyAddress common.Address, nodeId *big.Int) (common.Address, error) { - return _Registry.Contract.GetBeneficiary(&_Registry.CallOpts, idProxyAddress, nodeId) -} - -// GetBeneficiary is a free data retrieval call binding the contract method 0x0a6cef46. -// -// Solidity: function getBeneficiary(address idProxyAddress, uint256 nodeId) view returns(address beneficiary) -func (_Registry *RegistryCallerSession) GetBeneficiary(idProxyAddress common.Address, nodeId *big.Int) (common.Address, error) { - return _Registry.Contract.GetBeneficiary(&_Registry.CallOpts, idProxyAddress, nodeId) -} - -// GetDataURI is a free data retrieval call binding the contract method 0xbc60a6ba. -// -// Solidity: function getDataURI(address idProxyAddress, uint256 tokenId) view returns(string data) -func (_Registry *RegistryCaller) GetDataURI(opts *bind.CallOpts, idProxyAddress common.Address, tokenId *big.Int) (string, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getDataURI", idProxyAddress, tokenId) - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// GetDataURI is a free data retrieval call binding the contract method 0xbc60a6ba. -// -// Solidity: function getDataURI(address idProxyAddress, uint256 tokenId) view returns(string data) -func (_Registry *RegistrySession) GetDataURI(idProxyAddress common.Address, tokenId *big.Int) (string, error) { - return _Registry.Contract.GetDataURI(&_Registry.CallOpts, idProxyAddress, tokenId) -} - -// GetDataURI is a free data retrieval call binding the contract method 0xbc60a6ba. -// -// Solidity: function getDataURI(address idProxyAddress, uint256 tokenId) view returns(string data) -func (_Registry *RegistryCallerSession) GetDataURI(idProxyAddress common.Address, tokenId *big.Int) (string, error) { - return _Registry.Contract.GetDataURI(&_Registry.CallOpts, idProxyAddress, tokenId) -} - -// GetDcxOperationCost is a free data retrieval call binding the contract method 0xd25f5787. -// -// Solidity: function getDcxOperationCost(bytes32 operation) view returns(uint256 cost) -func (_Registry *RegistryCaller) GetDcxOperationCost(opts *bind.CallOpts, operation [32]byte) (*big.Int, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getDcxOperationCost", operation) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetDcxOperationCost is a free data retrieval call binding the contract method 0xd25f5787. -// -// Solidity: function getDcxOperationCost(bytes32 operation) view returns(uint256 cost) -func (_Registry *RegistrySession) GetDcxOperationCost(operation [32]byte) (*big.Int, error) { - return _Registry.Contract.GetDcxOperationCost(&_Registry.CallOpts, operation) -} - -// GetDcxOperationCost is a free data retrieval call binding the contract method 0xd25f5787. -// -// Solidity: function getDcxOperationCost(bytes32 operation) view returns(uint256 cost) -func (_Registry *RegistryCallerSession) GetDcxOperationCost(operation [32]byte) (*big.Int, error) { - return _Registry.Contract.GetDcxOperationCost(&_Registry.CallOpts, operation) -} - -// GetDeviceDefinitionIdByVehicleId is a free data retrieval call binding the contract method 0xb7bded95. -// -// Solidity: function getDeviceDefinitionIdByVehicleId(uint256 vehicleId) view returns(string ddId) -func (_Registry *RegistryCaller) GetDeviceDefinitionIdByVehicleId(opts *bind.CallOpts, vehicleId *big.Int) (string, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getDeviceDefinitionIdByVehicleId", vehicleId) - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// GetDeviceDefinitionIdByVehicleId is a free data retrieval call binding the contract method 0xb7bded95. -// -// Solidity: function getDeviceDefinitionIdByVehicleId(uint256 vehicleId) view returns(string ddId) -func (_Registry *RegistrySession) GetDeviceDefinitionIdByVehicleId(vehicleId *big.Int) (string, error) { - return _Registry.Contract.GetDeviceDefinitionIdByVehicleId(&_Registry.CallOpts, vehicleId) -} - -// GetDeviceDefinitionIdByVehicleId is a free data retrieval call binding the contract method 0xb7bded95. -// -// Solidity: function getDeviceDefinitionIdByVehicleId(uint256 vehicleId) view returns(string ddId) -func (_Registry *RegistryCallerSession) GetDeviceDefinitionIdByVehicleId(vehicleId *big.Int) (string, error) { - return _Registry.Contract.GetDeviceDefinitionIdByVehicleId(&_Registry.CallOpts, vehicleId) -} - -// GetDeviceDefinitionTableId is a free data retrieval call binding the contract method 0x396e5987. -// -// Solidity: function getDeviceDefinitionTableId(uint256 manufacturerId) view returns(uint256 tableId) -func (_Registry *RegistryCaller) GetDeviceDefinitionTableId(opts *bind.CallOpts, manufacturerId *big.Int) (*big.Int, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getDeviceDefinitionTableId", manufacturerId) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetDeviceDefinitionTableId is a free data retrieval call binding the contract method 0x396e5987. -// -// Solidity: function getDeviceDefinitionTableId(uint256 manufacturerId) view returns(uint256 tableId) -func (_Registry *RegistrySession) GetDeviceDefinitionTableId(manufacturerId *big.Int) (*big.Int, error) { - return _Registry.Contract.GetDeviceDefinitionTableId(&_Registry.CallOpts, manufacturerId) -} - -// GetDeviceDefinitionTableId is a free data retrieval call binding the contract method 0x396e5987. -// -// Solidity: function getDeviceDefinitionTableId(uint256 manufacturerId) view returns(uint256 tableId) -func (_Registry *RegistryCallerSession) GetDeviceDefinitionTableId(manufacturerId *big.Int) (*big.Int, error) { - return _Registry.Contract.GetDeviceDefinitionTableId(&_Registry.CallOpts, manufacturerId) -} - -// GetDeviceDefinitionTableName is a free data retrieval call binding the contract method 0xa1d17941. -// -// Solidity: function getDeviceDefinitionTableName(uint256 manufacturerId) view returns(string tableName) -func (_Registry *RegistryCaller) GetDeviceDefinitionTableName(opts *bind.CallOpts, manufacturerId *big.Int) (string, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getDeviceDefinitionTableName", manufacturerId) - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// GetDeviceDefinitionTableName is a free data retrieval call binding the contract method 0xa1d17941. -// -// Solidity: function getDeviceDefinitionTableName(uint256 manufacturerId) view returns(string tableName) -func (_Registry *RegistrySession) GetDeviceDefinitionTableName(manufacturerId *big.Int) (string, error) { - return _Registry.Contract.GetDeviceDefinitionTableName(&_Registry.CallOpts, manufacturerId) -} - -// GetDeviceDefinitionTableName is a free data retrieval call binding the contract method 0xa1d17941. -// -// Solidity: function getDeviceDefinitionTableName(uint256 manufacturerId) view returns(string tableName) -func (_Registry *RegistryCallerSession) GetDeviceDefinitionTableName(manufacturerId *big.Int) (string, error) { - return _Registry.Contract.GetDeviceDefinitionTableName(&_Registry.CallOpts, manufacturerId) -} - -// GetDimoCredit is a free data retrieval call binding the contract method 0xcfe55b7d. -// -// Solidity: function getDimoCredit() view returns(address dimoCredit) -func (_Registry *RegistryCaller) GetDimoCredit(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getDimoCredit") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// GetDimoCredit is a free data retrieval call binding the contract method 0xcfe55b7d. -// -// Solidity: function getDimoCredit() view returns(address dimoCredit) -func (_Registry *RegistrySession) GetDimoCredit() (common.Address, error) { - return _Registry.Contract.GetDimoCredit(&_Registry.CallOpts) -} - -// GetDimoCredit is a free data retrieval call binding the contract method 0xcfe55b7d. -// -// Solidity: function getDimoCredit() view returns(address dimoCredit) -func (_Registry *RegistryCallerSession) GetDimoCredit() (common.Address, error) { - return _Registry.Contract.GetDimoCredit(&_Registry.CallOpts) -} - -// GetDimoToken is a free data retrieval call binding the contract method 0x77898251. -// -// Solidity: function getDimoToken() view returns(address dimoToken) -func (_Registry *RegistryCaller) GetDimoToken(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getDimoToken") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// GetDimoToken is a free data retrieval call binding the contract method 0x77898251. -// -// Solidity: function getDimoToken() view returns(address dimoToken) -func (_Registry *RegistrySession) GetDimoToken() (common.Address, error) { - return _Registry.Contract.GetDimoToken(&_Registry.CallOpts) -} - -// GetDimoToken is a free data retrieval call binding the contract method 0x77898251. -// -// Solidity: function getDimoToken() view returns(address dimoToken) -func (_Registry *RegistryCallerSession) GetDimoToken() (common.Address, error) { - return _Registry.Contract.GetDimoToken(&_Registry.CallOpts) -} - -// GetFoundation is a free data retrieval call binding the contract method 0xa2bc6cdf. -// -// Solidity: function getFoundation() view returns(address foundation) -func (_Registry *RegistryCaller) GetFoundation(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getFoundation") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// GetFoundation is a free data retrieval call binding the contract method 0xa2bc6cdf. -// -// Solidity: function getFoundation() view returns(address foundation) -func (_Registry *RegistrySession) GetFoundation() (common.Address, error) { - return _Registry.Contract.GetFoundation(&_Registry.CallOpts) -} - -// GetFoundation is a free data retrieval call binding the contract method 0xa2bc6cdf. -// -// Solidity: function getFoundation() view returns(address foundation) -func (_Registry *RegistryCallerSession) GetFoundation() (common.Address, error) { - return _Registry.Contract.GetFoundation(&_Registry.CallOpts) -} - -// GetInfo is a free data retrieval call binding the contract method 0xdce2f860. -// -// Solidity: function getInfo(address idProxyAddress, uint256 tokenId, string attribute) view returns(string info) -func (_Registry *RegistryCaller) GetInfo(opts *bind.CallOpts, idProxyAddress common.Address, tokenId *big.Int, attribute string) (string, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getInfo", idProxyAddress, tokenId, attribute) - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// GetInfo is a free data retrieval call binding the contract method 0xdce2f860. -// -// Solidity: function getInfo(address idProxyAddress, uint256 tokenId, string attribute) view returns(string info) -func (_Registry *RegistrySession) GetInfo(idProxyAddress common.Address, tokenId *big.Int, attribute string) (string, error) { - return _Registry.Contract.GetInfo(&_Registry.CallOpts, idProxyAddress, tokenId, attribute) -} - -// GetInfo is a free data retrieval call binding the contract method 0xdce2f860. -// -// Solidity: function getInfo(address idProxyAddress, uint256 tokenId, string attribute) view returns(string info) -func (_Registry *RegistryCallerSession) GetInfo(idProxyAddress common.Address, tokenId *big.Int, attribute string) (string, error) { - return _Registry.Contract.GetInfo(&_Registry.CallOpts, idProxyAddress, tokenId, attribute) -} - -// GetIntegrationIdByName is a free data retrieval call binding the contract method 0x714b7cfb. -// -// Solidity: function getIntegrationIdByName(string name) view returns(uint256 nodeId) -func (_Registry *RegistryCaller) GetIntegrationIdByName(opts *bind.CallOpts, name string) (*big.Int, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getIntegrationIdByName", name) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetIntegrationIdByName is a free data retrieval call binding the contract method 0x714b7cfb. -// -// Solidity: function getIntegrationIdByName(string name) view returns(uint256 nodeId) -func (_Registry *RegistrySession) GetIntegrationIdByName(name string) (*big.Int, error) { - return _Registry.Contract.GetIntegrationIdByName(&_Registry.CallOpts, name) -} - -// GetIntegrationIdByName is a free data retrieval call binding the contract method 0x714b7cfb. -// -// Solidity: function getIntegrationIdByName(string name) view returns(uint256 nodeId) -func (_Registry *RegistryCallerSession) GetIntegrationIdByName(name string) (*big.Int, error) { - return _Registry.Contract.GetIntegrationIdByName(&_Registry.CallOpts, name) -} - -// GetIntegrationNameById is a free data retrieval call binding the contract method 0x123141bd. -// -// Solidity: function getIntegrationNameById(uint256 tokenId) view returns(string name) -func (_Registry *RegistryCaller) GetIntegrationNameById(opts *bind.CallOpts, tokenId *big.Int) (string, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getIntegrationNameById", tokenId) - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// GetIntegrationNameById is a free data retrieval call binding the contract method 0x123141bd. -// -// Solidity: function getIntegrationNameById(uint256 tokenId) view returns(string name) -func (_Registry *RegistrySession) GetIntegrationNameById(tokenId *big.Int) (string, error) { - return _Registry.Contract.GetIntegrationNameById(&_Registry.CallOpts, tokenId) -} - -// GetIntegrationNameById is a free data retrieval call binding the contract method 0x123141bd. -// -// Solidity: function getIntegrationNameById(uint256 tokenId) view returns(string name) -func (_Registry *RegistryCallerSession) GetIntegrationNameById(tokenId *big.Int) (string, error) { - return _Registry.Contract.GetIntegrationNameById(&_Registry.CallOpts, tokenId) -} - -// GetLink is a free data retrieval call binding the contract method 0x112e62a2. -// -// Solidity: function getLink(address idProxyAddress, uint256 sourceNode) view returns(uint256 targetNode) -func (_Registry *RegistryCaller) GetLink(opts *bind.CallOpts, idProxyAddress common.Address, sourceNode *big.Int) (*big.Int, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getLink", idProxyAddress, sourceNode) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetLink is a free data retrieval call binding the contract method 0x112e62a2. -// -// Solidity: function getLink(address idProxyAddress, uint256 sourceNode) view returns(uint256 targetNode) -func (_Registry *RegistrySession) GetLink(idProxyAddress common.Address, sourceNode *big.Int) (*big.Int, error) { - return _Registry.Contract.GetLink(&_Registry.CallOpts, idProxyAddress, sourceNode) -} - -// GetLink is a free data retrieval call binding the contract method 0x112e62a2. -// -// Solidity: function getLink(address idProxyAddress, uint256 sourceNode) view returns(uint256 targetNode) -func (_Registry *RegistryCallerSession) GetLink(idProxyAddress common.Address, sourceNode *big.Int) (*big.Int, error) { - return _Registry.Contract.GetLink(&_Registry.CallOpts, idProxyAddress, sourceNode) -} - -// GetManufacturerIdByName is a free data retrieval call binding the contract method 0xce55aab0. -// -// Solidity: function getManufacturerIdByName(string name) view returns(uint256 nodeId) -func (_Registry *RegistryCaller) GetManufacturerIdByName(opts *bind.CallOpts, name string) (*big.Int, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getManufacturerIdByName", name) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetManufacturerIdByName is a free data retrieval call binding the contract method 0xce55aab0. -// -// Solidity: function getManufacturerIdByName(string name) view returns(uint256 nodeId) -func (_Registry *RegistrySession) GetManufacturerIdByName(name string) (*big.Int, error) { - return _Registry.Contract.GetManufacturerIdByName(&_Registry.CallOpts, name) -} - -// GetManufacturerIdByName is a free data retrieval call binding the contract method 0xce55aab0. -// -// Solidity: function getManufacturerIdByName(string name) view returns(uint256 nodeId) -func (_Registry *RegistryCallerSession) GetManufacturerIdByName(name string) (*big.Int, error) { - return _Registry.Contract.GetManufacturerIdByName(&_Registry.CallOpts, name) -} - -// GetManufacturerLicense is a free data retrieval call binding the contract method 0x170e4293. -// -// Solidity: function getManufacturerLicense() view returns(address manufacturerLicense) -func (_Registry *RegistryCaller) GetManufacturerLicense(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getManufacturerLicense") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// GetManufacturerLicense is a free data retrieval call binding the contract method 0x170e4293. -// -// Solidity: function getManufacturerLicense() view returns(address manufacturerLicense) -func (_Registry *RegistrySession) GetManufacturerLicense() (common.Address, error) { - return _Registry.Contract.GetManufacturerLicense(&_Registry.CallOpts) -} - -// GetManufacturerLicense is a free data retrieval call binding the contract method 0x170e4293. -// -// Solidity: function getManufacturerLicense() view returns(address manufacturerLicense) -func (_Registry *RegistryCallerSession) GetManufacturerLicense() (common.Address, error) { - return _Registry.Contract.GetManufacturerLicense(&_Registry.CallOpts) -} - -// GetManufacturerNameById is a free data retrieval call binding the contract method 0x9109b30b. -// -// Solidity: function getManufacturerNameById(uint256 tokenId) view returns(string name) -func (_Registry *RegistryCaller) GetManufacturerNameById(opts *bind.CallOpts, tokenId *big.Int) (string, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getManufacturerNameById", tokenId) - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// GetManufacturerNameById is a free data retrieval call binding the contract method 0x9109b30b. -// -// Solidity: function getManufacturerNameById(uint256 tokenId) view returns(string name) -func (_Registry *RegistrySession) GetManufacturerNameById(tokenId *big.Int) (string, error) { - return _Registry.Contract.GetManufacturerNameById(&_Registry.CallOpts, tokenId) -} - -// GetManufacturerNameById is a free data retrieval call binding the contract method 0x9109b30b. -// -// Solidity: function getManufacturerNameById(uint256 tokenId) view returns(string name) -func (_Registry *RegistryCallerSession) GetManufacturerNameById(tokenId *big.Int) (string, error) { - return _Registry.Contract.GetManufacturerNameById(&_Registry.CallOpts, tokenId) -} - -// GetNodeLink is a free data retrieval call binding the contract method 0xbd2b5568. -// -// Solidity: function getNodeLink(address idProxyAddressSource, address idProxyAddressTarget, uint256 sourceNode) view returns(uint256 targetNode) -func (_Registry *RegistryCaller) GetNodeLink(opts *bind.CallOpts, idProxyAddressSource common.Address, idProxyAddressTarget common.Address, sourceNode *big.Int) (*big.Int, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getNodeLink", idProxyAddressSource, idProxyAddressTarget, sourceNode) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetNodeLink is a free data retrieval call binding the contract method 0xbd2b5568. -// -// Solidity: function getNodeLink(address idProxyAddressSource, address idProxyAddressTarget, uint256 sourceNode) view returns(uint256 targetNode) -func (_Registry *RegistrySession) GetNodeLink(idProxyAddressSource common.Address, idProxyAddressTarget common.Address, sourceNode *big.Int) (*big.Int, error) { - return _Registry.Contract.GetNodeLink(&_Registry.CallOpts, idProxyAddressSource, idProxyAddressTarget, sourceNode) -} - -// GetNodeLink is a free data retrieval call binding the contract method 0xbd2b5568. -// -// Solidity: function getNodeLink(address idProxyAddressSource, address idProxyAddressTarget, uint256 sourceNode) view returns(uint256 targetNode) -func (_Registry *RegistryCallerSession) GetNodeLink(idProxyAddressSource common.Address, idProxyAddressTarget common.Address, sourceNode *big.Int) (*big.Int, error) { - return _Registry.Contract.GetNodeLink(&_Registry.CallOpts, idProxyAddressSource, idProxyAddressTarget, sourceNode) -} - -// GetParentNode is a free data retrieval call binding the contract method 0x82087d24. -// -// Solidity: function getParentNode(address idProxyAddress, uint256 tokenId) view returns(uint256 parentNode) -func (_Registry *RegistryCaller) GetParentNode(opts *bind.CallOpts, idProxyAddress common.Address, tokenId *big.Int) (*big.Int, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getParentNode", idProxyAddress, tokenId) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetParentNode is a free data retrieval call binding the contract method 0x82087d24. -// -// Solidity: function getParentNode(address idProxyAddress, uint256 tokenId) view returns(uint256 parentNode) -func (_Registry *RegistrySession) GetParentNode(idProxyAddress common.Address, tokenId *big.Int) (*big.Int, error) { - return _Registry.Contract.GetParentNode(&_Registry.CallOpts, idProxyAddress, tokenId) -} - -// GetParentNode is a free data retrieval call binding the contract method 0x82087d24. -// -// Solidity: function getParentNode(address idProxyAddress, uint256 tokenId) view returns(uint256 parentNode) -func (_Registry *RegistryCallerSession) GetParentNode(idProxyAddress common.Address, tokenId *big.Int) (*big.Int, error) { - return _Registry.Contract.GetParentNode(&_Registry.CallOpts, idProxyAddress, tokenId) -} - -// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. -// -// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) -func (_Registry *RegistryCaller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getRoleAdmin", role) - - if err != nil { - return *new([32]byte), err - } - - out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) - - return out0, err - -} - -// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. -// -// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) -func (_Registry *RegistrySession) GetRoleAdmin(role [32]byte) ([32]byte, error) { - return _Registry.Contract.GetRoleAdmin(&_Registry.CallOpts, role) -} - -// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. -// -// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) -func (_Registry *RegistryCallerSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { - return _Registry.Contract.GetRoleAdmin(&_Registry.CallOpts, role) -} - -// GetSyntheticDeviceAddressById is a free data retrieval call binding the contract method 0x493b27e1. -// -// Solidity: function getSyntheticDeviceAddressById(uint256 nodeId) view returns(address addr) -func (_Registry *RegistryCaller) GetSyntheticDeviceAddressById(opts *bind.CallOpts, nodeId *big.Int) (common.Address, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getSyntheticDeviceAddressById", nodeId) - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// GetSyntheticDeviceAddressById is a free data retrieval call binding the contract method 0x493b27e1. -// -// Solidity: function getSyntheticDeviceAddressById(uint256 nodeId) view returns(address addr) -func (_Registry *RegistrySession) GetSyntheticDeviceAddressById(nodeId *big.Int) (common.Address, error) { - return _Registry.Contract.GetSyntheticDeviceAddressById(&_Registry.CallOpts, nodeId) -} - -// GetSyntheticDeviceAddressById is a free data retrieval call binding the contract method 0x493b27e1. -// -// Solidity: function getSyntheticDeviceAddressById(uint256 nodeId) view returns(address addr) -func (_Registry *RegistryCallerSession) GetSyntheticDeviceAddressById(nodeId *big.Int) (common.Address, error) { - return _Registry.Contract.GetSyntheticDeviceAddressById(&_Registry.CallOpts, nodeId) -} - -// GetSyntheticDeviceIdByAddress is a free data retrieval call binding the contract method 0x795b910a. -// -// Solidity: function getSyntheticDeviceIdByAddress(address addr) view returns(uint256 nodeId) -func (_Registry *RegistryCaller) GetSyntheticDeviceIdByAddress(opts *bind.CallOpts, addr common.Address) (*big.Int, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getSyntheticDeviceIdByAddress", addr) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetSyntheticDeviceIdByAddress is a free data retrieval call binding the contract method 0x795b910a. -// -// Solidity: function getSyntheticDeviceIdByAddress(address addr) view returns(uint256 nodeId) -func (_Registry *RegistrySession) GetSyntheticDeviceIdByAddress(addr common.Address) (*big.Int, error) { - return _Registry.Contract.GetSyntheticDeviceIdByAddress(&_Registry.CallOpts, addr) -} - -// GetSyntheticDeviceIdByAddress is a free data retrieval call binding the contract method 0x795b910a. -// -// Solidity: function getSyntheticDeviceIdByAddress(address addr) view returns(uint256 nodeId) -func (_Registry *RegistryCallerSession) GetSyntheticDeviceIdByAddress(addr common.Address) (*big.Int, error) { - return _Registry.Contract.GetSyntheticDeviceIdByAddress(&_Registry.CallOpts, addr) -} - -// GetVehicleStream is a free data retrieval call binding the contract method 0x180e469a. -// -// Solidity: function getVehicleStream(uint256 vehicleId) view returns(string streamId) -func (_Registry *RegistryCaller) GetVehicleStream(opts *bind.CallOpts, vehicleId *big.Int) (string, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "getVehicleStream", vehicleId) - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// GetVehicleStream is a free data retrieval call binding the contract method 0x180e469a. -// -// Solidity: function getVehicleStream(uint256 vehicleId) view returns(string streamId) -func (_Registry *RegistrySession) GetVehicleStream(vehicleId *big.Int) (string, error) { - return _Registry.Contract.GetVehicleStream(&_Registry.CallOpts, vehicleId) -} - -// GetVehicleStream is a free data retrieval call binding the contract method 0x180e469a. -// -// Solidity: function getVehicleStream(uint256 vehicleId) view returns(string streamId) -func (_Registry *RegistryCallerSession) GetVehicleStream(vehicleId *big.Int) (string, error) { - return _Registry.Contract.GetVehicleStream(&_Registry.CallOpts, vehicleId) -} - -// HasRole is a free data retrieval call binding the contract method 0x91d14854. -// -// Solidity: function hasRole(bytes32 role, address account) view returns(bool) -func (_Registry *RegistryCaller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "hasRole", role, account) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// HasRole is a free data retrieval call binding the contract method 0x91d14854. -// -// Solidity: function hasRole(bytes32 role, address account) view returns(bool) -func (_Registry *RegistrySession) HasRole(role [32]byte, account common.Address) (bool, error) { - return _Registry.Contract.HasRole(&_Registry.CallOpts, role, account) -} - -// HasRole is a free data retrieval call binding the contract method 0x91d14854. -// -// Solidity: function hasRole(bytes32 role, address account) view returns(bool) -func (_Registry *RegistryCallerSession) HasRole(role [32]byte, account common.Address) (bool, error) { - return _Registry.Contract.HasRole(&_Registry.CallOpts, role, account) -} - -// IsAftermarketDeviceClaimed is a free data retrieval call binding the contract method 0xc6b36f2a. -// -// Solidity: function isAftermarketDeviceClaimed(uint256 nodeId) view returns(bool isClaimed) -func (_Registry *RegistryCaller) IsAftermarketDeviceClaimed(opts *bind.CallOpts, nodeId *big.Int) (bool, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "isAftermarketDeviceClaimed", nodeId) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsAftermarketDeviceClaimed is a free data retrieval call binding the contract method 0xc6b36f2a. -// -// Solidity: function isAftermarketDeviceClaimed(uint256 nodeId) view returns(bool isClaimed) -func (_Registry *RegistrySession) IsAftermarketDeviceClaimed(nodeId *big.Int) (bool, error) { - return _Registry.Contract.IsAftermarketDeviceClaimed(&_Registry.CallOpts, nodeId) -} - -// IsAftermarketDeviceClaimed is a free data retrieval call binding the contract method 0xc6b36f2a. -// -// Solidity: function isAftermarketDeviceClaimed(uint256 nodeId) view returns(bool isClaimed) -func (_Registry *RegistryCallerSession) IsAftermarketDeviceClaimed(nodeId *big.Int) (bool, error) { - return _Registry.Contract.IsAftermarketDeviceClaimed(&_Registry.CallOpts, nodeId) -} - -// IsAllowedToOwnIntegrationNode is a free data retrieval call binding the contract method 0xbc8002f0. -// -// Solidity: function isAllowedToOwnIntegrationNode(address addr) view returns(bool _isAllowed) -func (_Registry *RegistryCaller) IsAllowedToOwnIntegrationNode(opts *bind.CallOpts, addr common.Address) (bool, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "isAllowedToOwnIntegrationNode", addr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsAllowedToOwnIntegrationNode is a free data retrieval call binding the contract method 0xbc8002f0. -// -// Solidity: function isAllowedToOwnIntegrationNode(address addr) view returns(bool _isAllowed) -func (_Registry *RegistrySession) IsAllowedToOwnIntegrationNode(addr common.Address) (bool, error) { - return _Registry.Contract.IsAllowedToOwnIntegrationNode(&_Registry.CallOpts, addr) -} - -// IsAllowedToOwnIntegrationNode is a free data retrieval call binding the contract method 0xbc8002f0. -// -// Solidity: function isAllowedToOwnIntegrationNode(address addr) view returns(bool _isAllowed) -func (_Registry *RegistryCallerSession) IsAllowedToOwnIntegrationNode(addr common.Address) (bool, error) { - return _Registry.Contract.IsAllowedToOwnIntegrationNode(&_Registry.CallOpts, addr) -} - -// IsAllowedToOwnManufacturerNode is a free data retrieval call binding the contract method 0xd9c27c40. -// -// Solidity: function isAllowedToOwnManufacturerNode(address addr) view returns(bool _isAllowed) -func (_Registry *RegistryCaller) IsAllowedToOwnManufacturerNode(opts *bind.CallOpts, addr common.Address) (bool, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "isAllowedToOwnManufacturerNode", addr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsAllowedToOwnManufacturerNode is a free data retrieval call binding the contract method 0xd9c27c40. -// -// Solidity: function isAllowedToOwnManufacturerNode(address addr) view returns(bool _isAllowed) -func (_Registry *RegistrySession) IsAllowedToOwnManufacturerNode(addr common.Address) (bool, error) { - return _Registry.Contract.IsAllowedToOwnManufacturerNode(&_Registry.CallOpts, addr) -} - -// IsAllowedToOwnManufacturerNode is a free data retrieval call binding the contract method 0xd9c27c40. -// -// Solidity: function isAllowedToOwnManufacturerNode(address addr) view returns(bool _isAllowed) -func (_Registry *RegistryCallerSession) IsAllowedToOwnManufacturerNode(addr common.Address) (bool, error) { - return _Registry.Contract.IsAllowedToOwnManufacturerNode(&_Registry.CallOpts, addr) -} - -// IsController is a free data retrieval call binding the contract method 0xb429afeb. -// -// Solidity: function isController(address addr) view returns(bool _isController) -func (_Registry *RegistryCaller) IsController(opts *bind.CallOpts, addr common.Address) (bool, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "isController", addr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsController is a free data retrieval call binding the contract method 0xb429afeb. -// -// Solidity: function isController(address addr) view returns(bool _isController) -func (_Registry *RegistrySession) IsController(addr common.Address) (bool, error) { - return _Registry.Contract.IsController(&_Registry.CallOpts, addr) -} - -// IsController is a free data retrieval call binding the contract method 0xb429afeb. -// -// Solidity: function isController(address addr) view returns(bool _isController) -func (_Registry *RegistryCallerSession) IsController(addr common.Address) (bool, error) { - return _Registry.Contract.IsController(&_Registry.CallOpts, addr) -} - -// IsIntegrationController is a free data retrieval call binding the contract method 0xe21f68b7. -// -// Solidity: function isIntegrationController(address addr) view returns(bool _isController) -func (_Registry *RegistryCaller) IsIntegrationController(opts *bind.CallOpts, addr common.Address) (bool, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "isIntegrationController", addr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsIntegrationController is a free data retrieval call binding the contract method 0xe21f68b7. -// -// Solidity: function isIntegrationController(address addr) view returns(bool _isController) -func (_Registry *RegistrySession) IsIntegrationController(addr common.Address) (bool, error) { - return _Registry.Contract.IsIntegrationController(&_Registry.CallOpts, addr) -} - -// IsIntegrationController is a free data retrieval call binding the contract method 0xe21f68b7. -// -// Solidity: function isIntegrationController(address addr) view returns(bool _isController) -func (_Registry *RegistryCallerSession) IsIntegrationController(addr common.Address) (bool, error) { - return _Registry.Contract.IsIntegrationController(&_Registry.CallOpts, addr) -} - -// IsIntegrationMinted is a free data retrieval call binding the contract method 0x603dd1db. -// -// Solidity: function isIntegrationMinted(address addr) view returns(bool _isIntegrationMinted) -func (_Registry *RegistryCaller) IsIntegrationMinted(opts *bind.CallOpts, addr common.Address) (bool, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "isIntegrationMinted", addr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsIntegrationMinted is a free data retrieval call binding the contract method 0x603dd1db. -// -// Solidity: function isIntegrationMinted(address addr) view returns(bool _isIntegrationMinted) -func (_Registry *RegistrySession) IsIntegrationMinted(addr common.Address) (bool, error) { - return _Registry.Contract.IsIntegrationMinted(&_Registry.CallOpts, addr) -} - -// IsIntegrationMinted is a free data retrieval call binding the contract method 0x603dd1db. -// -// Solidity: function isIntegrationMinted(address addr) view returns(bool _isIntegrationMinted) -func (_Registry *RegistryCallerSession) IsIntegrationMinted(addr common.Address) (bool, error) { - return _Registry.Contract.IsIntegrationMinted(&_Registry.CallOpts, addr) -} - -// IsManufacturerMinted is a free data retrieval call binding the contract method 0x456bf169. -// -// Solidity: function isManufacturerMinted(address addr) view returns(bool _isManufacturerMinted) -func (_Registry *RegistryCaller) IsManufacturerMinted(opts *bind.CallOpts, addr common.Address) (bool, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "isManufacturerMinted", addr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsManufacturerMinted is a free data retrieval call binding the contract method 0x456bf169. -// -// Solidity: function isManufacturerMinted(address addr) view returns(bool _isManufacturerMinted) -func (_Registry *RegistrySession) IsManufacturerMinted(addr common.Address) (bool, error) { - return _Registry.Contract.IsManufacturerMinted(&_Registry.CallOpts, addr) -} - -// IsManufacturerMinted is a free data retrieval call binding the contract method 0x456bf169. -// -// Solidity: function isManufacturerMinted(address addr) view returns(bool _isManufacturerMinted) -func (_Registry *RegistryCallerSession) IsManufacturerMinted(addr common.Address) (bool, error) { - return _Registry.Contract.IsManufacturerMinted(&_Registry.CallOpts, addr) -} - -// MultiStaticCall is a free data retrieval call binding the contract method 0x1c0c6e51. -// -// Solidity: function multiStaticCall(bytes[] data) view returns(bytes[] results) -func (_Registry *RegistryCaller) MultiStaticCall(opts *bind.CallOpts, data [][]byte) ([][]byte, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "multiStaticCall", data) - - if err != nil { - return *new([][]byte), err - } - - out0 := *abi.ConvertType(out[0], new([][]byte)).(*[][]byte) - - return out0, err - -} - -// MultiStaticCall is a free data retrieval call binding the contract method 0x1c0c6e51. -// -// Solidity: function multiStaticCall(bytes[] data) view returns(bytes[] results) -func (_Registry *RegistrySession) MultiStaticCall(data [][]byte) ([][]byte, error) { - return _Registry.Contract.MultiStaticCall(&_Registry.CallOpts, data) -} - -// MultiStaticCall is a free data retrieval call binding the contract method 0x1c0c6e51. -// -// Solidity: function multiStaticCall(bytes[] data) view returns(bytes[] results) -func (_Registry *RegistryCallerSession) MultiStaticCall(data [][]byte) ([][]byte, error) { - return _Registry.Contract.MultiStaticCall(&_Registry.CallOpts, data) -} - -// OnERC721Received is a free data retrieval call binding the contract method 0x150b7a02. -// -// Solidity: function onERC721Received(address , address , uint256 , bytes ) pure returns(bytes4) -func (_Registry *RegistryCaller) OnERC721Received(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address, arg2 *big.Int, arg3 []byte) ([4]byte, error) { - var out []interface{} - err := _Registry.contract.Call(opts, &out, "onERC721Received", arg0, arg1, arg2, arg3) - - if err != nil { - return *new([4]byte), err - } - - out0 := *abi.ConvertType(out[0], new([4]byte)).(*[4]byte) - - return out0, err - -} - -// OnERC721Received is a free data retrieval call binding the contract method 0x150b7a02. -// -// Solidity: function onERC721Received(address , address , uint256 , bytes ) pure returns(bytes4) -func (_Registry *RegistrySession) OnERC721Received(arg0 common.Address, arg1 common.Address, arg2 *big.Int, arg3 []byte) ([4]byte, error) { - return _Registry.Contract.OnERC721Received(&_Registry.CallOpts, arg0, arg1, arg2, arg3) -} - -// OnERC721Received is a free data retrieval call binding the contract method 0x150b7a02. -// -// Solidity: function onERC721Received(address , address , uint256 , bytes ) pure returns(bytes4) -func (_Registry *RegistryCallerSession) OnERC721Received(arg0 common.Address, arg1 common.Address, arg2 *big.Int, arg3 []byte) ([4]byte, error) { - return _Registry.Contract.OnERC721Received(&_Registry.CallOpts, arg0, arg1, arg2, arg3) -} - -// AddAftermarketDeviceAttribute is a paid mutator transaction binding the contract method 0x6111afa3. -// -// Solidity: function addAftermarketDeviceAttribute(string attribute) returns() -func (_Registry *RegistryTransactor) AddAftermarketDeviceAttribute(opts *bind.TransactOpts, attribute string) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "addAftermarketDeviceAttribute", attribute) -} - -// AddAftermarketDeviceAttribute is a paid mutator transaction binding the contract method 0x6111afa3. -// -// Solidity: function addAftermarketDeviceAttribute(string attribute) returns() -func (_Registry *RegistrySession) AddAftermarketDeviceAttribute(attribute string) (*types.Transaction, error) { - return _Registry.Contract.AddAftermarketDeviceAttribute(&_Registry.TransactOpts, attribute) -} - -// AddAftermarketDeviceAttribute is a paid mutator transaction binding the contract method 0x6111afa3. -// -// Solidity: function addAftermarketDeviceAttribute(string attribute) returns() -func (_Registry *RegistryTransactorSession) AddAftermarketDeviceAttribute(attribute string) (*types.Transaction, error) { - return _Registry.Contract.AddAftermarketDeviceAttribute(&_Registry.TransactOpts, attribute) -} - -// AddIntegrationAttribute is a paid mutator transaction binding the contract method 0x044d2498. -// -// Solidity: function addIntegrationAttribute(string attribute) returns() -func (_Registry *RegistryTransactor) AddIntegrationAttribute(opts *bind.TransactOpts, attribute string) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "addIntegrationAttribute", attribute) -} - -// AddIntegrationAttribute is a paid mutator transaction binding the contract method 0x044d2498. -// -// Solidity: function addIntegrationAttribute(string attribute) returns() -func (_Registry *RegistrySession) AddIntegrationAttribute(attribute string) (*types.Transaction, error) { - return _Registry.Contract.AddIntegrationAttribute(&_Registry.TransactOpts, attribute) -} - -// AddIntegrationAttribute is a paid mutator transaction binding the contract method 0x044d2498. -// -// Solidity: function addIntegrationAttribute(string attribute) returns() -func (_Registry *RegistryTransactorSession) AddIntegrationAttribute(attribute string) (*types.Transaction, error) { - return _Registry.Contract.AddIntegrationAttribute(&_Registry.TransactOpts, attribute) -} - -// AddManufacturerAttribute is a paid mutator transaction binding the contract method 0x50300a3f. -// -// Solidity: function addManufacturerAttribute(string attribute) returns() -func (_Registry *RegistryTransactor) AddManufacturerAttribute(opts *bind.TransactOpts, attribute string) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "addManufacturerAttribute", attribute) -} - -// AddManufacturerAttribute is a paid mutator transaction binding the contract method 0x50300a3f. -// -// Solidity: function addManufacturerAttribute(string attribute) returns() -func (_Registry *RegistrySession) AddManufacturerAttribute(attribute string) (*types.Transaction, error) { - return _Registry.Contract.AddManufacturerAttribute(&_Registry.TransactOpts, attribute) -} - -// AddManufacturerAttribute is a paid mutator transaction binding the contract method 0x50300a3f. -// -// Solidity: function addManufacturerAttribute(string attribute) returns() -func (_Registry *RegistryTransactorSession) AddManufacturerAttribute(attribute string) (*types.Transaction, error) { - return _Registry.Contract.AddManufacturerAttribute(&_Registry.TransactOpts, attribute) -} - -// AddModule is a paid mutator transaction binding the contract method 0x0df5b997. -// -// Solidity: function addModule(address implementation, bytes4[] selectors) returns() -func (_Registry *RegistryTransactor) AddModule(opts *bind.TransactOpts, implementation common.Address, selectors [][4]byte) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "addModule", implementation, selectors) -} - -// AddModule is a paid mutator transaction binding the contract method 0x0df5b997. -// -// Solidity: function addModule(address implementation, bytes4[] selectors) returns() -func (_Registry *RegistrySession) AddModule(implementation common.Address, selectors [][4]byte) (*types.Transaction, error) { - return _Registry.Contract.AddModule(&_Registry.TransactOpts, implementation, selectors) -} - -// AddModule is a paid mutator transaction binding the contract method 0x0df5b997. -// -// Solidity: function addModule(address implementation, bytes4[] selectors) returns() -func (_Registry *RegistryTransactorSession) AddModule(implementation common.Address, selectors [][4]byte) (*types.Transaction, error) { - return _Registry.Contract.AddModule(&_Registry.TransactOpts, implementation, selectors) -} - -// AddSyntheticDeviceAttribute is a paid mutator transaction binding the contract method 0xe1f371df. -// -// Solidity: function addSyntheticDeviceAttribute(string attribute) returns() -func (_Registry *RegistryTransactor) AddSyntheticDeviceAttribute(opts *bind.TransactOpts, attribute string) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "addSyntheticDeviceAttribute", attribute) -} - -// AddSyntheticDeviceAttribute is a paid mutator transaction binding the contract method 0xe1f371df. -// -// Solidity: function addSyntheticDeviceAttribute(string attribute) returns() -func (_Registry *RegistrySession) AddSyntheticDeviceAttribute(attribute string) (*types.Transaction, error) { - return _Registry.Contract.AddSyntheticDeviceAttribute(&_Registry.TransactOpts, attribute) -} - -// AddSyntheticDeviceAttribute is a paid mutator transaction binding the contract method 0xe1f371df. -// -// Solidity: function addSyntheticDeviceAttribute(string attribute) returns() -func (_Registry *RegistryTransactorSession) AddSyntheticDeviceAttribute(attribute string) (*types.Transaction, error) { - return _Registry.Contract.AddSyntheticDeviceAttribute(&_Registry.TransactOpts, attribute) -} - -// AddVehicleAttribute is a paid mutator transaction binding the contract method 0xf0d1a557. -// -// Solidity: function addVehicleAttribute(string attribute) returns() -func (_Registry *RegistryTransactor) AddVehicleAttribute(opts *bind.TransactOpts, attribute string) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "addVehicleAttribute", attribute) -} - -// AddVehicleAttribute is a paid mutator transaction binding the contract method 0xf0d1a557. -// -// Solidity: function addVehicleAttribute(string attribute) returns() -func (_Registry *RegistrySession) AddVehicleAttribute(attribute string) (*types.Transaction, error) { - return _Registry.Contract.AddVehicleAttribute(&_Registry.TransactOpts, attribute) -} - -// AddVehicleAttribute is a paid mutator transaction binding the contract method 0xf0d1a557. -// -// Solidity: function addVehicleAttribute(string attribute) returns() -func (_Registry *RegistryTransactorSession) AddVehicleAttribute(attribute string) (*types.Transaction, error) { - return _Registry.Contract.AddVehicleAttribute(&_Registry.TransactOpts, attribute) -} - -// AdminBurnAftermarketDevices is a paid mutator transaction binding the contract method 0xd7376bae. -// -// Solidity: function adminBurnAftermarketDevices(uint256[] tokenIds) returns() -func (_Registry *RegistryTransactor) AdminBurnAftermarketDevices(opts *bind.TransactOpts, tokenIds []*big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "adminBurnAftermarketDevices", tokenIds) -} - -// AdminBurnAftermarketDevices is a paid mutator transaction binding the contract method 0xd7376bae. -// -// Solidity: function adminBurnAftermarketDevices(uint256[] tokenIds) returns() -func (_Registry *RegistrySession) AdminBurnAftermarketDevices(tokenIds []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.AdminBurnAftermarketDevices(&_Registry.TransactOpts, tokenIds) -} - -// AdminBurnAftermarketDevices is a paid mutator transaction binding the contract method 0xd7376bae. -// -// Solidity: function adminBurnAftermarketDevices(uint256[] tokenIds) returns() -func (_Registry *RegistryTransactorSession) AdminBurnAftermarketDevices(tokenIds []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.AdminBurnAftermarketDevices(&_Registry.TransactOpts, tokenIds) -} - -// AdminBurnAftermarketDevicesAndDeletePairings is a paid mutator transaction binding the contract method 0x63dec203. -// -// Solidity: function adminBurnAftermarketDevicesAndDeletePairings(uint256[] tokenIds) returns() -func (_Registry *RegistryTransactor) AdminBurnAftermarketDevicesAndDeletePairings(opts *bind.TransactOpts, tokenIds []*big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "adminBurnAftermarketDevicesAndDeletePairings", tokenIds) -} - -// AdminBurnAftermarketDevicesAndDeletePairings is a paid mutator transaction binding the contract method 0x63dec203. -// -// Solidity: function adminBurnAftermarketDevicesAndDeletePairings(uint256[] tokenIds) returns() -func (_Registry *RegistrySession) AdminBurnAftermarketDevicesAndDeletePairings(tokenIds []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.AdminBurnAftermarketDevicesAndDeletePairings(&_Registry.TransactOpts, tokenIds) -} - -// AdminBurnAftermarketDevicesAndDeletePairings is a paid mutator transaction binding the contract method 0x63dec203. -// -// Solidity: function adminBurnAftermarketDevicesAndDeletePairings(uint256[] tokenIds) returns() -func (_Registry *RegistryTransactorSession) AdminBurnAftermarketDevicesAndDeletePairings(tokenIds []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.AdminBurnAftermarketDevicesAndDeletePairings(&_Registry.TransactOpts, tokenIds) -} - -// AdminBurnSyntheticDevicesAndDeletePairings is a paid mutator transaction binding the contract method 0x52878b61. -// -// Solidity: function adminBurnSyntheticDevicesAndDeletePairings(uint256[] tokenIds) returns() -func (_Registry *RegistryTransactor) AdminBurnSyntheticDevicesAndDeletePairings(opts *bind.TransactOpts, tokenIds []*big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "adminBurnSyntheticDevicesAndDeletePairings", tokenIds) -} - -// AdminBurnSyntheticDevicesAndDeletePairings is a paid mutator transaction binding the contract method 0x52878b61. -// -// Solidity: function adminBurnSyntheticDevicesAndDeletePairings(uint256[] tokenIds) returns() -func (_Registry *RegistrySession) AdminBurnSyntheticDevicesAndDeletePairings(tokenIds []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.AdminBurnSyntheticDevicesAndDeletePairings(&_Registry.TransactOpts, tokenIds) -} - -// AdminBurnSyntheticDevicesAndDeletePairings is a paid mutator transaction binding the contract method 0x52878b61. -// -// Solidity: function adminBurnSyntheticDevicesAndDeletePairings(uint256[] tokenIds) returns() -func (_Registry *RegistryTransactorSession) AdminBurnSyntheticDevicesAndDeletePairings(tokenIds []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.AdminBurnSyntheticDevicesAndDeletePairings(&_Registry.TransactOpts, tokenIds) -} - -// AdminBurnVehicles is a paid mutator transaction binding the contract method 0x282eb387. -// -// Solidity: function adminBurnVehicles(uint256[] tokenIds) returns() -func (_Registry *RegistryTransactor) AdminBurnVehicles(opts *bind.TransactOpts, tokenIds []*big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "adminBurnVehicles", tokenIds) -} - -// AdminBurnVehicles is a paid mutator transaction binding the contract method 0x282eb387. -// -// Solidity: function adminBurnVehicles(uint256[] tokenIds) returns() -func (_Registry *RegistrySession) AdminBurnVehicles(tokenIds []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.AdminBurnVehicles(&_Registry.TransactOpts, tokenIds) -} - -// AdminBurnVehicles is a paid mutator transaction binding the contract method 0x282eb387. -// -// Solidity: function adminBurnVehicles(uint256[] tokenIds) returns() -func (_Registry *RegistryTransactorSession) AdminBurnVehicles(tokenIds []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.AdminBurnVehicles(&_Registry.TransactOpts, tokenIds) -} - -// AdminBurnVehiclesAndDeletePairings is a paid mutator transaction binding the contract method 0x11d679c9. -// -// Solidity: function adminBurnVehiclesAndDeletePairings(uint256[] tokenIds) returns() -func (_Registry *RegistryTransactor) AdminBurnVehiclesAndDeletePairings(opts *bind.TransactOpts, tokenIds []*big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "adminBurnVehiclesAndDeletePairings", tokenIds) -} - -// AdminBurnVehiclesAndDeletePairings is a paid mutator transaction binding the contract method 0x11d679c9. -// -// Solidity: function adminBurnVehiclesAndDeletePairings(uint256[] tokenIds) returns() -func (_Registry *RegistrySession) AdminBurnVehiclesAndDeletePairings(tokenIds []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.AdminBurnVehiclesAndDeletePairings(&_Registry.TransactOpts, tokenIds) -} - -// AdminBurnVehiclesAndDeletePairings is a paid mutator transaction binding the contract method 0x11d679c9. -// -// Solidity: function adminBurnVehiclesAndDeletePairings(uint256[] tokenIds) returns() -func (_Registry *RegistryTransactorSession) AdminBurnVehiclesAndDeletePairings(tokenIds []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.AdminBurnVehiclesAndDeletePairings(&_Registry.TransactOpts, tokenIds) -} - -// AdminCacheDimoStreamrEns is a paid mutator transaction binding the contract method 0xb17b974b. -// -// Solidity: function adminCacheDimoStreamrEns() returns() -func (_Registry *RegistryTransactor) AdminCacheDimoStreamrEns(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "adminCacheDimoStreamrEns") -} - -// AdminCacheDimoStreamrEns is a paid mutator transaction binding the contract method 0xb17b974b. -// -// Solidity: function adminCacheDimoStreamrEns() returns() -func (_Registry *RegistrySession) AdminCacheDimoStreamrEns() (*types.Transaction, error) { - return _Registry.Contract.AdminCacheDimoStreamrEns(&_Registry.TransactOpts) -} - -// AdminCacheDimoStreamrEns is a paid mutator transaction binding the contract method 0xb17b974b. -// -// Solidity: function adminCacheDimoStreamrEns() returns() -func (_Registry *RegistryTransactorSession) AdminCacheDimoStreamrEns() (*types.Transaction, error) { - return _Registry.Contract.AdminCacheDimoStreamrEns(&_Registry.TransactOpts) -} - -// AdminChangeParentNode is a paid mutator transaction binding the contract method 0x56936962. -// -// Solidity: function adminChangeParentNode(uint256 newParentNode, address idProxyAddress, uint256[] nodeIdList) returns() -func (_Registry *RegistryTransactor) AdminChangeParentNode(opts *bind.TransactOpts, newParentNode *big.Int, idProxyAddress common.Address, nodeIdList []*big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "adminChangeParentNode", newParentNode, idProxyAddress, nodeIdList) -} - -// AdminChangeParentNode is a paid mutator transaction binding the contract method 0x56936962. -// -// Solidity: function adminChangeParentNode(uint256 newParentNode, address idProxyAddress, uint256[] nodeIdList) returns() -func (_Registry *RegistrySession) AdminChangeParentNode(newParentNode *big.Int, idProxyAddress common.Address, nodeIdList []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.AdminChangeParentNode(&_Registry.TransactOpts, newParentNode, idProxyAddress, nodeIdList) -} - -// AdminChangeParentNode is a paid mutator transaction binding the contract method 0x56936962. -// -// Solidity: function adminChangeParentNode(uint256 newParentNode, address idProxyAddress, uint256[] nodeIdList) returns() -func (_Registry *RegistryTransactorSession) AdminChangeParentNode(newParentNode *big.Int, idProxyAddress common.Address, nodeIdList []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.AdminChangeParentNode(&_Registry.TransactOpts, newParentNode, idProxyAddress, nodeIdList) -} - -// AdminPairAftermarketDevice is a paid mutator transaction binding the contract method 0x3febacab. -// -// Solidity: function adminPairAftermarketDevice(uint256 aftermarketDeviceNode, uint256 vehicleNode) returns() -func (_Registry *RegistryTransactor) AdminPairAftermarketDevice(opts *bind.TransactOpts, aftermarketDeviceNode *big.Int, vehicleNode *big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "adminPairAftermarketDevice", aftermarketDeviceNode, vehicleNode) -} - -// AdminPairAftermarketDevice is a paid mutator transaction binding the contract method 0x3febacab. -// -// Solidity: function adminPairAftermarketDevice(uint256 aftermarketDeviceNode, uint256 vehicleNode) returns() -func (_Registry *RegistrySession) AdminPairAftermarketDevice(aftermarketDeviceNode *big.Int, vehicleNode *big.Int) (*types.Transaction, error) { - return _Registry.Contract.AdminPairAftermarketDevice(&_Registry.TransactOpts, aftermarketDeviceNode, vehicleNode) -} - -// AdminPairAftermarketDevice is a paid mutator transaction binding the contract method 0x3febacab. -// -// Solidity: function adminPairAftermarketDevice(uint256 aftermarketDeviceNode, uint256 vehicleNode) returns() -func (_Registry *RegistryTransactorSession) AdminPairAftermarketDevice(aftermarketDeviceNode *big.Int, vehicleNode *big.Int) (*types.Transaction, error) { - return _Registry.Contract.AdminPairAftermarketDevice(&_Registry.TransactOpts, aftermarketDeviceNode, vehicleNode) -} - -// AdminRemoveVehicleAttribute is a paid mutator transaction binding the contract method 0x5f741f4d. -// -// Solidity: function adminRemoveVehicleAttribute(string attribute) returns() -func (_Registry *RegistryTransactor) AdminRemoveVehicleAttribute(opts *bind.TransactOpts, attribute string) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "adminRemoveVehicleAttribute", attribute) -} - -// AdminRemoveVehicleAttribute is a paid mutator transaction binding the contract method 0x5f741f4d. -// -// Solidity: function adminRemoveVehicleAttribute(string attribute) returns() -func (_Registry *RegistrySession) AdminRemoveVehicleAttribute(attribute string) (*types.Transaction, error) { - return _Registry.Contract.AdminRemoveVehicleAttribute(&_Registry.TransactOpts, attribute) -} - -// AdminRemoveVehicleAttribute is a paid mutator transaction binding the contract method 0x5f741f4d. -// -// Solidity: function adminRemoveVehicleAttribute(string attribute) returns() -func (_Registry *RegistryTransactorSession) AdminRemoveVehicleAttribute(attribute string) (*types.Transaction, error) { - return _Registry.Contract.AdminRemoveVehicleAttribute(&_Registry.TransactOpts, attribute) -} - -// AdminSetVehicleDDs is a paid mutator transaction binding the contract method 0xdd60fd1a. -// -// Solidity: function adminSetVehicleDDs((uint256,string)[] vehicleIdDdId) returns() -func (_Registry *RegistryTransactor) AdminSetVehicleDDs(opts *bind.TransactOpts, vehicleIdDdId []DevAdminVehicleIdDeviceDefinitionId) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "adminSetVehicleDDs", vehicleIdDdId) -} - -// AdminSetVehicleDDs is a paid mutator transaction binding the contract method 0xdd60fd1a. -// -// Solidity: function adminSetVehicleDDs((uint256,string)[] vehicleIdDdId) returns() -func (_Registry *RegistrySession) AdminSetVehicleDDs(vehicleIdDdId []DevAdminVehicleIdDeviceDefinitionId) (*types.Transaction, error) { - return _Registry.Contract.AdminSetVehicleDDs(&_Registry.TransactOpts, vehicleIdDdId) -} - -// AdminSetVehicleDDs is a paid mutator transaction binding the contract method 0xdd60fd1a. -// -// Solidity: function adminSetVehicleDDs((uint256,string)[] vehicleIdDdId) returns() -func (_Registry *RegistryTransactorSession) AdminSetVehicleDDs(vehicleIdDdId []DevAdminVehicleIdDeviceDefinitionId) (*types.Transaction, error) { - return _Registry.Contract.AdminSetVehicleDDs(&_Registry.TransactOpts, vehicleIdDdId) -} - -// BurnSyntheticDeviceSign is a paid mutator transaction binding the contract method 0x7c7c9978. -// -// Solidity: function burnSyntheticDeviceSign(uint256 vehicleNode, uint256 syntheticDeviceNode, bytes ownerSig) returns() -func (_Registry *RegistryTransactor) BurnSyntheticDeviceSign(opts *bind.TransactOpts, vehicleNode *big.Int, syntheticDeviceNode *big.Int, ownerSig []byte) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "burnSyntheticDeviceSign", vehicleNode, syntheticDeviceNode, ownerSig) -} - -// BurnSyntheticDeviceSign is a paid mutator transaction binding the contract method 0x7c7c9978. -// -// Solidity: function burnSyntheticDeviceSign(uint256 vehicleNode, uint256 syntheticDeviceNode, bytes ownerSig) returns() -func (_Registry *RegistrySession) BurnSyntheticDeviceSign(vehicleNode *big.Int, syntheticDeviceNode *big.Int, ownerSig []byte) (*types.Transaction, error) { - return _Registry.Contract.BurnSyntheticDeviceSign(&_Registry.TransactOpts, vehicleNode, syntheticDeviceNode, ownerSig) -} - -// BurnSyntheticDeviceSign is a paid mutator transaction binding the contract method 0x7c7c9978. -// -// Solidity: function burnSyntheticDeviceSign(uint256 vehicleNode, uint256 syntheticDeviceNode, bytes ownerSig) returns() -func (_Registry *RegistryTransactorSession) BurnSyntheticDeviceSign(vehicleNode *big.Int, syntheticDeviceNode *big.Int, ownerSig []byte) (*types.Transaction, error) { - return _Registry.Contract.BurnSyntheticDeviceSign(&_Registry.TransactOpts, vehicleNode, syntheticDeviceNode, ownerSig) -} - -// BurnVehicleSign is a paid mutator transaction binding the contract method 0xd0b61156. -// -// Solidity: function burnVehicleSign(uint256 tokenId, bytes ownerSig) returns() -func (_Registry *RegistryTransactor) BurnVehicleSign(opts *bind.TransactOpts, tokenId *big.Int, ownerSig []byte) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "burnVehicleSign", tokenId, ownerSig) -} - -// BurnVehicleSign is a paid mutator transaction binding the contract method 0xd0b61156. -// -// Solidity: function burnVehicleSign(uint256 tokenId, bytes ownerSig) returns() -func (_Registry *RegistrySession) BurnVehicleSign(tokenId *big.Int, ownerSig []byte) (*types.Transaction, error) { - return _Registry.Contract.BurnVehicleSign(&_Registry.TransactOpts, tokenId, ownerSig) -} - -// BurnVehicleSign is a paid mutator transaction binding the contract method 0xd0b61156. -// -// Solidity: function burnVehicleSign(uint256 tokenId, bytes ownerSig) returns() -func (_Registry *RegistryTransactorSession) BurnVehicleSign(tokenId *big.Int, ownerSig []byte) (*types.Transaction, error) { - return _Registry.Contract.BurnVehicleSign(&_Registry.TransactOpts, tokenId, ownerSig) -} - -// ClaimAftermarketDeviceBatch is a paid mutator transaction binding the contract method 0xab2ae229. -// -// Solidity: function claimAftermarketDeviceBatch((uint256,address)[] adOwnerPair) returns() -func (_Registry *RegistryTransactor) ClaimAftermarketDeviceBatch(opts *bind.TransactOpts, adOwnerPair []AftermarketDeviceOwnerPair) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "claimAftermarketDeviceBatch", adOwnerPair) -} - -// ClaimAftermarketDeviceBatch is a paid mutator transaction binding the contract method 0xab2ae229. -// -// Solidity: function claimAftermarketDeviceBatch((uint256,address)[] adOwnerPair) returns() -func (_Registry *RegistrySession) ClaimAftermarketDeviceBatch(adOwnerPair []AftermarketDeviceOwnerPair) (*types.Transaction, error) { - return _Registry.Contract.ClaimAftermarketDeviceBatch(&_Registry.TransactOpts, adOwnerPair) -} - -// ClaimAftermarketDeviceBatch is a paid mutator transaction binding the contract method 0xab2ae229. -// -// Solidity: function claimAftermarketDeviceBatch((uint256,address)[] adOwnerPair) returns() -func (_Registry *RegistryTransactorSession) ClaimAftermarketDeviceBatch(adOwnerPair []AftermarketDeviceOwnerPair) (*types.Transaction, error) { - return _Registry.Contract.ClaimAftermarketDeviceBatch(&_Registry.TransactOpts, adOwnerPair) -} - -// ClaimAftermarketDeviceSign is a paid mutator transaction binding the contract method 0x89a841bb. -// -// Solidity: function claimAftermarketDeviceSign(uint256 aftermarketDeviceNode, address owner, bytes ownerSig, bytes aftermarketDeviceSig) returns() -func (_Registry *RegistryTransactor) ClaimAftermarketDeviceSign(opts *bind.TransactOpts, aftermarketDeviceNode *big.Int, owner common.Address, ownerSig []byte, aftermarketDeviceSig []byte) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "claimAftermarketDeviceSign", aftermarketDeviceNode, owner, ownerSig, aftermarketDeviceSig) -} - -// ClaimAftermarketDeviceSign is a paid mutator transaction binding the contract method 0x89a841bb. -// -// Solidity: function claimAftermarketDeviceSign(uint256 aftermarketDeviceNode, address owner, bytes ownerSig, bytes aftermarketDeviceSig) returns() -func (_Registry *RegistrySession) ClaimAftermarketDeviceSign(aftermarketDeviceNode *big.Int, owner common.Address, ownerSig []byte, aftermarketDeviceSig []byte) (*types.Transaction, error) { - return _Registry.Contract.ClaimAftermarketDeviceSign(&_Registry.TransactOpts, aftermarketDeviceNode, owner, ownerSig, aftermarketDeviceSig) -} - -// ClaimAftermarketDeviceSign is a paid mutator transaction binding the contract method 0x89a841bb. -// -// Solidity: function claimAftermarketDeviceSign(uint256 aftermarketDeviceNode, address owner, bytes ownerSig, bytes aftermarketDeviceSig) returns() -func (_Registry *RegistryTransactorSession) ClaimAftermarketDeviceSign(aftermarketDeviceNode *big.Int, owner common.Address, ownerSig []byte, aftermarketDeviceSig []byte) (*types.Transaction, error) { - return _Registry.Contract.ClaimAftermarketDeviceSign(&_Registry.TransactOpts, aftermarketDeviceNode, owner, ownerSig, aftermarketDeviceSig) -} - -// CreateDeviceDefinitionTable is a paid mutator transaction binding the contract method 0x20954d21. -// -// Solidity: function createDeviceDefinitionTable(address tableOwner, uint256 manufacturerId) returns() -func (_Registry *RegistryTransactor) CreateDeviceDefinitionTable(opts *bind.TransactOpts, tableOwner common.Address, manufacturerId *big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "createDeviceDefinitionTable", tableOwner, manufacturerId) -} - -// CreateDeviceDefinitionTable is a paid mutator transaction binding the contract method 0x20954d21. -// -// Solidity: function createDeviceDefinitionTable(address tableOwner, uint256 manufacturerId) returns() -func (_Registry *RegistrySession) CreateDeviceDefinitionTable(tableOwner common.Address, manufacturerId *big.Int) (*types.Transaction, error) { - return _Registry.Contract.CreateDeviceDefinitionTable(&_Registry.TransactOpts, tableOwner, manufacturerId) -} - -// CreateDeviceDefinitionTable is a paid mutator transaction binding the contract method 0x20954d21. -// -// Solidity: function createDeviceDefinitionTable(address tableOwner, uint256 manufacturerId) returns() -func (_Registry *RegistryTransactorSession) CreateDeviceDefinitionTable(tableOwner common.Address, manufacturerId *big.Int) (*types.Transaction, error) { - return _Registry.Contract.CreateDeviceDefinitionTable(&_Registry.TransactOpts, tableOwner, manufacturerId) -} - -// CreateDeviceDefinitionTableBatch is a paid mutator transaction binding the contract method 0x794c6790. -// -// Solidity: function createDeviceDefinitionTableBatch(address tableOwner, uint256[] manufacturerIds) returns() -func (_Registry *RegistryTransactor) CreateDeviceDefinitionTableBatch(opts *bind.TransactOpts, tableOwner common.Address, manufacturerIds []*big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "createDeviceDefinitionTableBatch", tableOwner, manufacturerIds) -} - -// CreateDeviceDefinitionTableBatch is a paid mutator transaction binding the contract method 0x794c6790. -// -// Solidity: function createDeviceDefinitionTableBatch(address tableOwner, uint256[] manufacturerIds) returns() -func (_Registry *RegistrySession) CreateDeviceDefinitionTableBatch(tableOwner common.Address, manufacturerIds []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.CreateDeviceDefinitionTableBatch(&_Registry.TransactOpts, tableOwner, manufacturerIds) -} - -// CreateDeviceDefinitionTableBatch is a paid mutator transaction binding the contract method 0x794c6790. -// -// Solidity: function createDeviceDefinitionTableBatch(address tableOwner, uint256[] manufacturerIds) returns() -func (_Registry *RegistryTransactorSession) CreateDeviceDefinitionTableBatch(tableOwner common.Address, manufacturerIds []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.CreateDeviceDefinitionTableBatch(&_Registry.TransactOpts, tableOwner, manufacturerIds) -} - -// CreateVehicleStream is a paid mutator transaction binding the contract method 0x497323c8. -// -// Solidity: function createVehicleStream(uint256 vehicleId) returns() -func (_Registry *RegistryTransactor) CreateVehicleStream(opts *bind.TransactOpts, vehicleId *big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "createVehicleStream", vehicleId) -} - -// CreateVehicleStream is a paid mutator transaction binding the contract method 0x497323c8. -// -// Solidity: function createVehicleStream(uint256 vehicleId) returns() -func (_Registry *RegistrySession) CreateVehicleStream(vehicleId *big.Int) (*types.Transaction, error) { - return _Registry.Contract.CreateVehicleStream(&_Registry.TransactOpts, vehicleId) -} - -// CreateVehicleStream is a paid mutator transaction binding the contract method 0x497323c8. -// -// Solidity: function createVehicleStream(uint256 vehicleId) returns() -func (_Registry *RegistryTransactorSession) CreateVehicleStream(vehicleId *big.Int) (*types.Transaction, error) { - return _Registry.Contract.CreateVehicleStream(&_Registry.TransactOpts, vehicleId) -} - -// DeleteDeviceDefinition is a paid mutator transaction binding the contract method 0x32b3f2d5. -// -// Solidity: function deleteDeviceDefinition(uint256 manufacturerId, string id) returns() -func (_Registry *RegistryTransactor) DeleteDeviceDefinition(opts *bind.TransactOpts, manufacturerId *big.Int, id string) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "deleteDeviceDefinition", manufacturerId, id) -} - -// DeleteDeviceDefinition is a paid mutator transaction binding the contract method 0x32b3f2d5. -// -// Solidity: function deleteDeviceDefinition(uint256 manufacturerId, string id) returns() -func (_Registry *RegistrySession) DeleteDeviceDefinition(manufacturerId *big.Int, id string) (*types.Transaction, error) { - return _Registry.Contract.DeleteDeviceDefinition(&_Registry.TransactOpts, manufacturerId, id) -} - -// DeleteDeviceDefinition is a paid mutator transaction binding the contract method 0x32b3f2d5. -// -// Solidity: function deleteDeviceDefinition(uint256 manufacturerId, string id) returns() -func (_Registry *RegistryTransactorSession) DeleteDeviceDefinition(manufacturerId *big.Int, id string) (*types.Transaction, error) { - return _Registry.Contract.DeleteDeviceDefinition(&_Registry.TransactOpts, manufacturerId, id) -} - -// GetPolicy is a paid mutator transaction binding the contract method 0x66df322e. -// -// Solidity: function getPolicy(address caller, uint256 ) payable returns((bool,bool,bool,string,string,string[]) policy) -func (_Registry *RegistryTransactor) GetPolicy(opts *bind.TransactOpts, caller common.Address, arg1 *big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "getPolicy", caller, arg1) -} - -// GetPolicy is a paid mutator transaction binding the contract method 0x66df322e. -// -// Solidity: function getPolicy(address caller, uint256 ) payable returns((bool,bool,bool,string,string,string[]) policy) -func (_Registry *RegistrySession) GetPolicy(caller common.Address, arg1 *big.Int) (*types.Transaction, error) { - return _Registry.Contract.GetPolicy(&_Registry.TransactOpts, caller, arg1) -} - -// GetPolicy is a paid mutator transaction binding the contract method 0x66df322e. -// -// Solidity: function getPolicy(address caller, uint256 ) payable returns((bool,bool,bool,string,string,string[]) policy) -func (_Registry *RegistryTransactorSession) GetPolicy(caller common.Address, arg1 *big.Int) (*types.Transaction, error) { - return _Registry.Contract.GetPolicy(&_Registry.TransactOpts, caller, arg1) -} - -// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. -// -// Solidity: function grantRole(bytes32 role, address account) returns() -func (_Registry *RegistryTransactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "grantRole", role, account) -} - -// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. -// -// Solidity: function grantRole(bytes32 role, address account) returns() -func (_Registry *RegistrySession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { - return _Registry.Contract.GrantRole(&_Registry.TransactOpts, role, account) -} - -// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. -// -// Solidity: function grantRole(bytes32 role, address account) returns() -func (_Registry *RegistryTransactorSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { - return _Registry.Contract.GrantRole(&_Registry.TransactOpts, role, account) -} - -// Initialize is a paid mutator transaction binding the contract method 0x4cd88b76. -// -// Solidity: function initialize(string name, string version) returns() -func (_Registry *RegistryTransactor) Initialize(opts *bind.TransactOpts, name string, version string) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "initialize", name, version) -} - -// Initialize is a paid mutator transaction binding the contract method 0x4cd88b76. -// -// Solidity: function initialize(string name, string version) returns() -func (_Registry *RegistrySession) Initialize(name string, version string) (*types.Transaction, error) { - return _Registry.Contract.Initialize(&_Registry.TransactOpts, name, version) -} - -// Initialize is a paid mutator transaction binding the contract method 0x4cd88b76. -// -// Solidity: function initialize(string name, string version) returns() -func (_Registry *RegistryTransactorSession) Initialize(name string, version string) (*types.Transaction, error) { - return _Registry.Contract.Initialize(&_Registry.TransactOpts, name, version) -} - -// InsertDeviceDefinition is a paid mutator transaction binding the contract method 0x23536c5f. -// -// Solidity: function insertDeviceDefinition(uint256 manufacturerId, (string,string,uint256,string,string,string,string) data) returns() -func (_Registry *RegistryTransactor) InsertDeviceDefinition(opts *bind.TransactOpts, manufacturerId *big.Int, data DeviceDefinitionInput) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "insertDeviceDefinition", manufacturerId, data) -} - -// InsertDeviceDefinition is a paid mutator transaction binding the contract method 0x23536c5f. -// -// Solidity: function insertDeviceDefinition(uint256 manufacturerId, (string,string,uint256,string,string,string,string) data) returns() -func (_Registry *RegistrySession) InsertDeviceDefinition(manufacturerId *big.Int, data DeviceDefinitionInput) (*types.Transaction, error) { - return _Registry.Contract.InsertDeviceDefinition(&_Registry.TransactOpts, manufacturerId, data) -} - -// InsertDeviceDefinition is a paid mutator transaction binding the contract method 0x23536c5f. -// -// Solidity: function insertDeviceDefinition(uint256 manufacturerId, (string,string,uint256,string,string,string,string) data) returns() -func (_Registry *RegistryTransactorSession) InsertDeviceDefinition(manufacturerId *big.Int, data DeviceDefinitionInput) (*types.Transaction, error) { - return _Registry.Contract.InsertDeviceDefinition(&_Registry.TransactOpts, manufacturerId, data) -} - -// InsertDeviceDefinitionBatch is a paid mutator transaction binding the contract method 0x80d50451. -// -// Solidity: function insertDeviceDefinitionBatch(uint256 manufacturerId, (string,string,uint256,string,string,string,string)[] data) returns() -func (_Registry *RegistryTransactor) InsertDeviceDefinitionBatch(opts *bind.TransactOpts, manufacturerId *big.Int, data []DeviceDefinitionInput) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "insertDeviceDefinitionBatch", manufacturerId, data) -} - -// InsertDeviceDefinitionBatch is a paid mutator transaction binding the contract method 0x80d50451. -// -// Solidity: function insertDeviceDefinitionBatch(uint256 manufacturerId, (string,string,uint256,string,string,string,string)[] data) returns() -func (_Registry *RegistrySession) InsertDeviceDefinitionBatch(manufacturerId *big.Int, data []DeviceDefinitionInput) (*types.Transaction, error) { - return _Registry.Contract.InsertDeviceDefinitionBatch(&_Registry.TransactOpts, manufacturerId, data) -} - -// InsertDeviceDefinitionBatch is a paid mutator transaction binding the contract method 0x80d50451. -// -// Solidity: function insertDeviceDefinitionBatch(uint256 manufacturerId, (string,string,uint256,string,string,string,string)[] data) returns() -func (_Registry *RegistryTransactorSession) InsertDeviceDefinitionBatch(manufacturerId *big.Int, data []DeviceDefinitionInput) (*types.Transaction, error) { - return _Registry.Contract.InsertDeviceDefinitionBatch(&_Registry.TransactOpts, manufacturerId, data) -} - -// MintAftermarketDeviceByManufacturerBatch is a paid mutator transaction binding the contract method 0x7ba79a39. -// -// Solidity: function mintAftermarketDeviceByManufacturerBatch(uint256 manufacturerNode, (address,(string,string)[])[] adInfos) returns() -func (_Registry *RegistryTransactor) MintAftermarketDeviceByManufacturerBatch(opts *bind.TransactOpts, manufacturerNode *big.Int, adInfos []AftermarketDeviceInfos) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "mintAftermarketDeviceByManufacturerBatch", manufacturerNode, adInfos) -} - -// MintAftermarketDeviceByManufacturerBatch is a paid mutator transaction binding the contract method 0x7ba79a39. -// -// Solidity: function mintAftermarketDeviceByManufacturerBatch(uint256 manufacturerNode, (address,(string,string)[])[] adInfos) returns() -func (_Registry *RegistrySession) MintAftermarketDeviceByManufacturerBatch(manufacturerNode *big.Int, adInfos []AftermarketDeviceInfos) (*types.Transaction, error) { - return _Registry.Contract.MintAftermarketDeviceByManufacturerBatch(&_Registry.TransactOpts, manufacturerNode, adInfos) -} - -// MintAftermarketDeviceByManufacturerBatch is a paid mutator transaction binding the contract method 0x7ba79a39. -// -// Solidity: function mintAftermarketDeviceByManufacturerBatch(uint256 manufacturerNode, (address,(string,string)[])[] adInfos) returns() -func (_Registry *RegistryTransactorSession) MintAftermarketDeviceByManufacturerBatch(manufacturerNode *big.Int, adInfos []AftermarketDeviceInfos) (*types.Transaction, error) { - return _Registry.Contract.MintAftermarketDeviceByManufacturerBatch(&_Registry.TransactOpts, manufacturerNode, adInfos) -} - -// MintIntegration is a paid mutator transaction binding the contract method 0xd6739004. -// -// Solidity: function mintIntegration(address owner, string name, (string,string)[] attrInfoPairList) returns() -func (_Registry *RegistryTransactor) MintIntegration(opts *bind.TransactOpts, owner common.Address, name string, attrInfoPairList []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "mintIntegration", owner, name, attrInfoPairList) -} - -// MintIntegration is a paid mutator transaction binding the contract method 0xd6739004. -// -// Solidity: function mintIntegration(address owner, string name, (string,string)[] attrInfoPairList) returns() -func (_Registry *RegistrySession) MintIntegration(owner common.Address, name string, attrInfoPairList []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.MintIntegration(&_Registry.TransactOpts, owner, name, attrInfoPairList) -} - -// MintIntegration is a paid mutator transaction binding the contract method 0xd6739004. -// -// Solidity: function mintIntegration(address owner, string name, (string,string)[] attrInfoPairList) returns() -func (_Registry *RegistryTransactorSession) MintIntegration(owner common.Address, name string, attrInfoPairList []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.MintIntegration(&_Registry.TransactOpts, owner, name, attrInfoPairList) -} - -// MintIntegrationBatch is a paid mutator transaction binding the contract method 0x653af271. -// -// Solidity: function mintIntegrationBatch(address owner, string[] names) returns() -func (_Registry *RegistryTransactor) MintIntegrationBatch(opts *bind.TransactOpts, owner common.Address, names []string) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "mintIntegrationBatch", owner, names) -} - -// MintIntegrationBatch is a paid mutator transaction binding the contract method 0x653af271. -// -// Solidity: function mintIntegrationBatch(address owner, string[] names) returns() -func (_Registry *RegistrySession) MintIntegrationBatch(owner common.Address, names []string) (*types.Transaction, error) { - return _Registry.Contract.MintIntegrationBatch(&_Registry.TransactOpts, owner, names) -} - -// MintIntegrationBatch is a paid mutator transaction binding the contract method 0x653af271. -// -// Solidity: function mintIntegrationBatch(address owner, string[] names) returns() -func (_Registry *RegistryTransactorSession) MintIntegrationBatch(owner common.Address, names []string) (*types.Transaction, error) { - return _Registry.Contract.MintIntegrationBatch(&_Registry.TransactOpts, owner, names) -} - -// MintManufacturer is a paid mutator transaction binding the contract method 0x5f36da6b. -// -// Solidity: function mintManufacturer(address owner, string name, (string,string)[] attrInfoPairList) returns() -func (_Registry *RegistryTransactor) MintManufacturer(opts *bind.TransactOpts, owner common.Address, name string, attrInfoPairList []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "mintManufacturer", owner, name, attrInfoPairList) -} - -// MintManufacturer is a paid mutator transaction binding the contract method 0x5f36da6b. -// -// Solidity: function mintManufacturer(address owner, string name, (string,string)[] attrInfoPairList) returns() -func (_Registry *RegistrySession) MintManufacturer(owner common.Address, name string, attrInfoPairList []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.MintManufacturer(&_Registry.TransactOpts, owner, name, attrInfoPairList) -} - -// MintManufacturer is a paid mutator transaction binding the contract method 0x5f36da6b. -// -// Solidity: function mintManufacturer(address owner, string name, (string,string)[] attrInfoPairList) returns() -func (_Registry *RegistryTransactorSession) MintManufacturer(owner common.Address, name string, attrInfoPairList []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.MintManufacturer(&_Registry.TransactOpts, owner, name, attrInfoPairList) -} - -// MintManufacturerBatch is a paid mutator transaction binding the contract method 0x9abb3000. -// -// Solidity: function mintManufacturerBatch(address owner, string[] names) returns() -func (_Registry *RegistryTransactor) MintManufacturerBatch(opts *bind.TransactOpts, owner common.Address, names []string) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "mintManufacturerBatch", owner, names) -} - -// MintManufacturerBatch is a paid mutator transaction binding the contract method 0x9abb3000. -// -// Solidity: function mintManufacturerBatch(address owner, string[] names) returns() -func (_Registry *RegistrySession) MintManufacturerBatch(owner common.Address, names []string) (*types.Transaction, error) { - return _Registry.Contract.MintManufacturerBatch(&_Registry.TransactOpts, owner, names) -} - -// MintManufacturerBatch is a paid mutator transaction binding the contract method 0x9abb3000. -// -// Solidity: function mintManufacturerBatch(address owner, string[] names) returns() -func (_Registry *RegistryTransactorSession) MintManufacturerBatch(owner common.Address, names []string) (*types.Transaction, error) { - return _Registry.Contract.MintManufacturerBatch(&_Registry.TransactOpts, owner, names) -} - -// MintSyntheticDeviceBatch is a paid mutator transaction binding the contract method 0x261d982a. -// -// Solidity: function mintSyntheticDeviceBatch(uint256 integrationNode, (uint256,address,(string,string)[])[] data) returns() -func (_Registry *RegistryTransactor) MintSyntheticDeviceBatch(opts *bind.TransactOpts, integrationNode *big.Int, data []MintSyntheticDeviceBatchInput) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "mintSyntheticDeviceBatch", integrationNode, data) -} - -// MintSyntheticDeviceBatch is a paid mutator transaction binding the contract method 0x261d982a. -// -// Solidity: function mintSyntheticDeviceBatch(uint256 integrationNode, (uint256,address,(string,string)[])[] data) returns() -func (_Registry *RegistrySession) MintSyntheticDeviceBatch(integrationNode *big.Int, data []MintSyntheticDeviceBatchInput) (*types.Transaction, error) { - return _Registry.Contract.MintSyntheticDeviceBatch(&_Registry.TransactOpts, integrationNode, data) -} - -// MintSyntheticDeviceBatch is a paid mutator transaction binding the contract method 0x261d982a. -// -// Solidity: function mintSyntheticDeviceBatch(uint256 integrationNode, (uint256,address,(string,string)[])[] data) returns() -func (_Registry *RegistryTransactorSession) MintSyntheticDeviceBatch(integrationNode *big.Int, data []MintSyntheticDeviceBatchInput) (*types.Transaction, error) { - return _Registry.Contract.MintSyntheticDeviceBatch(&_Registry.TransactOpts, integrationNode, data) -} - -// MintSyntheticDeviceSign is a paid mutator transaction binding the contract method 0xc624e8a1. -// -// Solidity: function mintSyntheticDeviceSign((uint256,uint256,bytes,bytes,address,(string,string)[]) data) returns() -func (_Registry *RegistryTransactor) MintSyntheticDeviceSign(opts *bind.TransactOpts, data MintSyntheticDeviceInput) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "mintSyntheticDeviceSign", data) -} - -// MintSyntheticDeviceSign is a paid mutator transaction binding the contract method 0xc624e8a1. -// -// Solidity: function mintSyntheticDeviceSign((uint256,uint256,bytes,bytes,address,(string,string)[]) data) returns() -func (_Registry *RegistrySession) MintSyntheticDeviceSign(data MintSyntheticDeviceInput) (*types.Transaction, error) { - return _Registry.Contract.MintSyntheticDeviceSign(&_Registry.TransactOpts, data) -} - -// MintSyntheticDeviceSign is a paid mutator transaction binding the contract method 0xc624e8a1. -// -// Solidity: function mintSyntheticDeviceSign((uint256,uint256,bytes,bytes,address,(string,string)[]) data) returns() -func (_Registry *RegistryTransactorSession) MintSyntheticDeviceSign(data MintSyntheticDeviceInput) (*types.Transaction, error) { - return _Registry.Contract.MintSyntheticDeviceSign(&_Registry.TransactOpts, data) -} - -// MintVehicle is a paid mutator transaction binding the contract method 0x3da44e56. -// -// Solidity: function mintVehicle(uint256 manufacturerNode, address owner, (string,string)[] attrInfo) returns() -func (_Registry *RegistryTransactor) MintVehicle(opts *bind.TransactOpts, manufacturerNode *big.Int, owner common.Address, attrInfo []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "mintVehicle", manufacturerNode, owner, attrInfo) -} - -// MintVehicle is a paid mutator transaction binding the contract method 0x3da44e56. -// -// Solidity: function mintVehicle(uint256 manufacturerNode, address owner, (string,string)[] attrInfo) returns() -func (_Registry *RegistrySession) MintVehicle(manufacturerNode *big.Int, owner common.Address, attrInfo []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.MintVehicle(&_Registry.TransactOpts, manufacturerNode, owner, attrInfo) -} - -// MintVehicle is a paid mutator transaction binding the contract method 0x3da44e56. -// -// Solidity: function mintVehicle(uint256 manufacturerNode, address owner, (string,string)[] attrInfo) returns() -func (_Registry *RegistryTransactorSession) MintVehicle(manufacturerNode *big.Int, owner common.Address, attrInfo []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.MintVehicle(&_Registry.TransactOpts, manufacturerNode, owner, attrInfo) -} - -// MintVehicleAndSdSign is a paid mutator transaction binding the contract method 0xfb1a28e8. -// -// Solidity: function mintVehicleAndSdSign((uint256,address,(string,string)[],uint256,bytes,bytes,address,(string,string)[]) data) returns() -func (_Registry *RegistryTransactor) MintVehicleAndSdSign(opts *bind.TransactOpts, data MintVehicleAndSdInput) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "mintVehicleAndSdSign", data) -} - -// MintVehicleAndSdSign is a paid mutator transaction binding the contract method 0xfb1a28e8. -// -// Solidity: function mintVehicleAndSdSign((uint256,address,(string,string)[],uint256,bytes,bytes,address,(string,string)[]) data) returns() -func (_Registry *RegistrySession) MintVehicleAndSdSign(data MintVehicleAndSdInput) (*types.Transaction, error) { - return _Registry.Contract.MintVehicleAndSdSign(&_Registry.TransactOpts, data) -} - -// MintVehicleAndSdSign is a paid mutator transaction binding the contract method 0xfb1a28e8. -// -// Solidity: function mintVehicleAndSdSign((uint256,address,(string,string)[],uint256,bytes,bytes,address,(string,string)[]) data) returns() -func (_Registry *RegistryTransactorSession) MintVehicleAndSdSign(data MintVehicleAndSdInput) (*types.Transaction, error) { - return _Registry.Contract.MintVehicleAndSdSign(&_Registry.TransactOpts, data) -} - -// MintVehicleAndSdWithDeviceDefinitionSign is a paid mutator transaction binding the contract method 0xd23965e3. -// -// Solidity: function mintVehicleAndSdWithDeviceDefinitionSign((uint256,address,string,(string,string)[],uint256,bytes,bytes,address,(string,string)[]) data) returns() -func (_Registry *RegistryTransactor) MintVehicleAndSdWithDeviceDefinitionSign(opts *bind.TransactOpts, data MintVehicleAndSdWithDdInput) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "mintVehicleAndSdWithDeviceDefinitionSign", data) -} - -// MintVehicleAndSdWithDeviceDefinitionSign is a paid mutator transaction binding the contract method 0xd23965e3. -// -// Solidity: function mintVehicleAndSdWithDeviceDefinitionSign((uint256,address,string,(string,string)[],uint256,bytes,bytes,address,(string,string)[]) data) returns() -func (_Registry *RegistrySession) MintVehicleAndSdWithDeviceDefinitionSign(data MintVehicleAndSdWithDdInput) (*types.Transaction, error) { - return _Registry.Contract.MintVehicleAndSdWithDeviceDefinitionSign(&_Registry.TransactOpts, data) -} - -// MintVehicleAndSdWithDeviceDefinitionSign is a paid mutator transaction binding the contract method 0xd23965e3. -// -// Solidity: function mintVehicleAndSdWithDeviceDefinitionSign((uint256,address,string,(string,string)[],uint256,bytes,bytes,address,(string,string)[]) data) returns() -func (_Registry *RegistryTransactorSession) MintVehicleAndSdWithDeviceDefinitionSign(data MintVehicleAndSdWithDdInput) (*types.Transaction, error) { - return _Registry.Contract.MintVehicleAndSdWithDeviceDefinitionSign(&_Registry.TransactOpts, data) -} - -// MintVehicleSign is a paid mutator transaction binding the contract method 0x1b1a82c8. -// -// Solidity: function mintVehicleSign(uint256 manufacturerNode, address owner, (string,string)[] attrInfo, bytes signature) returns() -func (_Registry *RegistryTransactor) MintVehicleSign(opts *bind.TransactOpts, manufacturerNode *big.Int, owner common.Address, attrInfo []AttributeInfoPair, signature []byte) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "mintVehicleSign", manufacturerNode, owner, attrInfo, signature) -} - -// MintVehicleSign is a paid mutator transaction binding the contract method 0x1b1a82c8. -// -// Solidity: function mintVehicleSign(uint256 manufacturerNode, address owner, (string,string)[] attrInfo, bytes signature) returns() -func (_Registry *RegistrySession) MintVehicleSign(manufacturerNode *big.Int, owner common.Address, attrInfo []AttributeInfoPair, signature []byte) (*types.Transaction, error) { - return _Registry.Contract.MintVehicleSign(&_Registry.TransactOpts, manufacturerNode, owner, attrInfo, signature) -} - -// MintVehicleSign is a paid mutator transaction binding the contract method 0x1b1a82c8. -// -// Solidity: function mintVehicleSign(uint256 manufacturerNode, address owner, (string,string)[] attrInfo, bytes signature) returns() -func (_Registry *RegistryTransactorSession) MintVehicleSign(manufacturerNode *big.Int, owner common.Address, attrInfo []AttributeInfoPair, signature []byte) (*types.Transaction, error) { - return _Registry.Contract.MintVehicleSign(&_Registry.TransactOpts, manufacturerNode, owner, attrInfo, signature) -} - -// MintVehicleWithDeviceDefinition is a paid mutator transaction binding the contract method 0xd84baff1. -// -// Solidity: function mintVehicleWithDeviceDefinition(uint256 manufacturerNode, address owner, string deviceDefinitionId, (string,string)[] attrInfo) returns() -func (_Registry *RegistryTransactor) MintVehicleWithDeviceDefinition(opts *bind.TransactOpts, manufacturerNode *big.Int, owner common.Address, deviceDefinitionId string, attrInfo []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "mintVehicleWithDeviceDefinition", manufacturerNode, owner, deviceDefinitionId, attrInfo) -} - -// MintVehicleWithDeviceDefinition is a paid mutator transaction binding the contract method 0xd84baff1. -// -// Solidity: function mintVehicleWithDeviceDefinition(uint256 manufacturerNode, address owner, string deviceDefinitionId, (string,string)[] attrInfo) returns() -func (_Registry *RegistrySession) MintVehicleWithDeviceDefinition(manufacturerNode *big.Int, owner common.Address, deviceDefinitionId string, attrInfo []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.MintVehicleWithDeviceDefinition(&_Registry.TransactOpts, manufacturerNode, owner, deviceDefinitionId, attrInfo) -} - -// MintVehicleWithDeviceDefinition is a paid mutator transaction binding the contract method 0xd84baff1. -// -// Solidity: function mintVehicleWithDeviceDefinition(uint256 manufacturerNode, address owner, string deviceDefinitionId, (string,string)[] attrInfo) returns() -func (_Registry *RegistryTransactorSession) MintVehicleWithDeviceDefinition(manufacturerNode *big.Int, owner common.Address, deviceDefinitionId string, attrInfo []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.MintVehicleWithDeviceDefinition(&_Registry.TransactOpts, manufacturerNode, owner, deviceDefinitionId, attrInfo) -} - -// MintVehicleWithDeviceDefinitionSign is a paid mutator transaction binding the contract method 0x8dca2b8e. -// -// Solidity: function mintVehicleWithDeviceDefinitionSign(uint256 manufacturerNode, address owner, string deviceDefinitionId, (string,string)[] attrInfo, bytes signature) returns() -func (_Registry *RegistryTransactor) MintVehicleWithDeviceDefinitionSign(opts *bind.TransactOpts, manufacturerNode *big.Int, owner common.Address, deviceDefinitionId string, attrInfo []AttributeInfoPair, signature []byte) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "mintVehicleWithDeviceDefinitionSign", manufacturerNode, owner, deviceDefinitionId, attrInfo, signature) -} - -// MintVehicleWithDeviceDefinitionSign is a paid mutator transaction binding the contract method 0x8dca2b8e. -// -// Solidity: function mintVehicleWithDeviceDefinitionSign(uint256 manufacturerNode, address owner, string deviceDefinitionId, (string,string)[] attrInfo, bytes signature) returns() -func (_Registry *RegistrySession) MintVehicleWithDeviceDefinitionSign(manufacturerNode *big.Int, owner common.Address, deviceDefinitionId string, attrInfo []AttributeInfoPair, signature []byte) (*types.Transaction, error) { - return _Registry.Contract.MintVehicleWithDeviceDefinitionSign(&_Registry.TransactOpts, manufacturerNode, owner, deviceDefinitionId, attrInfo, signature) -} - -// MintVehicleWithDeviceDefinitionSign is a paid mutator transaction binding the contract method 0x8dca2b8e. -// -// Solidity: function mintVehicleWithDeviceDefinitionSign(uint256 manufacturerNode, address owner, string deviceDefinitionId, (string,string)[] attrInfo, bytes signature) returns() -func (_Registry *RegistryTransactorSession) MintVehicleWithDeviceDefinitionSign(manufacturerNode *big.Int, owner common.Address, deviceDefinitionId string, attrInfo []AttributeInfoPair, signature []byte) (*types.Transaction, error) { - return _Registry.Contract.MintVehicleWithDeviceDefinitionSign(&_Registry.TransactOpts, manufacturerNode, owner, deviceDefinitionId, attrInfo, signature) -} - -// MultiDelegateCall is a paid mutator transaction binding the contract method 0x415c2d96. -// -// Solidity: function multiDelegateCall(bytes[] data) returns(bytes[] results) -func (_Registry *RegistryTransactor) MultiDelegateCall(opts *bind.TransactOpts, data [][]byte) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "multiDelegateCall", data) -} - -// MultiDelegateCall is a paid mutator transaction binding the contract method 0x415c2d96. -// -// Solidity: function multiDelegateCall(bytes[] data) returns(bytes[] results) -func (_Registry *RegistrySession) MultiDelegateCall(data [][]byte) (*types.Transaction, error) { - return _Registry.Contract.MultiDelegateCall(&_Registry.TransactOpts, data) -} - -// MultiDelegateCall is a paid mutator transaction binding the contract method 0x415c2d96. -// -// Solidity: function multiDelegateCall(bytes[] data) returns(bytes[] results) -func (_Registry *RegistryTransactorSession) MultiDelegateCall(data [][]byte) (*types.Transaction, error) { - return _Registry.Contract.MultiDelegateCall(&_Registry.TransactOpts, data) -} - -// OnBurnVehicleStream is a paid mutator transaction binding the contract method 0xa91ec798. -// -// Solidity: function onBurnVehicleStream(uint256 vehicleId) returns() -func (_Registry *RegistryTransactor) OnBurnVehicleStream(opts *bind.TransactOpts, vehicleId *big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "onBurnVehicleStream", vehicleId) -} - -// OnBurnVehicleStream is a paid mutator transaction binding the contract method 0xa91ec798. -// -// Solidity: function onBurnVehicleStream(uint256 vehicleId) returns() -func (_Registry *RegistrySession) OnBurnVehicleStream(vehicleId *big.Int) (*types.Transaction, error) { - return _Registry.Contract.OnBurnVehicleStream(&_Registry.TransactOpts, vehicleId) -} - -// OnBurnVehicleStream is a paid mutator transaction binding the contract method 0xa91ec798. -// -// Solidity: function onBurnVehicleStream(uint256 vehicleId) returns() -func (_Registry *RegistryTransactorSession) OnBurnVehicleStream(vehicleId *big.Int) (*types.Transaction, error) { - return _Registry.Contract.OnBurnVehicleStream(&_Registry.TransactOpts, vehicleId) -} - -// OnSetSubscribePrivilege is a paid mutator transaction binding the contract method 0xc8f11a06. -// -// Solidity: function onSetSubscribePrivilege(uint256 vehicleId, address subscriber, uint256 expirationTime) returns() -func (_Registry *RegistryTransactor) OnSetSubscribePrivilege(opts *bind.TransactOpts, vehicleId *big.Int, subscriber common.Address, expirationTime *big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "onSetSubscribePrivilege", vehicleId, subscriber, expirationTime) -} - -// OnSetSubscribePrivilege is a paid mutator transaction binding the contract method 0xc8f11a06. -// -// Solidity: function onSetSubscribePrivilege(uint256 vehicleId, address subscriber, uint256 expirationTime) returns() -func (_Registry *RegistrySession) OnSetSubscribePrivilege(vehicleId *big.Int, subscriber common.Address, expirationTime *big.Int) (*types.Transaction, error) { - return _Registry.Contract.OnSetSubscribePrivilege(&_Registry.TransactOpts, vehicleId, subscriber, expirationTime) -} - -// OnSetSubscribePrivilege is a paid mutator transaction binding the contract method 0xc8f11a06. -// -// Solidity: function onSetSubscribePrivilege(uint256 vehicleId, address subscriber, uint256 expirationTime) returns() -func (_Registry *RegistryTransactorSession) OnSetSubscribePrivilege(vehicleId *big.Int, subscriber common.Address, expirationTime *big.Int) (*types.Transaction, error) { - return _Registry.Contract.OnSetSubscribePrivilege(&_Registry.TransactOpts, vehicleId, subscriber, expirationTime) -} - -// OnTransferVehicleStream is a paid mutator transaction binding the contract method 0x1882b263. -// -// Solidity: function onTransferVehicleStream(address to, uint256 vehicleId) returns() -func (_Registry *RegistryTransactor) OnTransferVehicleStream(opts *bind.TransactOpts, to common.Address, vehicleId *big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "onTransferVehicleStream", to, vehicleId) -} - -// OnTransferVehicleStream is a paid mutator transaction binding the contract method 0x1882b263. -// -// Solidity: function onTransferVehicleStream(address to, uint256 vehicleId) returns() -func (_Registry *RegistrySession) OnTransferVehicleStream(to common.Address, vehicleId *big.Int) (*types.Transaction, error) { - return _Registry.Contract.OnTransferVehicleStream(&_Registry.TransactOpts, to, vehicleId) -} - -// OnTransferVehicleStream is a paid mutator transaction binding the contract method 0x1882b263. -// -// Solidity: function onTransferVehicleStream(address to, uint256 vehicleId) returns() -func (_Registry *RegistryTransactorSession) OnTransferVehicleStream(to common.Address, vehicleId *big.Int) (*types.Transaction, error) { - return _Registry.Contract.OnTransferVehicleStream(&_Registry.TransactOpts, to, vehicleId) -} - -// PairAftermarketDeviceSign is a paid mutator transaction binding the contract method 0xb50df2f7. -// -// Solidity: function pairAftermarketDeviceSign(uint256 aftermarketDeviceNode, uint256 vehicleNode, bytes aftermarketDeviceSig, bytes vehicleOwnerSig) returns() -func (_Registry *RegistryTransactor) PairAftermarketDeviceSign(opts *bind.TransactOpts, aftermarketDeviceNode *big.Int, vehicleNode *big.Int, aftermarketDeviceSig []byte, vehicleOwnerSig []byte) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "pairAftermarketDeviceSign", aftermarketDeviceNode, vehicleNode, aftermarketDeviceSig, vehicleOwnerSig) -} - -// PairAftermarketDeviceSign is a paid mutator transaction binding the contract method 0xb50df2f7. -// -// Solidity: function pairAftermarketDeviceSign(uint256 aftermarketDeviceNode, uint256 vehicleNode, bytes aftermarketDeviceSig, bytes vehicleOwnerSig) returns() -func (_Registry *RegistrySession) PairAftermarketDeviceSign(aftermarketDeviceNode *big.Int, vehicleNode *big.Int, aftermarketDeviceSig []byte, vehicleOwnerSig []byte) (*types.Transaction, error) { - return _Registry.Contract.PairAftermarketDeviceSign(&_Registry.TransactOpts, aftermarketDeviceNode, vehicleNode, aftermarketDeviceSig, vehicleOwnerSig) -} - -// PairAftermarketDeviceSign is a paid mutator transaction binding the contract method 0xb50df2f7. -// -// Solidity: function pairAftermarketDeviceSign(uint256 aftermarketDeviceNode, uint256 vehicleNode, bytes aftermarketDeviceSig, bytes vehicleOwnerSig) returns() -func (_Registry *RegistryTransactorSession) PairAftermarketDeviceSign(aftermarketDeviceNode *big.Int, vehicleNode *big.Int, aftermarketDeviceSig []byte, vehicleOwnerSig []byte) (*types.Transaction, error) { - return _Registry.Contract.PairAftermarketDeviceSign(&_Registry.TransactOpts, aftermarketDeviceNode, vehicleNode, aftermarketDeviceSig, vehicleOwnerSig) -} - -// PairAftermarketDeviceSign0 is a paid mutator transaction binding the contract method 0xcfe642dd. -// -// Solidity: function pairAftermarketDeviceSign(uint256 aftermarketDeviceNode, uint256 vehicleNode, bytes signature) returns() -func (_Registry *RegistryTransactor) PairAftermarketDeviceSign0(opts *bind.TransactOpts, aftermarketDeviceNode *big.Int, vehicleNode *big.Int, signature []byte) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "pairAftermarketDeviceSign0", aftermarketDeviceNode, vehicleNode, signature) -} - -// PairAftermarketDeviceSign0 is a paid mutator transaction binding the contract method 0xcfe642dd. -// -// Solidity: function pairAftermarketDeviceSign(uint256 aftermarketDeviceNode, uint256 vehicleNode, bytes signature) returns() -func (_Registry *RegistrySession) PairAftermarketDeviceSign0(aftermarketDeviceNode *big.Int, vehicleNode *big.Int, signature []byte) (*types.Transaction, error) { - return _Registry.Contract.PairAftermarketDeviceSign0(&_Registry.TransactOpts, aftermarketDeviceNode, vehicleNode, signature) -} - -// PairAftermarketDeviceSign0 is a paid mutator transaction binding the contract method 0xcfe642dd. -// -// Solidity: function pairAftermarketDeviceSign(uint256 aftermarketDeviceNode, uint256 vehicleNode, bytes signature) returns() -func (_Registry *RegistryTransactorSession) PairAftermarketDeviceSign0(aftermarketDeviceNode *big.Int, vehicleNode *big.Int, signature []byte) (*types.Transaction, error) { - return _Registry.Contract.PairAftermarketDeviceSign0(&_Registry.TransactOpts, aftermarketDeviceNode, vehicleNode, signature) -} - -// RemoveModule is a paid mutator transaction binding the contract method 0x9748a762. -// -// Solidity: function removeModule(address implementation, bytes4[] selectors) returns() -func (_Registry *RegistryTransactor) RemoveModule(opts *bind.TransactOpts, implementation common.Address, selectors [][4]byte) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "removeModule", implementation, selectors) -} - -// RemoveModule is a paid mutator transaction binding the contract method 0x9748a762. -// -// Solidity: function removeModule(address implementation, bytes4[] selectors) returns() -func (_Registry *RegistrySession) RemoveModule(implementation common.Address, selectors [][4]byte) (*types.Transaction, error) { - return _Registry.Contract.RemoveModule(&_Registry.TransactOpts, implementation, selectors) -} - -// RemoveModule is a paid mutator transaction binding the contract method 0x9748a762. -// -// Solidity: function removeModule(address implementation, bytes4[] selectors) returns() -func (_Registry *RegistryTransactorSession) RemoveModule(implementation common.Address, selectors [][4]byte) (*types.Transaction, error) { - return _Registry.Contract.RemoveModule(&_Registry.TransactOpts, implementation, selectors) -} - -// RenameManufacturers is a paid mutator transaction binding the contract method 0xf73a8f04. -// -// Solidity: function renameManufacturers((uint256,string)[] idManufacturerNames) returns() -func (_Registry *RegistryTransactor) RenameManufacturers(opts *bind.TransactOpts, idManufacturerNames []DevAdminIdManufacturerName) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "renameManufacturers", idManufacturerNames) -} - -// RenameManufacturers is a paid mutator transaction binding the contract method 0xf73a8f04. -// -// Solidity: function renameManufacturers((uint256,string)[] idManufacturerNames) returns() -func (_Registry *RegistrySession) RenameManufacturers(idManufacturerNames []DevAdminIdManufacturerName) (*types.Transaction, error) { - return _Registry.Contract.RenameManufacturers(&_Registry.TransactOpts, idManufacturerNames) -} - -// RenameManufacturers is a paid mutator transaction binding the contract method 0xf73a8f04. -// -// Solidity: function renameManufacturers((uint256,string)[] idManufacturerNames) returns() -func (_Registry *RegistryTransactorSession) RenameManufacturers(idManufacturerNames []DevAdminIdManufacturerName) (*types.Transaction, error) { - return _Registry.Contract.RenameManufacturers(&_Registry.TransactOpts, idManufacturerNames) -} - -// RenounceRole is a paid mutator transaction binding the contract method 0x8bb9c5bf. -// -// Solidity: function renounceRole(bytes32 role) returns() -func (_Registry *RegistryTransactor) RenounceRole(opts *bind.TransactOpts, role [32]byte) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "renounceRole", role) -} - -// RenounceRole is a paid mutator transaction binding the contract method 0x8bb9c5bf. -// -// Solidity: function renounceRole(bytes32 role) returns() -func (_Registry *RegistrySession) RenounceRole(role [32]byte) (*types.Transaction, error) { - return _Registry.Contract.RenounceRole(&_Registry.TransactOpts, role) -} - -// RenounceRole is a paid mutator transaction binding the contract method 0x8bb9c5bf. -// -// Solidity: function renounceRole(bytes32 role) returns() -func (_Registry *RegistryTransactorSession) RenounceRole(role [32]byte) (*types.Transaction, error) { - return _Registry.Contract.RenounceRole(&_Registry.TransactOpts, role) -} - -// ReprovisionAftermarketDeviceByManufacturerBatch is a paid mutator transaction binding the contract method 0x9b3abd48. -// -// Solidity: function reprovisionAftermarketDeviceByManufacturerBatch(uint256[] aftermarketDeviceNodeList) returns() -func (_Registry *RegistryTransactor) ReprovisionAftermarketDeviceByManufacturerBatch(opts *bind.TransactOpts, aftermarketDeviceNodeList []*big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "reprovisionAftermarketDeviceByManufacturerBatch", aftermarketDeviceNodeList) -} - -// ReprovisionAftermarketDeviceByManufacturerBatch is a paid mutator transaction binding the contract method 0x9b3abd48. -// -// Solidity: function reprovisionAftermarketDeviceByManufacturerBatch(uint256[] aftermarketDeviceNodeList) returns() -func (_Registry *RegistrySession) ReprovisionAftermarketDeviceByManufacturerBatch(aftermarketDeviceNodeList []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.ReprovisionAftermarketDeviceByManufacturerBatch(&_Registry.TransactOpts, aftermarketDeviceNodeList) -} - -// ReprovisionAftermarketDeviceByManufacturerBatch is a paid mutator transaction binding the contract method 0x9b3abd48. -// -// Solidity: function reprovisionAftermarketDeviceByManufacturerBatch(uint256[] aftermarketDeviceNodeList) returns() -func (_Registry *RegistryTransactorSession) ReprovisionAftermarketDeviceByManufacturerBatch(aftermarketDeviceNodeList []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.ReprovisionAftermarketDeviceByManufacturerBatch(&_Registry.TransactOpts, aftermarketDeviceNodeList) -} - -// ResetAftermarketDeviceAddressByManufacturerBatch is a paid mutator transaction binding the contract method 0x9d0b139b. -// -// Solidity: function resetAftermarketDeviceAddressByManufacturerBatch((uint256,address)[] adIdAddrs) returns() -func (_Registry *RegistryTransactor) ResetAftermarketDeviceAddressByManufacturerBatch(opts *bind.TransactOpts, adIdAddrs []AftermarketDeviceIdAddressPair) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "resetAftermarketDeviceAddressByManufacturerBatch", adIdAddrs) -} - -// ResetAftermarketDeviceAddressByManufacturerBatch is a paid mutator transaction binding the contract method 0x9d0b139b. -// -// Solidity: function resetAftermarketDeviceAddressByManufacturerBatch((uint256,address)[] adIdAddrs) returns() -func (_Registry *RegistrySession) ResetAftermarketDeviceAddressByManufacturerBatch(adIdAddrs []AftermarketDeviceIdAddressPair) (*types.Transaction, error) { - return _Registry.Contract.ResetAftermarketDeviceAddressByManufacturerBatch(&_Registry.TransactOpts, adIdAddrs) -} - -// ResetAftermarketDeviceAddressByManufacturerBatch is a paid mutator transaction binding the contract method 0x9d0b139b. -// -// Solidity: function resetAftermarketDeviceAddressByManufacturerBatch((uint256,address)[] adIdAddrs) returns() -func (_Registry *RegistryTransactorSession) ResetAftermarketDeviceAddressByManufacturerBatch(adIdAddrs []AftermarketDeviceIdAddressPair) (*types.Transaction, error) { - return _Registry.Contract.ResetAftermarketDeviceAddressByManufacturerBatch(&_Registry.TransactOpts, adIdAddrs) -} - -// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. -// -// Solidity: function revokeRole(bytes32 role, address account) returns() -func (_Registry *RegistryTransactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "revokeRole", role, account) -} - -// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. -// -// Solidity: function revokeRole(bytes32 role, address account) returns() -func (_Registry *RegistrySession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { - return _Registry.Contract.RevokeRole(&_Registry.TransactOpts, role, account) -} - -// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. -// -// Solidity: function revokeRole(bytes32 role, address account) returns() -func (_Registry *RegistryTransactorSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { - return _Registry.Contract.RevokeRole(&_Registry.TransactOpts, role, account) -} - -// SetAftermarketDeviceBeneficiary is a paid mutator transaction binding the contract method 0xbebc0bfc. -// -// Solidity: function setAftermarketDeviceBeneficiary(uint256 nodeId, address beneficiary) returns() -func (_Registry *RegistryTransactor) SetAftermarketDeviceBeneficiary(opts *bind.TransactOpts, nodeId *big.Int, beneficiary common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setAftermarketDeviceBeneficiary", nodeId, beneficiary) -} - -// SetAftermarketDeviceBeneficiary is a paid mutator transaction binding the contract method 0xbebc0bfc. -// -// Solidity: function setAftermarketDeviceBeneficiary(uint256 nodeId, address beneficiary) returns() -func (_Registry *RegistrySession) SetAftermarketDeviceBeneficiary(nodeId *big.Int, beneficiary common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetAftermarketDeviceBeneficiary(&_Registry.TransactOpts, nodeId, beneficiary) -} - -// SetAftermarketDeviceBeneficiary is a paid mutator transaction binding the contract method 0xbebc0bfc. -// -// Solidity: function setAftermarketDeviceBeneficiary(uint256 nodeId, address beneficiary) returns() -func (_Registry *RegistryTransactorSession) SetAftermarketDeviceBeneficiary(nodeId *big.Int, beneficiary common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetAftermarketDeviceBeneficiary(&_Registry.TransactOpts, nodeId, beneficiary) -} - -// SetAftermarketDeviceIdProxyAddress is a paid mutator transaction binding the contract method 0x4d49d82a. -// -// Solidity: function setAftermarketDeviceIdProxyAddress(address addr) returns() -func (_Registry *RegistryTransactor) SetAftermarketDeviceIdProxyAddress(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setAftermarketDeviceIdProxyAddress", addr) -} - -// SetAftermarketDeviceIdProxyAddress is a paid mutator transaction binding the contract method 0x4d49d82a. -// -// Solidity: function setAftermarketDeviceIdProxyAddress(address addr) returns() -func (_Registry *RegistrySession) SetAftermarketDeviceIdProxyAddress(addr common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetAftermarketDeviceIdProxyAddress(&_Registry.TransactOpts, addr) -} - -// SetAftermarketDeviceIdProxyAddress is a paid mutator transaction binding the contract method 0x4d49d82a. -// -// Solidity: function setAftermarketDeviceIdProxyAddress(address addr) returns() -func (_Registry *RegistryTransactorSession) SetAftermarketDeviceIdProxyAddress(addr common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetAftermarketDeviceIdProxyAddress(&_Registry.TransactOpts, addr) -} - -// SetAftermarketDeviceInfo is a paid mutator transaction binding the contract method 0x4d13b709. -// -// Solidity: function setAftermarketDeviceInfo(uint256 tokenId, (string,string)[] attrInfo) returns() -func (_Registry *RegistryTransactor) SetAftermarketDeviceInfo(opts *bind.TransactOpts, tokenId *big.Int, attrInfo []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setAftermarketDeviceInfo", tokenId, attrInfo) -} - -// SetAftermarketDeviceInfo is a paid mutator transaction binding the contract method 0x4d13b709. -// -// Solidity: function setAftermarketDeviceInfo(uint256 tokenId, (string,string)[] attrInfo) returns() -func (_Registry *RegistrySession) SetAftermarketDeviceInfo(tokenId *big.Int, attrInfo []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.SetAftermarketDeviceInfo(&_Registry.TransactOpts, tokenId, attrInfo) -} - -// SetAftermarketDeviceInfo is a paid mutator transaction binding the contract method 0x4d13b709. -// -// Solidity: function setAftermarketDeviceInfo(uint256 tokenId, (string,string)[] attrInfo) returns() -func (_Registry *RegistryTransactorSession) SetAftermarketDeviceInfo(tokenId *big.Int, attrInfo []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.SetAftermarketDeviceInfo(&_Registry.TransactOpts, tokenId, attrInfo) -} - -// SetBaseDataURI is a paid mutator transaction binding the contract method 0xe324093f. -// -// Solidity: function setBaseDataURI(address idProxyAddress, string _baseDataURI) returns() -func (_Registry *RegistryTransactor) SetBaseDataURI(opts *bind.TransactOpts, idProxyAddress common.Address, _baseDataURI string) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setBaseDataURI", idProxyAddress, _baseDataURI) -} - -// SetBaseDataURI is a paid mutator transaction binding the contract method 0xe324093f. -// -// Solidity: function setBaseDataURI(address idProxyAddress, string _baseDataURI) returns() -func (_Registry *RegistrySession) SetBaseDataURI(idProxyAddress common.Address, _baseDataURI string) (*types.Transaction, error) { - return _Registry.Contract.SetBaseDataURI(&_Registry.TransactOpts, idProxyAddress, _baseDataURI) -} - -// SetBaseDataURI is a paid mutator transaction binding the contract method 0xe324093f. -// -// Solidity: function setBaseDataURI(address idProxyAddress, string _baseDataURI) returns() -func (_Registry *RegistryTransactorSession) SetBaseDataURI(idProxyAddress common.Address, _baseDataURI string) (*types.Transaction, error) { - return _Registry.Contract.SetBaseDataURI(&_Registry.TransactOpts, idProxyAddress, _baseDataURI) -} - -// SetController is a paid mutator transaction binding the contract method 0x92eefe9b. -// -// Solidity: function setController(address _controller) returns() -func (_Registry *RegistryTransactor) SetController(opts *bind.TransactOpts, _controller common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setController", _controller) -} - -// SetController is a paid mutator transaction binding the contract method 0x92eefe9b. -// -// Solidity: function setController(address _controller) returns() -func (_Registry *RegistrySession) SetController(_controller common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetController(&_Registry.TransactOpts, _controller) -} - -// SetController is a paid mutator transaction binding the contract method 0x92eefe9b. -// -// Solidity: function setController(address _controller) returns() -func (_Registry *RegistryTransactorSession) SetController(_controller common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetController(&_Registry.TransactOpts, _controller) -} - -// SetDcxOperationCost is a paid mutator transaction binding the contract method 0xa2fe8c85. -// -// Solidity: function setDcxOperationCost(bytes32 operation, uint256 cost) returns() -func (_Registry *RegistryTransactor) SetDcxOperationCost(opts *bind.TransactOpts, operation [32]byte, cost *big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setDcxOperationCost", operation, cost) -} - -// SetDcxOperationCost is a paid mutator transaction binding the contract method 0xa2fe8c85. -// -// Solidity: function setDcxOperationCost(bytes32 operation, uint256 cost) returns() -func (_Registry *RegistrySession) SetDcxOperationCost(operation [32]byte, cost *big.Int) (*types.Transaction, error) { - return _Registry.Contract.SetDcxOperationCost(&_Registry.TransactOpts, operation, cost) -} - -// SetDcxOperationCost is a paid mutator transaction binding the contract method 0xa2fe8c85. -// -// Solidity: function setDcxOperationCost(bytes32 operation, uint256 cost) returns() -func (_Registry *RegistryTransactorSession) SetDcxOperationCost(operation [32]byte, cost *big.Int) (*types.Transaction, error) { - return _Registry.Contract.SetDcxOperationCost(&_Registry.TransactOpts, operation, cost) -} - -// SetDeviceDefinitionTable is a paid mutator transaction binding the contract method 0x088fafdb. -// -// Solidity: function setDeviceDefinitionTable(uint256 manufacturerId, uint256 tableId) returns() -func (_Registry *RegistryTransactor) SetDeviceDefinitionTable(opts *bind.TransactOpts, manufacturerId *big.Int, tableId *big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setDeviceDefinitionTable", manufacturerId, tableId) -} - -// SetDeviceDefinitionTable is a paid mutator transaction binding the contract method 0x088fafdb. -// -// Solidity: function setDeviceDefinitionTable(uint256 manufacturerId, uint256 tableId) returns() -func (_Registry *RegistrySession) SetDeviceDefinitionTable(manufacturerId *big.Int, tableId *big.Int) (*types.Transaction, error) { - return _Registry.Contract.SetDeviceDefinitionTable(&_Registry.TransactOpts, manufacturerId, tableId) -} - -// SetDeviceDefinitionTable is a paid mutator transaction binding the contract method 0x088fafdb. -// -// Solidity: function setDeviceDefinitionTable(uint256 manufacturerId, uint256 tableId) returns() -func (_Registry *RegistryTransactorSession) SetDeviceDefinitionTable(manufacturerId *big.Int, tableId *big.Int) (*types.Transaction, error) { - return _Registry.Contract.SetDeviceDefinitionTable(&_Registry.TransactOpts, manufacturerId, tableId) -} - -// SetDimoBaseStreamId is a paid mutator transaction binding the contract method 0x9e594424. -// -// Solidity: function setDimoBaseStreamId(string dimoStreamrEns) returns() -func (_Registry *RegistryTransactor) SetDimoBaseStreamId(opts *bind.TransactOpts, dimoStreamrEns string) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setDimoBaseStreamId", dimoStreamrEns) -} - -// SetDimoBaseStreamId is a paid mutator transaction binding the contract method 0x9e594424. -// -// Solidity: function setDimoBaseStreamId(string dimoStreamrEns) returns() -func (_Registry *RegistrySession) SetDimoBaseStreamId(dimoStreamrEns string) (*types.Transaction, error) { - return _Registry.Contract.SetDimoBaseStreamId(&_Registry.TransactOpts, dimoStreamrEns) -} - -// SetDimoBaseStreamId is a paid mutator transaction binding the contract method 0x9e594424. -// -// Solidity: function setDimoBaseStreamId(string dimoStreamrEns) returns() -func (_Registry *RegistryTransactorSession) SetDimoBaseStreamId(dimoStreamrEns string) (*types.Transaction, error) { - return _Registry.Contract.SetDimoBaseStreamId(&_Registry.TransactOpts, dimoStreamrEns) -} - -// SetDimoCredit is a paid mutator transaction binding the contract method 0x4fa9ff16. -// -// Solidity: function setDimoCredit(address dimoCredit) returns() -func (_Registry *RegistryTransactor) SetDimoCredit(opts *bind.TransactOpts, dimoCredit common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setDimoCredit", dimoCredit) -} - -// SetDimoCredit is a paid mutator transaction binding the contract method 0x4fa9ff16. -// -// Solidity: function setDimoCredit(address dimoCredit) returns() -func (_Registry *RegistrySession) SetDimoCredit(dimoCredit common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetDimoCredit(&_Registry.TransactOpts, dimoCredit) -} - -// SetDimoCredit is a paid mutator transaction binding the contract method 0x4fa9ff16. -// -// Solidity: function setDimoCredit(address dimoCredit) returns() -func (_Registry *RegistryTransactorSession) SetDimoCredit(dimoCredit common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetDimoCredit(&_Registry.TransactOpts, dimoCredit) -} - -// SetDimoStreamrNode is a paid mutator transaction binding the contract method 0x5f450e29. -// -// Solidity: function setDimoStreamrNode(address dimoStreamrNode) returns() -func (_Registry *RegistryTransactor) SetDimoStreamrNode(opts *bind.TransactOpts, dimoStreamrNode common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setDimoStreamrNode", dimoStreamrNode) -} - -// SetDimoStreamrNode is a paid mutator transaction binding the contract method 0x5f450e29. -// -// Solidity: function setDimoStreamrNode(address dimoStreamrNode) returns() -func (_Registry *RegistrySession) SetDimoStreamrNode(dimoStreamrNode common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetDimoStreamrNode(&_Registry.TransactOpts, dimoStreamrNode) -} - -// SetDimoStreamrNode is a paid mutator transaction binding the contract method 0x5f450e29. -// -// Solidity: function setDimoStreamrNode(address dimoStreamrNode) returns() -func (_Registry *RegistryTransactorSession) SetDimoStreamrNode(dimoStreamrNode common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetDimoStreamrNode(&_Registry.TransactOpts, dimoStreamrNode) -} - -// SetDimoToken is a paid mutator transaction binding the contract method 0x5b6c1979. -// -// Solidity: function setDimoToken(address dimoToken) returns() -func (_Registry *RegistryTransactor) SetDimoToken(opts *bind.TransactOpts, dimoToken common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setDimoToken", dimoToken) -} - -// SetDimoToken is a paid mutator transaction binding the contract method 0x5b6c1979. -// -// Solidity: function setDimoToken(address dimoToken) returns() -func (_Registry *RegistrySession) SetDimoToken(dimoToken common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetDimoToken(&_Registry.TransactOpts, dimoToken) -} - -// SetDimoToken is a paid mutator transaction binding the contract method 0x5b6c1979. -// -// Solidity: function setDimoToken(address dimoToken) returns() -func (_Registry *RegistryTransactorSession) SetDimoToken(dimoToken common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetDimoToken(&_Registry.TransactOpts, dimoToken) -} - -// SetFoundation is a paid mutator transaction binding the contract method 0xdb3543f5. -// -// Solidity: function setFoundation(address foundation) returns() -func (_Registry *RegistryTransactor) SetFoundation(opts *bind.TransactOpts, foundation common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setFoundation", foundation) -} - -// SetFoundation is a paid mutator transaction binding the contract method 0xdb3543f5. -// -// Solidity: function setFoundation(address foundation) returns() -func (_Registry *RegistrySession) SetFoundation(foundation common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetFoundation(&_Registry.TransactOpts, foundation) -} - -// SetFoundation is a paid mutator transaction binding the contract method 0xdb3543f5. -// -// Solidity: function setFoundation(address foundation) returns() -func (_Registry *RegistryTransactorSession) SetFoundation(foundation common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetFoundation(&_Registry.TransactOpts, foundation) -} - -// SetIntegrationController is a paid mutator transaction binding the contract method 0x106129aa. -// -// Solidity: function setIntegrationController(address _controller) returns() -func (_Registry *RegistryTransactor) SetIntegrationController(opts *bind.TransactOpts, _controller common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setIntegrationController", _controller) -} - -// SetIntegrationController is a paid mutator transaction binding the contract method 0x106129aa. -// -// Solidity: function setIntegrationController(address _controller) returns() -func (_Registry *RegistrySession) SetIntegrationController(_controller common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetIntegrationController(&_Registry.TransactOpts, _controller) -} - -// SetIntegrationController is a paid mutator transaction binding the contract method 0x106129aa. -// -// Solidity: function setIntegrationController(address _controller) returns() -func (_Registry *RegistryTransactorSession) SetIntegrationController(_controller common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetIntegrationController(&_Registry.TransactOpts, _controller) -} - -// SetIntegrationIdProxyAddress is a paid mutator transaction binding the contract method 0x636c1d1b. -// -// Solidity: function setIntegrationIdProxyAddress(address addr) returns() -func (_Registry *RegistryTransactor) SetIntegrationIdProxyAddress(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setIntegrationIdProxyAddress", addr) -} - -// SetIntegrationIdProxyAddress is a paid mutator transaction binding the contract method 0x636c1d1b. -// -// Solidity: function setIntegrationIdProxyAddress(address addr) returns() -func (_Registry *RegistrySession) SetIntegrationIdProxyAddress(addr common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetIntegrationIdProxyAddress(&_Registry.TransactOpts, addr) -} - -// SetIntegrationIdProxyAddress is a paid mutator transaction binding the contract method 0x636c1d1b. -// -// Solidity: function setIntegrationIdProxyAddress(address addr) returns() -func (_Registry *RegistryTransactorSession) SetIntegrationIdProxyAddress(addr common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetIntegrationIdProxyAddress(&_Registry.TransactOpts, addr) -} - -// SetIntegrationInfo is a paid mutator transaction binding the contract method 0x8d7e6001. -// -// Solidity: function setIntegrationInfo(uint256 tokenId, (string,string)[] attrInfoList) returns() -func (_Registry *RegistryTransactor) SetIntegrationInfo(opts *bind.TransactOpts, tokenId *big.Int, attrInfoList []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setIntegrationInfo", tokenId, attrInfoList) -} - -// SetIntegrationInfo is a paid mutator transaction binding the contract method 0x8d7e6001. -// -// Solidity: function setIntegrationInfo(uint256 tokenId, (string,string)[] attrInfoList) returns() -func (_Registry *RegistrySession) SetIntegrationInfo(tokenId *big.Int, attrInfoList []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.SetIntegrationInfo(&_Registry.TransactOpts, tokenId, attrInfoList) -} - -// SetIntegrationInfo is a paid mutator transaction binding the contract method 0x8d7e6001. -// -// Solidity: function setIntegrationInfo(uint256 tokenId, (string,string)[] attrInfoList) returns() -func (_Registry *RegistryTransactorSession) SetIntegrationInfo(tokenId *big.Int, attrInfoList []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.SetIntegrationInfo(&_Registry.TransactOpts, tokenId, attrInfoList) -} - -// SetManufacturerIdProxyAddress is a paid mutator transaction binding the contract method 0xd159f49a. -// -// Solidity: function setManufacturerIdProxyAddress(address addr) returns() -func (_Registry *RegistryTransactor) SetManufacturerIdProxyAddress(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setManufacturerIdProxyAddress", addr) -} - -// SetManufacturerIdProxyAddress is a paid mutator transaction binding the contract method 0xd159f49a. -// -// Solidity: function setManufacturerIdProxyAddress(address addr) returns() -func (_Registry *RegistrySession) SetManufacturerIdProxyAddress(addr common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetManufacturerIdProxyAddress(&_Registry.TransactOpts, addr) -} - -// SetManufacturerIdProxyAddress is a paid mutator transaction binding the contract method 0xd159f49a. -// -// Solidity: function setManufacturerIdProxyAddress(address addr) returns() -func (_Registry *RegistryTransactorSession) SetManufacturerIdProxyAddress(addr common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetManufacturerIdProxyAddress(&_Registry.TransactOpts, addr) -} - -// SetManufacturerInfo is a paid mutator transaction binding the contract method 0x63545ffa. -// -// Solidity: function setManufacturerInfo(uint256 tokenId, (string,string)[] attrInfoList) returns() -func (_Registry *RegistryTransactor) SetManufacturerInfo(opts *bind.TransactOpts, tokenId *big.Int, attrInfoList []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setManufacturerInfo", tokenId, attrInfoList) -} - -// SetManufacturerInfo is a paid mutator transaction binding the contract method 0x63545ffa. -// -// Solidity: function setManufacturerInfo(uint256 tokenId, (string,string)[] attrInfoList) returns() -func (_Registry *RegistrySession) SetManufacturerInfo(tokenId *big.Int, attrInfoList []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.SetManufacturerInfo(&_Registry.TransactOpts, tokenId, attrInfoList) -} - -// SetManufacturerInfo is a paid mutator transaction binding the contract method 0x63545ffa. -// -// Solidity: function setManufacturerInfo(uint256 tokenId, (string,string)[] attrInfoList) returns() -func (_Registry *RegistryTransactorSession) SetManufacturerInfo(tokenId *big.Int, attrInfoList []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.SetManufacturerInfo(&_Registry.TransactOpts, tokenId, attrInfoList) -} - -// SetManufacturerLicense is a paid mutator transaction binding the contract method 0xea9ae2f5. -// -// Solidity: function setManufacturerLicense(address manufacturerLicense) returns() -func (_Registry *RegistryTransactor) SetManufacturerLicense(opts *bind.TransactOpts, manufacturerLicense common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setManufacturerLicense", manufacturerLicense) -} - -// SetManufacturerLicense is a paid mutator transaction binding the contract method 0xea9ae2f5. -// -// Solidity: function setManufacturerLicense(address manufacturerLicense) returns() -func (_Registry *RegistrySession) SetManufacturerLicense(manufacturerLicense common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetManufacturerLicense(&_Registry.TransactOpts, manufacturerLicense) -} - -// SetManufacturerLicense is a paid mutator transaction binding the contract method 0xea9ae2f5. -// -// Solidity: function setManufacturerLicense(address manufacturerLicense) returns() -func (_Registry *RegistryTransactorSession) SetManufacturerLicense(manufacturerLicense common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetManufacturerLicense(&_Registry.TransactOpts, manufacturerLicense) -} - -// SetStreamRegistry is a paid mutator transaction binding the contract method 0x0c3cac3b. -// -// Solidity: function setStreamRegistry(address streamRegistry) returns() -func (_Registry *RegistryTransactor) SetStreamRegistry(opts *bind.TransactOpts, streamRegistry common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setStreamRegistry", streamRegistry) -} - -// SetStreamRegistry is a paid mutator transaction binding the contract method 0x0c3cac3b. -// -// Solidity: function setStreamRegistry(address streamRegistry) returns() -func (_Registry *RegistrySession) SetStreamRegistry(streamRegistry common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetStreamRegistry(&_Registry.TransactOpts, streamRegistry) -} - -// SetStreamRegistry is a paid mutator transaction binding the contract method 0x0c3cac3b. -// -// Solidity: function setStreamRegistry(address streamRegistry) returns() -func (_Registry *RegistryTransactorSession) SetStreamRegistry(streamRegistry common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetStreamRegistry(&_Registry.TransactOpts, streamRegistry) -} - -// SetSubscriptionToVehicleStream is a paid mutator transaction binding the contract method 0xbb44bb75. -// -// Solidity: function setSubscriptionToVehicleStream(uint256 vehicleId, address subscriber, uint256 expirationTime) returns() -func (_Registry *RegistryTransactor) SetSubscriptionToVehicleStream(opts *bind.TransactOpts, vehicleId *big.Int, subscriber common.Address, expirationTime *big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setSubscriptionToVehicleStream", vehicleId, subscriber, expirationTime) -} - -// SetSubscriptionToVehicleStream is a paid mutator transaction binding the contract method 0xbb44bb75. -// -// Solidity: function setSubscriptionToVehicleStream(uint256 vehicleId, address subscriber, uint256 expirationTime) returns() -func (_Registry *RegistrySession) SetSubscriptionToVehicleStream(vehicleId *big.Int, subscriber common.Address, expirationTime *big.Int) (*types.Transaction, error) { - return _Registry.Contract.SetSubscriptionToVehicleStream(&_Registry.TransactOpts, vehicleId, subscriber, expirationTime) -} - -// SetSubscriptionToVehicleStream is a paid mutator transaction binding the contract method 0xbb44bb75. -// -// Solidity: function setSubscriptionToVehicleStream(uint256 vehicleId, address subscriber, uint256 expirationTime) returns() -func (_Registry *RegistryTransactorSession) SetSubscriptionToVehicleStream(vehicleId *big.Int, subscriber common.Address, expirationTime *big.Int) (*types.Transaction, error) { - return _Registry.Contract.SetSubscriptionToVehicleStream(&_Registry.TransactOpts, vehicleId, subscriber, expirationTime) -} - -// SetSyntheticDeviceIdProxyAddress is a paid mutator transaction binding the contract method 0xecf452d7. -// -// Solidity: function setSyntheticDeviceIdProxyAddress(address addr) returns() -func (_Registry *RegistryTransactor) SetSyntheticDeviceIdProxyAddress(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setSyntheticDeviceIdProxyAddress", addr) -} - -// SetSyntheticDeviceIdProxyAddress is a paid mutator transaction binding the contract method 0xecf452d7. -// -// Solidity: function setSyntheticDeviceIdProxyAddress(address addr) returns() -func (_Registry *RegistrySession) SetSyntheticDeviceIdProxyAddress(addr common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetSyntheticDeviceIdProxyAddress(&_Registry.TransactOpts, addr) -} - -// SetSyntheticDeviceIdProxyAddress is a paid mutator transaction binding the contract method 0xecf452d7. -// -// Solidity: function setSyntheticDeviceIdProxyAddress(address addr) returns() -func (_Registry *RegistryTransactorSession) SetSyntheticDeviceIdProxyAddress(addr common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetSyntheticDeviceIdProxyAddress(&_Registry.TransactOpts, addr) -} - -// SetSyntheticDeviceInfo is a paid mutator transaction binding the contract method 0x80430e0d. -// -// Solidity: function setSyntheticDeviceInfo(uint256 tokenId, (string,string)[] attrInfo) returns() -func (_Registry *RegistryTransactor) SetSyntheticDeviceInfo(opts *bind.TransactOpts, tokenId *big.Int, attrInfo []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setSyntheticDeviceInfo", tokenId, attrInfo) -} - -// SetSyntheticDeviceInfo is a paid mutator transaction binding the contract method 0x80430e0d. -// -// Solidity: function setSyntheticDeviceInfo(uint256 tokenId, (string,string)[] attrInfo) returns() -func (_Registry *RegistrySession) SetSyntheticDeviceInfo(tokenId *big.Int, attrInfo []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.SetSyntheticDeviceInfo(&_Registry.TransactOpts, tokenId, attrInfo) -} - -// SetSyntheticDeviceInfo is a paid mutator transaction binding the contract method 0x80430e0d. -// -// Solidity: function setSyntheticDeviceInfo(uint256 tokenId, (string,string)[] attrInfo) returns() -func (_Registry *RegistryTransactorSession) SetSyntheticDeviceInfo(tokenId *big.Int, attrInfo []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.SetSyntheticDeviceInfo(&_Registry.TransactOpts, tokenId, attrInfo) -} - -// SetVehicleIdProxyAddress is a paid mutator transaction binding the contract method 0x9bfae6da. -// -// Solidity: function setVehicleIdProxyAddress(address addr) returns() -func (_Registry *RegistryTransactor) SetVehicleIdProxyAddress(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setVehicleIdProxyAddress", addr) -} - -// SetVehicleIdProxyAddress is a paid mutator transaction binding the contract method 0x9bfae6da. -// -// Solidity: function setVehicleIdProxyAddress(address addr) returns() -func (_Registry *RegistrySession) SetVehicleIdProxyAddress(addr common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetVehicleIdProxyAddress(&_Registry.TransactOpts, addr) -} - -// SetVehicleIdProxyAddress is a paid mutator transaction binding the contract method 0x9bfae6da. -// -// Solidity: function setVehicleIdProxyAddress(address addr) returns() -func (_Registry *RegistryTransactorSession) SetVehicleIdProxyAddress(addr common.Address) (*types.Transaction, error) { - return _Registry.Contract.SetVehicleIdProxyAddress(&_Registry.TransactOpts, addr) -} - -// SetVehicleInfo is a paid mutator transaction binding the contract method 0xd9c3ae61. -// -// Solidity: function setVehicleInfo(uint256 tokenId, (string,string)[] attrInfo) returns() -func (_Registry *RegistryTransactor) SetVehicleInfo(opts *bind.TransactOpts, tokenId *big.Int, attrInfo []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setVehicleInfo", tokenId, attrInfo) -} - -// SetVehicleInfo is a paid mutator transaction binding the contract method 0xd9c3ae61. -// -// Solidity: function setVehicleInfo(uint256 tokenId, (string,string)[] attrInfo) returns() -func (_Registry *RegistrySession) SetVehicleInfo(tokenId *big.Int, attrInfo []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.SetVehicleInfo(&_Registry.TransactOpts, tokenId, attrInfo) -} - -// SetVehicleInfo is a paid mutator transaction binding the contract method 0xd9c3ae61. -// -// Solidity: function setVehicleInfo(uint256 tokenId, (string,string)[] attrInfo) returns() -func (_Registry *RegistryTransactorSession) SetVehicleInfo(tokenId *big.Int, attrInfo []AttributeInfoPair) (*types.Transaction, error) { - return _Registry.Contract.SetVehicleInfo(&_Registry.TransactOpts, tokenId, attrInfo) -} - -// SetVehicleStream is a paid mutator transaction binding the contract method 0x6f58f093. -// -// Solidity: function setVehicleStream(uint256 vehicleId, string streamId) returns() -func (_Registry *RegistryTransactor) SetVehicleStream(opts *bind.TransactOpts, vehicleId *big.Int, streamId string) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "setVehicleStream", vehicleId, streamId) -} - -// SetVehicleStream is a paid mutator transaction binding the contract method 0x6f58f093. -// -// Solidity: function setVehicleStream(uint256 vehicleId, string streamId) returns() -func (_Registry *RegistrySession) SetVehicleStream(vehicleId *big.Int, streamId string) (*types.Transaction, error) { - return _Registry.Contract.SetVehicleStream(&_Registry.TransactOpts, vehicleId, streamId) -} - -// SetVehicleStream is a paid mutator transaction binding the contract method 0x6f58f093. -// -// Solidity: function setVehicleStream(uint256 vehicleId, string streamId) returns() -func (_Registry *RegistryTransactorSession) SetVehicleStream(vehicleId *big.Int, streamId string) (*types.Transaction, error) { - return _Registry.Contract.SetVehicleStream(&_Registry.TransactOpts, vehicleId, streamId) -} - -// SubscribeToVehicleStream is a paid mutator transaction binding the contract method 0x37479f7e. -// -// Solidity: function subscribeToVehicleStream(uint256 vehicleId, uint256 expirationTime) returns() -func (_Registry *RegistryTransactor) SubscribeToVehicleStream(opts *bind.TransactOpts, vehicleId *big.Int, expirationTime *big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "subscribeToVehicleStream", vehicleId, expirationTime) -} - -// SubscribeToVehicleStream is a paid mutator transaction binding the contract method 0x37479f7e. -// -// Solidity: function subscribeToVehicleStream(uint256 vehicleId, uint256 expirationTime) returns() -func (_Registry *RegistrySession) SubscribeToVehicleStream(vehicleId *big.Int, expirationTime *big.Int) (*types.Transaction, error) { - return _Registry.Contract.SubscribeToVehicleStream(&_Registry.TransactOpts, vehicleId, expirationTime) -} - -// SubscribeToVehicleStream is a paid mutator transaction binding the contract method 0x37479f7e. -// -// Solidity: function subscribeToVehicleStream(uint256 vehicleId, uint256 expirationTime) returns() -func (_Registry *RegistryTransactorSession) SubscribeToVehicleStream(vehicleId *big.Int, expirationTime *big.Int) (*types.Transaction, error) { - return _Registry.Contract.SubscribeToVehicleStream(&_Registry.TransactOpts, vehicleId, expirationTime) -} - -// TransferAftermarketDeviceOwnership is a paid mutator transaction binding the contract method 0xff96b761. -// -// Solidity: function transferAftermarketDeviceOwnership(uint256 aftermarketDeviceNode, address newOwner) returns() -func (_Registry *RegistryTransactor) TransferAftermarketDeviceOwnership(opts *bind.TransactOpts, aftermarketDeviceNode *big.Int, newOwner common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "transferAftermarketDeviceOwnership", aftermarketDeviceNode, newOwner) -} - -// TransferAftermarketDeviceOwnership is a paid mutator transaction binding the contract method 0xff96b761. -// -// Solidity: function transferAftermarketDeviceOwnership(uint256 aftermarketDeviceNode, address newOwner) returns() -func (_Registry *RegistrySession) TransferAftermarketDeviceOwnership(aftermarketDeviceNode *big.Int, newOwner common.Address) (*types.Transaction, error) { - return _Registry.Contract.TransferAftermarketDeviceOwnership(&_Registry.TransactOpts, aftermarketDeviceNode, newOwner) -} - -// TransferAftermarketDeviceOwnership is a paid mutator transaction binding the contract method 0xff96b761. -// -// Solidity: function transferAftermarketDeviceOwnership(uint256 aftermarketDeviceNode, address newOwner) returns() -func (_Registry *RegistryTransactorSession) TransferAftermarketDeviceOwnership(aftermarketDeviceNode *big.Int, newOwner common.Address) (*types.Transaction, error) { - return _Registry.Contract.TransferAftermarketDeviceOwnership(&_Registry.TransactOpts, aftermarketDeviceNode, newOwner) -} - -// UnclaimAftermarketDeviceNode is a paid mutator transaction binding the contract method 0x5c129493. -// -// Solidity: function unclaimAftermarketDeviceNode(uint256[] aftermarketDeviceNodes) returns() -func (_Registry *RegistryTransactor) UnclaimAftermarketDeviceNode(opts *bind.TransactOpts, aftermarketDeviceNodes []*big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "unclaimAftermarketDeviceNode", aftermarketDeviceNodes) -} - -// UnclaimAftermarketDeviceNode is a paid mutator transaction binding the contract method 0x5c129493. -// -// Solidity: function unclaimAftermarketDeviceNode(uint256[] aftermarketDeviceNodes) returns() -func (_Registry *RegistrySession) UnclaimAftermarketDeviceNode(aftermarketDeviceNodes []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.UnclaimAftermarketDeviceNode(&_Registry.TransactOpts, aftermarketDeviceNodes) -} - -// UnclaimAftermarketDeviceNode is a paid mutator transaction binding the contract method 0x5c129493. -// -// Solidity: function unclaimAftermarketDeviceNode(uint256[] aftermarketDeviceNodes) returns() -func (_Registry *RegistryTransactorSession) UnclaimAftermarketDeviceNode(aftermarketDeviceNodes []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.UnclaimAftermarketDeviceNode(&_Registry.TransactOpts, aftermarketDeviceNodes) -} - -// UnpairAftermarketDevice is a paid mutator transaction binding the contract method 0xee4d9596. -// -// Solidity: function unpairAftermarketDevice(uint256 aftermarketDeviceNode, uint256 vehicleNode) returns() -func (_Registry *RegistryTransactor) UnpairAftermarketDevice(opts *bind.TransactOpts, aftermarketDeviceNode *big.Int, vehicleNode *big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "unpairAftermarketDevice", aftermarketDeviceNode, vehicleNode) -} - -// UnpairAftermarketDevice is a paid mutator transaction binding the contract method 0xee4d9596. -// -// Solidity: function unpairAftermarketDevice(uint256 aftermarketDeviceNode, uint256 vehicleNode) returns() -func (_Registry *RegistrySession) UnpairAftermarketDevice(aftermarketDeviceNode *big.Int, vehicleNode *big.Int) (*types.Transaction, error) { - return _Registry.Contract.UnpairAftermarketDevice(&_Registry.TransactOpts, aftermarketDeviceNode, vehicleNode) -} - -// UnpairAftermarketDevice is a paid mutator transaction binding the contract method 0xee4d9596. -// -// Solidity: function unpairAftermarketDevice(uint256 aftermarketDeviceNode, uint256 vehicleNode) returns() -func (_Registry *RegistryTransactorSession) UnpairAftermarketDevice(aftermarketDeviceNode *big.Int, vehicleNode *big.Int) (*types.Transaction, error) { - return _Registry.Contract.UnpairAftermarketDevice(&_Registry.TransactOpts, aftermarketDeviceNode, vehicleNode) -} - -// UnpairAftermarketDeviceByDeviceNode is a paid mutator transaction binding the contract method 0x71193956. -// -// Solidity: function unpairAftermarketDeviceByDeviceNode(uint256[] aftermarketDeviceNodes) returns() -func (_Registry *RegistryTransactor) UnpairAftermarketDeviceByDeviceNode(opts *bind.TransactOpts, aftermarketDeviceNodes []*big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "unpairAftermarketDeviceByDeviceNode", aftermarketDeviceNodes) -} - -// UnpairAftermarketDeviceByDeviceNode is a paid mutator transaction binding the contract method 0x71193956. -// -// Solidity: function unpairAftermarketDeviceByDeviceNode(uint256[] aftermarketDeviceNodes) returns() -func (_Registry *RegistrySession) UnpairAftermarketDeviceByDeviceNode(aftermarketDeviceNodes []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.UnpairAftermarketDeviceByDeviceNode(&_Registry.TransactOpts, aftermarketDeviceNodes) -} - -// UnpairAftermarketDeviceByDeviceNode is a paid mutator transaction binding the contract method 0x71193956. -// -// Solidity: function unpairAftermarketDeviceByDeviceNode(uint256[] aftermarketDeviceNodes) returns() -func (_Registry *RegistryTransactorSession) UnpairAftermarketDeviceByDeviceNode(aftermarketDeviceNodes []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.UnpairAftermarketDeviceByDeviceNode(&_Registry.TransactOpts, aftermarketDeviceNodes) -} - -// UnpairAftermarketDeviceByVehicleNode is a paid mutator transaction binding the contract method 0x8c2ee9bb. -// -// Solidity: function unpairAftermarketDeviceByVehicleNode(uint256[] vehicleNodes) returns() -func (_Registry *RegistryTransactor) UnpairAftermarketDeviceByVehicleNode(opts *bind.TransactOpts, vehicleNodes []*big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "unpairAftermarketDeviceByVehicleNode", vehicleNodes) -} - -// UnpairAftermarketDeviceByVehicleNode is a paid mutator transaction binding the contract method 0x8c2ee9bb. -// -// Solidity: function unpairAftermarketDeviceByVehicleNode(uint256[] vehicleNodes) returns() -func (_Registry *RegistrySession) UnpairAftermarketDeviceByVehicleNode(vehicleNodes []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.UnpairAftermarketDeviceByVehicleNode(&_Registry.TransactOpts, vehicleNodes) -} - -// UnpairAftermarketDeviceByVehicleNode is a paid mutator transaction binding the contract method 0x8c2ee9bb. -// -// Solidity: function unpairAftermarketDeviceByVehicleNode(uint256[] vehicleNodes) returns() -func (_Registry *RegistryTransactorSession) UnpairAftermarketDeviceByVehicleNode(vehicleNodes []*big.Int) (*types.Transaction, error) { - return _Registry.Contract.UnpairAftermarketDeviceByVehicleNode(&_Registry.TransactOpts, vehicleNodes) -} - -// UnpairAftermarketDeviceSign is a paid mutator transaction binding the contract method 0x3f65997a. -// -// Solidity: function unpairAftermarketDeviceSign(uint256 aftermarketDeviceNode, uint256 vehicleNode, bytes signature) returns() -func (_Registry *RegistryTransactor) UnpairAftermarketDeviceSign(opts *bind.TransactOpts, aftermarketDeviceNode *big.Int, vehicleNode *big.Int, signature []byte) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "unpairAftermarketDeviceSign", aftermarketDeviceNode, vehicleNode, signature) -} - -// UnpairAftermarketDeviceSign is a paid mutator transaction binding the contract method 0x3f65997a. -// -// Solidity: function unpairAftermarketDeviceSign(uint256 aftermarketDeviceNode, uint256 vehicleNode, bytes signature) returns() -func (_Registry *RegistrySession) UnpairAftermarketDeviceSign(aftermarketDeviceNode *big.Int, vehicleNode *big.Int, signature []byte) (*types.Transaction, error) { - return _Registry.Contract.UnpairAftermarketDeviceSign(&_Registry.TransactOpts, aftermarketDeviceNode, vehicleNode, signature) -} - -// UnpairAftermarketDeviceSign is a paid mutator transaction binding the contract method 0x3f65997a. -// -// Solidity: function unpairAftermarketDeviceSign(uint256 aftermarketDeviceNode, uint256 vehicleNode, bytes signature) returns() -func (_Registry *RegistryTransactorSession) UnpairAftermarketDeviceSign(aftermarketDeviceNode *big.Int, vehicleNode *big.Int, signature []byte) (*types.Transaction, error) { - return _Registry.Contract.UnpairAftermarketDeviceSign(&_Registry.TransactOpts, aftermarketDeviceNode, vehicleNode, signature) -} - -// UnsetVehicleStream is a paid mutator transaction binding the contract method 0xcd90df7e. -// -// Solidity: function unsetVehicleStream(uint256 vehicleId) returns() -func (_Registry *RegistryTransactor) UnsetVehicleStream(opts *bind.TransactOpts, vehicleId *big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "unsetVehicleStream", vehicleId) -} - -// UnsetVehicleStream is a paid mutator transaction binding the contract method 0xcd90df7e. -// -// Solidity: function unsetVehicleStream(uint256 vehicleId) returns() -func (_Registry *RegistrySession) UnsetVehicleStream(vehicleId *big.Int) (*types.Transaction, error) { - return _Registry.Contract.UnsetVehicleStream(&_Registry.TransactOpts, vehicleId) -} - -// UnsetVehicleStream is a paid mutator transaction binding the contract method 0xcd90df7e. -// -// Solidity: function unsetVehicleStream(uint256 vehicleId) returns() -func (_Registry *RegistryTransactorSession) UnsetVehicleStream(vehicleId *big.Int) (*types.Transaction, error) { - return _Registry.Contract.UnsetVehicleStream(&_Registry.TransactOpts, vehicleId) -} - -// UpdateDeviceDefinition is a paid mutator transaction binding the contract method 0x182fef60. -// -// Solidity: function updateDeviceDefinition(uint256 manufacturerId, (string,string,string,string,string) data) returns() -func (_Registry *RegistryTransactor) UpdateDeviceDefinition(opts *bind.TransactOpts, manufacturerId *big.Int, data DeviceDefinitionUpdateInput) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "updateDeviceDefinition", manufacturerId, data) -} - -// UpdateDeviceDefinition is a paid mutator transaction binding the contract method 0x182fef60. -// -// Solidity: function updateDeviceDefinition(uint256 manufacturerId, (string,string,string,string,string) data) returns() -func (_Registry *RegistrySession) UpdateDeviceDefinition(manufacturerId *big.Int, data DeviceDefinitionUpdateInput) (*types.Transaction, error) { - return _Registry.Contract.UpdateDeviceDefinition(&_Registry.TransactOpts, manufacturerId, data) -} - -// UpdateDeviceDefinition is a paid mutator transaction binding the contract method 0x182fef60. -// -// Solidity: function updateDeviceDefinition(uint256 manufacturerId, (string,string,string,string,string) data) returns() -func (_Registry *RegistryTransactorSession) UpdateDeviceDefinition(manufacturerId *big.Int, data DeviceDefinitionUpdateInput) (*types.Transaction, error) { - return _Registry.Contract.UpdateDeviceDefinition(&_Registry.TransactOpts, manufacturerId, data) -} - -// UpdateIntegrationMinted is a paid mutator transaction binding the contract method 0x440707b5. -// -// Solidity: function updateIntegrationMinted(address from, address to) returns() -func (_Registry *RegistryTransactor) UpdateIntegrationMinted(opts *bind.TransactOpts, from common.Address, to common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "updateIntegrationMinted", from, to) -} - -// UpdateIntegrationMinted is a paid mutator transaction binding the contract method 0x440707b5. -// -// Solidity: function updateIntegrationMinted(address from, address to) returns() -func (_Registry *RegistrySession) UpdateIntegrationMinted(from common.Address, to common.Address) (*types.Transaction, error) { - return _Registry.Contract.UpdateIntegrationMinted(&_Registry.TransactOpts, from, to) -} - -// UpdateIntegrationMinted is a paid mutator transaction binding the contract method 0x440707b5. -// -// Solidity: function updateIntegrationMinted(address from, address to) returns() -func (_Registry *RegistryTransactorSession) UpdateIntegrationMinted(from common.Address, to common.Address) (*types.Transaction, error) { - return _Registry.Contract.UpdateIntegrationMinted(&_Registry.TransactOpts, from, to) -} - -// UpdateManufacturerMinted is a paid mutator transaction binding the contract method 0x20d60248. -// -// Solidity: function updateManufacturerMinted(address from, address to) returns() -func (_Registry *RegistryTransactor) UpdateManufacturerMinted(opts *bind.TransactOpts, from common.Address, to common.Address) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "updateManufacturerMinted", from, to) -} - -// UpdateManufacturerMinted is a paid mutator transaction binding the contract method 0x20d60248. -// -// Solidity: function updateManufacturerMinted(address from, address to) returns() -func (_Registry *RegistrySession) UpdateManufacturerMinted(from common.Address, to common.Address) (*types.Transaction, error) { - return _Registry.Contract.UpdateManufacturerMinted(&_Registry.TransactOpts, from, to) -} - -// UpdateManufacturerMinted is a paid mutator transaction binding the contract method 0x20d60248. -// -// Solidity: function updateManufacturerMinted(address from, address to) returns() -func (_Registry *RegistryTransactorSession) UpdateManufacturerMinted(from common.Address, to common.Address) (*types.Transaction, error) { - return _Registry.Contract.UpdateManufacturerMinted(&_Registry.TransactOpts, from, to) -} - -// UpdateModule is a paid mutator transaction binding the contract method 0x06d1d2a1. -// -// Solidity: function updateModule(address oldImplementation, address newImplementation, bytes4[] oldSelectors, bytes4[] newSelectors) returns() -func (_Registry *RegistryTransactor) UpdateModule(opts *bind.TransactOpts, oldImplementation common.Address, newImplementation common.Address, oldSelectors [][4]byte, newSelectors [][4]byte) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "updateModule", oldImplementation, newImplementation, oldSelectors, newSelectors) -} - -// UpdateModule is a paid mutator transaction binding the contract method 0x06d1d2a1. -// -// Solidity: function updateModule(address oldImplementation, address newImplementation, bytes4[] oldSelectors, bytes4[] newSelectors) returns() -func (_Registry *RegistrySession) UpdateModule(oldImplementation common.Address, newImplementation common.Address, oldSelectors [][4]byte, newSelectors [][4]byte) (*types.Transaction, error) { - return _Registry.Contract.UpdateModule(&_Registry.TransactOpts, oldImplementation, newImplementation, oldSelectors, newSelectors) -} - -// UpdateModule is a paid mutator transaction binding the contract method 0x06d1d2a1. -// -// Solidity: function updateModule(address oldImplementation, address newImplementation, bytes4[] oldSelectors, bytes4[] newSelectors) returns() -func (_Registry *RegistryTransactorSession) UpdateModule(oldImplementation common.Address, newImplementation common.Address, oldSelectors [][4]byte, newSelectors [][4]byte) (*types.Transaction, error) { - return _Registry.Contract.UpdateModule(&_Registry.TransactOpts, oldImplementation, newImplementation, oldSelectors, newSelectors) -} - -// ValidateBurnAndResetNode is a paid mutator transaction binding the contract method 0xea0e7d3a. -// -// Solidity: function validateBurnAndResetNode(uint256 tokenId) returns() -func (_Registry *RegistryTransactor) ValidateBurnAndResetNode(opts *bind.TransactOpts, tokenId *big.Int) (*types.Transaction, error) { - return _Registry.contract.Transact(opts, "validateBurnAndResetNode", tokenId) -} - -// ValidateBurnAndResetNode is a paid mutator transaction binding the contract method 0xea0e7d3a. -// -// Solidity: function validateBurnAndResetNode(uint256 tokenId) returns() -func (_Registry *RegistrySession) ValidateBurnAndResetNode(tokenId *big.Int) (*types.Transaction, error) { - return _Registry.Contract.ValidateBurnAndResetNode(&_Registry.TransactOpts, tokenId) -} - -// ValidateBurnAndResetNode is a paid mutator transaction binding the contract method 0xea0e7d3a. -// -// Solidity: function validateBurnAndResetNode(uint256 tokenId) returns() -func (_Registry *RegistryTransactorSession) ValidateBurnAndResetNode(tokenId *big.Int) (*types.Transaction, error) { - return _Registry.Contract.ValidateBurnAndResetNode(&_Registry.TransactOpts, tokenId) -} - -// Fallback is a paid mutator transaction binding the contract fallback function. -// -// Solidity: fallback() returns() -func (_Registry *RegistryTransactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { - return _Registry.contract.RawTransact(opts, calldata) -} - -// Fallback is a paid mutator transaction binding the contract fallback function. -// -// Solidity: fallback() returns() -func (_Registry *RegistrySession) Fallback(calldata []byte) (*types.Transaction, error) { - return _Registry.Contract.Fallback(&_Registry.TransactOpts, calldata) -} - -// Fallback is a paid mutator transaction binding the contract fallback function. -// -// Solidity: fallback() returns() -func (_Registry *RegistryTransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { - return _Registry.Contract.Fallback(&_Registry.TransactOpts, calldata) -} - -// RegistryAftermarketDeviceAddressResetIterator is returned from FilterAftermarketDeviceAddressReset and is used to iterate over the raw logs and unpacked data for AftermarketDeviceAddressReset events raised by the Registry contract. -type RegistryAftermarketDeviceAddressResetIterator struct { - Event *RegistryAftermarketDeviceAddressReset // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryAftermarketDeviceAddressResetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceAddressReset) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceAddressReset) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryAftermarketDeviceAddressResetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryAftermarketDeviceAddressResetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryAftermarketDeviceAddressReset represents a AftermarketDeviceAddressReset event raised by the Registry contract. -type RegistryAftermarketDeviceAddressReset struct { - ManufacturerId *big.Int - TokenId *big.Int - AftermarketDeviceAddress common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAftermarketDeviceAddressReset is a free log retrieval operation binding the contract event 0x4993b53bba9fe570bd465464126bb5be93bd1504db0060ed2b7cd89f5a32b6be. -// -// Solidity: event AftermarketDeviceAddressReset(uint256 indexed manufacturerId, uint256 indexed tokenId, address indexed aftermarketDeviceAddress) -func (_Registry *RegistryFilterer) FilterAftermarketDeviceAddressReset(opts *bind.FilterOpts, manufacturerId []*big.Int, tokenId []*big.Int, aftermarketDeviceAddress []common.Address) (*RegistryAftermarketDeviceAddressResetIterator, error) { - - var manufacturerIdRule []interface{} - for _, manufacturerIdItem := range manufacturerId { - manufacturerIdRule = append(manufacturerIdRule, manufacturerIdItem) - } - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - var aftermarketDeviceAddressRule []interface{} - for _, aftermarketDeviceAddressItem := range aftermarketDeviceAddress { - aftermarketDeviceAddressRule = append(aftermarketDeviceAddressRule, aftermarketDeviceAddressItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "AftermarketDeviceAddressReset", manufacturerIdRule, tokenIdRule, aftermarketDeviceAddressRule) - if err != nil { - return nil, err - } - return &RegistryAftermarketDeviceAddressResetIterator{contract: _Registry.contract, event: "AftermarketDeviceAddressReset", logs: logs, sub: sub}, nil -} - -// WatchAftermarketDeviceAddressReset is a free log subscription operation binding the contract event 0x4993b53bba9fe570bd465464126bb5be93bd1504db0060ed2b7cd89f5a32b6be. -// -// Solidity: event AftermarketDeviceAddressReset(uint256 indexed manufacturerId, uint256 indexed tokenId, address indexed aftermarketDeviceAddress) -func (_Registry *RegistryFilterer) WatchAftermarketDeviceAddressReset(opts *bind.WatchOpts, sink chan<- *RegistryAftermarketDeviceAddressReset, manufacturerId []*big.Int, tokenId []*big.Int, aftermarketDeviceAddress []common.Address) (event.Subscription, error) { - - var manufacturerIdRule []interface{} - for _, manufacturerIdItem := range manufacturerId { - manufacturerIdRule = append(manufacturerIdRule, manufacturerIdItem) - } - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - var aftermarketDeviceAddressRule []interface{} - for _, aftermarketDeviceAddressItem := range aftermarketDeviceAddress { - aftermarketDeviceAddressRule = append(aftermarketDeviceAddressRule, aftermarketDeviceAddressItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "AftermarketDeviceAddressReset", manufacturerIdRule, tokenIdRule, aftermarketDeviceAddressRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryAftermarketDeviceAddressReset) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceAddressReset", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseAftermarketDeviceAddressReset is a log parse operation binding the contract event 0x4993b53bba9fe570bd465464126bb5be93bd1504db0060ed2b7cd89f5a32b6be. -// -// Solidity: event AftermarketDeviceAddressReset(uint256 indexed manufacturerId, uint256 indexed tokenId, address indexed aftermarketDeviceAddress) -func (_Registry *RegistryFilterer) ParseAftermarketDeviceAddressReset(log types.Log) (*RegistryAftermarketDeviceAddressReset, error) { - event := new(RegistryAftermarketDeviceAddressReset) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceAddressReset", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryAftermarketDeviceAttributeAddedIterator is returned from FilterAftermarketDeviceAttributeAdded and is used to iterate over the raw logs and unpacked data for AftermarketDeviceAttributeAdded events raised by the Registry contract. -type RegistryAftermarketDeviceAttributeAddedIterator struct { - Event *RegistryAftermarketDeviceAttributeAdded // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryAftermarketDeviceAttributeAddedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceAttributeAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceAttributeAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryAftermarketDeviceAttributeAddedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryAftermarketDeviceAttributeAddedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryAftermarketDeviceAttributeAdded represents a AftermarketDeviceAttributeAdded event raised by the Registry contract. -type RegistryAftermarketDeviceAttributeAdded struct { - Attribute string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAftermarketDeviceAttributeAdded is a free log retrieval operation binding the contract event 0x3ef2473cbfb66e153539befafe6ba95e95c6cc0659ebc0d7e8a56f014de7eb5f. -// -// Solidity: event AftermarketDeviceAttributeAdded(string attribute) -func (_Registry *RegistryFilterer) FilterAftermarketDeviceAttributeAdded(opts *bind.FilterOpts) (*RegistryAftermarketDeviceAttributeAddedIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "AftermarketDeviceAttributeAdded") - if err != nil { - return nil, err - } - return &RegistryAftermarketDeviceAttributeAddedIterator{contract: _Registry.contract, event: "AftermarketDeviceAttributeAdded", logs: logs, sub: sub}, nil -} - -// WatchAftermarketDeviceAttributeAdded is a free log subscription operation binding the contract event 0x3ef2473cbfb66e153539befafe6ba95e95c6cc0659ebc0d7e8a56f014de7eb5f. -// -// Solidity: event AftermarketDeviceAttributeAdded(string attribute) -func (_Registry *RegistryFilterer) WatchAftermarketDeviceAttributeAdded(opts *bind.WatchOpts, sink chan<- *RegistryAftermarketDeviceAttributeAdded) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "AftermarketDeviceAttributeAdded") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryAftermarketDeviceAttributeAdded) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceAttributeAdded", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseAftermarketDeviceAttributeAdded is a log parse operation binding the contract event 0x3ef2473cbfb66e153539befafe6ba95e95c6cc0659ebc0d7e8a56f014de7eb5f. -// -// Solidity: event AftermarketDeviceAttributeAdded(string attribute) -func (_Registry *RegistryFilterer) ParseAftermarketDeviceAttributeAdded(log types.Log) (*RegistryAftermarketDeviceAttributeAdded, error) { - event := new(RegistryAftermarketDeviceAttributeAdded) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceAttributeAdded", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryAftermarketDeviceAttributeSetIterator is returned from FilterAftermarketDeviceAttributeSet and is used to iterate over the raw logs and unpacked data for AftermarketDeviceAttributeSet events raised by the Registry contract. -type RegistryAftermarketDeviceAttributeSetIterator struct { - Event *RegistryAftermarketDeviceAttributeSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryAftermarketDeviceAttributeSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceAttributeSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceAttributeSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryAftermarketDeviceAttributeSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryAftermarketDeviceAttributeSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryAftermarketDeviceAttributeSet represents a AftermarketDeviceAttributeSet event raised by the Registry contract. -type RegistryAftermarketDeviceAttributeSet struct { - TokenId *big.Int - Attribute string - Info string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAftermarketDeviceAttributeSet is a free log retrieval operation binding the contract event 0x977fe0ddf8485988af0b93d70bf5977b48236e9969cdb9b1f55977fbab7cd417. -// -// Solidity: event AftermarketDeviceAttributeSet(uint256 tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) FilterAftermarketDeviceAttributeSet(opts *bind.FilterOpts) (*RegistryAftermarketDeviceAttributeSetIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "AftermarketDeviceAttributeSet") - if err != nil { - return nil, err - } - return &RegistryAftermarketDeviceAttributeSetIterator{contract: _Registry.contract, event: "AftermarketDeviceAttributeSet", logs: logs, sub: sub}, nil -} - -// WatchAftermarketDeviceAttributeSet is a free log subscription operation binding the contract event 0x977fe0ddf8485988af0b93d70bf5977b48236e9969cdb9b1f55977fbab7cd417. -// -// Solidity: event AftermarketDeviceAttributeSet(uint256 tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) WatchAftermarketDeviceAttributeSet(opts *bind.WatchOpts, sink chan<- *RegistryAftermarketDeviceAttributeSet) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "AftermarketDeviceAttributeSet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryAftermarketDeviceAttributeSet) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceAttributeSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseAftermarketDeviceAttributeSet is a log parse operation binding the contract event 0x977fe0ddf8485988af0b93d70bf5977b48236e9969cdb9b1f55977fbab7cd417. -// -// Solidity: event AftermarketDeviceAttributeSet(uint256 tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) ParseAftermarketDeviceAttributeSet(log types.Log) (*RegistryAftermarketDeviceAttributeSet, error) { - event := new(RegistryAftermarketDeviceAttributeSet) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceAttributeSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryAftermarketDeviceAttributeSetDevAdminIterator is returned from FilterAftermarketDeviceAttributeSetDevAdmin and is used to iterate over the raw logs and unpacked data for AftermarketDeviceAttributeSetDevAdmin events raised by the Registry contract. -type RegistryAftermarketDeviceAttributeSetDevAdminIterator struct { - Event *RegistryAftermarketDeviceAttributeSetDevAdmin // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryAftermarketDeviceAttributeSetDevAdminIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceAttributeSetDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceAttributeSetDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryAftermarketDeviceAttributeSetDevAdminIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryAftermarketDeviceAttributeSetDevAdminIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryAftermarketDeviceAttributeSetDevAdmin represents a AftermarketDeviceAttributeSetDevAdmin event raised by the Registry contract. -type RegistryAftermarketDeviceAttributeSetDevAdmin struct { - TokenId *big.Int - Attribute string - Info string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAftermarketDeviceAttributeSetDevAdmin is a free log retrieval operation binding the contract event 0x000d5c453b5e43761f8a52bf98395d56422aaaebab0f8bcf44ac3c1627276b45. -// -// Solidity: event AftermarketDeviceAttributeSetDevAdmin(uint256 indexed tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) FilterAftermarketDeviceAttributeSetDevAdmin(opts *bind.FilterOpts, tokenId []*big.Int) (*RegistryAftermarketDeviceAttributeSetDevAdminIterator, error) { - - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "AftermarketDeviceAttributeSetDevAdmin", tokenIdRule) - if err != nil { - return nil, err - } - return &RegistryAftermarketDeviceAttributeSetDevAdminIterator{contract: _Registry.contract, event: "AftermarketDeviceAttributeSetDevAdmin", logs: logs, sub: sub}, nil -} - -// WatchAftermarketDeviceAttributeSetDevAdmin is a free log subscription operation binding the contract event 0x000d5c453b5e43761f8a52bf98395d56422aaaebab0f8bcf44ac3c1627276b45. -// -// Solidity: event AftermarketDeviceAttributeSetDevAdmin(uint256 indexed tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) WatchAftermarketDeviceAttributeSetDevAdmin(opts *bind.WatchOpts, sink chan<- *RegistryAftermarketDeviceAttributeSetDevAdmin, tokenId []*big.Int) (event.Subscription, error) { - - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "AftermarketDeviceAttributeSetDevAdmin", tokenIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryAftermarketDeviceAttributeSetDevAdmin) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceAttributeSetDevAdmin", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseAftermarketDeviceAttributeSetDevAdmin is a log parse operation binding the contract event 0x000d5c453b5e43761f8a52bf98395d56422aaaebab0f8bcf44ac3c1627276b45. -// -// Solidity: event AftermarketDeviceAttributeSetDevAdmin(uint256 indexed tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) ParseAftermarketDeviceAttributeSetDevAdmin(log types.Log) (*RegistryAftermarketDeviceAttributeSetDevAdmin, error) { - event := new(RegistryAftermarketDeviceAttributeSetDevAdmin) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceAttributeSetDevAdmin", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryAftermarketDeviceClaimedIterator is returned from FilterAftermarketDeviceClaimed and is used to iterate over the raw logs and unpacked data for AftermarketDeviceClaimed events raised by the Registry contract. -type RegistryAftermarketDeviceClaimedIterator struct { - Event *RegistryAftermarketDeviceClaimed // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryAftermarketDeviceClaimedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceClaimed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceClaimed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryAftermarketDeviceClaimedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryAftermarketDeviceClaimedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryAftermarketDeviceClaimed represents a AftermarketDeviceClaimed event raised by the Registry contract. -type RegistryAftermarketDeviceClaimed struct { - AftermarketDeviceNode *big.Int - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAftermarketDeviceClaimed is a free log retrieval operation binding the contract event 0x8468d811e5090d3b1a07e28af524e66c128f624e16b07638f419012c779f76ec. -// -// Solidity: event AftermarketDeviceClaimed(uint256 aftermarketDeviceNode, address indexed owner) -func (_Registry *RegistryFilterer) FilterAftermarketDeviceClaimed(opts *bind.FilterOpts, owner []common.Address) (*RegistryAftermarketDeviceClaimedIterator, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "AftermarketDeviceClaimed", ownerRule) - if err != nil { - return nil, err - } - return &RegistryAftermarketDeviceClaimedIterator{contract: _Registry.contract, event: "AftermarketDeviceClaimed", logs: logs, sub: sub}, nil -} - -// WatchAftermarketDeviceClaimed is a free log subscription operation binding the contract event 0x8468d811e5090d3b1a07e28af524e66c128f624e16b07638f419012c779f76ec. -// -// Solidity: event AftermarketDeviceClaimed(uint256 aftermarketDeviceNode, address indexed owner) -func (_Registry *RegistryFilterer) WatchAftermarketDeviceClaimed(opts *bind.WatchOpts, sink chan<- *RegistryAftermarketDeviceClaimed, owner []common.Address) (event.Subscription, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "AftermarketDeviceClaimed", ownerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryAftermarketDeviceClaimed) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceClaimed", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseAftermarketDeviceClaimed is a log parse operation binding the contract event 0x8468d811e5090d3b1a07e28af524e66c128f624e16b07638f419012c779f76ec. -// -// Solidity: event AftermarketDeviceClaimed(uint256 aftermarketDeviceNode, address indexed owner) -func (_Registry *RegistryFilterer) ParseAftermarketDeviceClaimed(log types.Log) (*RegistryAftermarketDeviceClaimed, error) { - event := new(RegistryAftermarketDeviceClaimed) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceClaimed", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryAftermarketDeviceIdProxySetIterator is returned from FilterAftermarketDeviceIdProxySet and is used to iterate over the raw logs and unpacked data for AftermarketDeviceIdProxySet events raised by the Registry contract. -type RegistryAftermarketDeviceIdProxySetIterator struct { - Event *RegistryAftermarketDeviceIdProxySet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryAftermarketDeviceIdProxySetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceIdProxySet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceIdProxySet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryAftermarketDeviceIdProxySetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryAftermarketDeviceIdProxySetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryAftermarketDeviceIdProxySet represents a AftermarketDeviceIdProxySet event raised by the Registry contract. -type RegistryAftermarketDeviceIdProxySet struct { - Proxy common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAftermarketDeviceIdProxySet is a free log retrieval operation binding the contract event 0xe2daa727eb82f2761802221c26f72d54501ca8abd6da081e50fedaaab21f4036. -// -// Solidity: event AftermarketDeviceIdProxySet(address indexed proxy) -func (_Registry *RegistryFilterer) FilterAftermarketDeviceIdProxySet(opts *bind.FilterOpts, proxy []common.Address) (*RegistryAftermarketDeviceIdProxySetIterator, error) { - - var proxyRule []interface{} - for _, proxyItem := range proxy { - proxyRule = append(proxyRule, proxyItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "AftermarketDeviceIdProxySet", proxyRule) - if err != nil { - return nil, err - } - return &RegistryAftermarketDeviceIdProxySetIterator{contract: _Registry.contract, event: "AftermarketDeviceIdProxySet", logs: logs, sub: sub}, nil -} - -// WatchAftermarketDeviceIdProxySet is a free log subscription operation binding the contract event 0xe2daa727eb82f2761802221c26f72d54501ca8abd6da081e50fedaaab21f4036. -// -// Solidity: event AftermarketDeviceIdProxySet(address indexed proxy) -func (_Registry *RegistryFilterer) WatchAftermarketDeviceIdProxySet(opts *bind.WatchOpts, sink chan<- *RegistryAftermarketDeviceIdProxySet, proxy []common.Address) (event.Subscription, error) { - - var proxyRule []interface{} - for _, proxyItem := range proxy { - proxyRule = append(proxyRule, proxyItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "AftermarketDeviceIdProxySet", proxyRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryAftermarketDeviceIdProxySet) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceIdProxySet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseAftermarketDeviceIdProxySet is a log parse operation binding the contract event 0xe2daa727eb82f2761802221c26f72d54501ca8abd6da081e50fedaaab21f4036. -// -// Solidity: event AftermarketDeviceIdProxySet(address indexed proxy) -func (_Registry *RegistryFilterer) ParseAftermarketDeviceIdProxySet(log types.Log) (*RegistryAftermarketDeviceIdProxySet, error) { - event := new(RegistryAftermarketDeviceIdProxySet) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceIdProxySet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryAftermarketDeviceNodeBurnedIterator is returned from FilterAftermarketDeviceNodeBurned and is used to iterate over the raw logs and unpacked data for AftermarketDeviceNodeBurned events raised by the Registry contract. -type RegistryAftermarketDeviceNodeBurnedIterator struct { - Event *RegistryAftermarketDeviceNodeBurned // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryAftermarketDeviceNodeBurnedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceNodeBurned) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceNodeBurned) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryAftermarketDeviceNodeBurnedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryAftermarketDeviceNodeBurnedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryAftermarketDeviceNodeBurned represents a AftermarketDeviceNodeBurned event raised by the Registry contract. -type RegistryAftermarketDeviceNodeBurned struct { - TokenId *big.Int - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAftermarketDeviceNodeBurned is a free log retrieval operation binding the contract event 0xc4d38c0a034bc1693db3b9a33125831c3d2e1f11e5b69be183ff9ac991384d95. -// -// Solidity: event AftermarketDeviceNodeBurned(uint256 indexed tokenId, address indexed owner) -func (_Registry *RegistryFilterer) FilterAftermarketDeviceNodeBurned(opts *bind.FilterOpts, tokenId []*big.Int, owner []common.Address) (*RegistryAftermarketDeviceNodeBurnedIterator, error) { - - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "AftermarketDeviceNodeBurned", tokenIdRule, ownerRule) - if err != nil { - return nil, err - } - return &RegistryAftermarketDeviceNodeBurnedIterator{contract: _Registry.contract, event: "AftermarketDeviceNodeBurned", logs: logs, sub: sub}, nil -} - -// WatchAftermarketDeviceNodeBurned is a free log subscription operation binding the contract event 0xc4d38c0a034bc1693db3b9a33125831c3d2e1f11e5b69be183ff9ac991384d95. -// -// Solidity: event AftermarketDeviceNodeBurned(uint256 indexed tokenId, address indexed owner) -func (_Registry *RegistryFilterer) WatchAftermarketDeviceNodeBurned(opts *bind.WatchOpts, sink chan<- *RegistryAftermarketDeviceNodeBurned, tokenId []*big.Int, owner []common.Address) (event.Subscription, error) { - - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "AftermarketDeviceNodeBurned", tokenIdRule, ownerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryAftermarketDeviceNodeBurned) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceNodeBurned", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseAftermarketDeviceNodeBurned is a log parse operation binding the contract event 0xc4d38c0a034bc1693db3b9a33125831c3d2e1f11e5b69be183ff9ac991384d95. -// -// Solidity: event AftermarketDeviceNodeBurned(uint256 indexed tokenId, address indexed owner) -func (_Registry *RegistryFilterer) ParseAftermarketDeviceNodeBurned(log types.Log) (*RegistryAftermarketDeviceNodeBurned, error) { - event := new(RegistryAftermarketDeviceNodeBurned) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceNodeBurned", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryAftermarketDeviceNodeBurnedDevAdminIterator is returned from FilterAftermarketDeviceNodeBurnedDevAdmin and is used to iterate over the raw logs and unpacked data for AftermarketDeviceNodeBurnedDevAdmin events raised by the Registry contract. -type RegistryAftermarketDeviceNodeBurnedDevAdminIterator struct { - Event *RegistryAftermarketDeviceNodeBurnedDevAdmin // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryAftermarketDeviceNodeBurnedDevAdminIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceNodeBurnedDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceNodeBurnedDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryAftermarketDeviceNodeBurnedDevAdminIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryAftermarketDeviceNodeBurnedDevAdminIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryAftermarketDeviceNodeBurnedDevAdmin represents a AftermarketDeviceNodeBurnedDevAdmin event raised by the Registry contract. -type RegistryAftermarketDeviceNodeBurnedDevAdmin struct { - AdNode *big.Int - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAftermarketDeviceNodeBurnedDevAdmin is a free log retrieval operation binding the contract event 0xb33f329db9f4347b4ce64f7b9c2d5fe2d92e95ac9fee76a553543f1338752a45. -// -// Solidity: event AftermarketDeviceNodeBurnedDevAdmin(uint256 indexed adNode, address indexed owner) -func (_Registry *RegistryFilterer) FilterAftermarketDeviceNodeBurnedDevAdmin(opts *bind.FilterOpts, adNode []*big.Int, owner []common.Address) (*RegistryAftermarketDeviceNodeBurnedDevAdminIterator, error) { - - var adNodeRule []interface{} - for _, adNodeItem := range adNode { - adNodeRule = append(adNodeRule, adNodeItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "AftermarketDeviceNodeBurnedDevAdmin", adNodeRule, ownerRule) - if err != nil { - return nil, err - } - return &RegistryAftermarketDeviceNodeBurnedDevAdminIterator{contract: _Registry.contract, event: "AftermarketDeviceNodeBurnedDevAdmin", logs: logs, sub: sub}, nil -} - -// WatchAftermarketDeviceNodeBurnedDevAdmin is a free log subscription operation binding the contract event 0xb33f329db9f4347b4ce64f7b9c2d5fe2d92e95ac9fee76a553543f1338752a45. -// -// Solidity: event AftermarketDeviceNodeBurnedDevAdmin(uint256 indexed adNode, address indexed owner) -func (_Registry *RegistryFilterer) WatchAftermarketDeviceNodeBurnedDevAdmin(opts *bind.WatchOpts, sink chan<- *RegistryAftermarketDeviceNodeBurnedDevAdmin, adNode []*big.Int, owner []common.Address) (event.Subscription, error) { - - var adNodeRule []interface{} - for _, adNodeItem := range adNode { - adNodeRule = append(adNodeRule, adNodeItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "AftermarketDeviceNodeBurnedDevAdmin", adNodeRule, ownerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryAftermarketDeviceNodeBurnedDevAdmin) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceNodeBurnedDevAdmin", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseAftermarketDeviceNodeBurnedDevAdmin is a log parse operation binding the contract event 0xb33f329db9f4347b4ce64f7b9c2d5fe2d92e95ac9fee76a553543f1338752a45. -// -// Solidity: event AftermarketDeviceNodeBurnedDevAdmin(uint256 indexed adNode, address indexed owner) -func (_Registry *RegistryFilterer) ParseAftermarketDeviceNodeBurnedDevAdmin(log types.Log) (*RegistryAftermarketDeviceNodeBurnedDevAdmin, error) { - event := new(RegistryAftermarketDeviceNodeBurnedDevAdmin) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceNodeBurnedDevAdmin", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryAftermarketDeviceNodeMintedIterator is returned from FilterAftermarketDeviceNodeMinted and is used to iterate over the raw logs and unpacked data for AftermarketDeviceNodeMinted events raised by the Registry contract. -type RegistryAftermarketDeviceNodeMintedIterator struct { - Event *RegistryAftermarketDeviceNodeMinted // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryAftermarketDeviceNodeMintedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceNodeMinted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceNodeMinted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryAftermarketDeviceNodeMintedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryAftermarketDeviceNodeMintedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryAftermarketDeviceNodeMinted represents a AftermarketDeviceNodeMinted event raised by the Registry contract. -type RegistryAftermarketDeviceNodeMinted struct { - ManufacturerId *big.Int - TokenId *big.Int - AftermarketDeviceAddress common.Address - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAftermarketDeviceNodeMinted is a free log retrieval operation binding the contract event 0xd624fd4c3311e1803d230d97ce71fd60c4f658c30a31fbe08edcb211fd90f63f. -// -// Solidity: event AftermarketDeviceNodeMinted(uint256 indexed manufacturerId, uint256 tokenId, address indexed aftermarketDeviceAddress, address indexed owner) -func (_Registry *RegistryFilterer) FilterAftermarketDeviceNodeMinted(opts *bind.FilterOpts, manufacturerId []*big.Int, aftermarketDeviceAddress []common.Address, owner []common.Address) (*RegistryAftermarketDeviceNodeMintedIterator, error) { - - var manufacturerIdRule []interface{} - for _, manufacturerIdItem := range manufacturerId { - manufacturerIdRule = append(manufacturerIdRule, manufacturerIdItem) - } - - var aftermarketDeviceAddressRule []interface{} - for _, aftermarketDeviceAddressItem := range aftermarketDeviceAddress { - aftermarketDeviceAddressRule = append(aftermarketDeviceAddressRule, aftermarketDeviceAddressItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "AftermarketDeviceNodeMinted", manufacturerIdRule, aftermarketDeviceAddressRule, ownerRule) - if err != nil { - return nil, err - } - return &RegistryAftermarketDeviceNodeMintedIterator{contract: _Registry.contract, event: "AftermarketDeviceNodeMinted", logs: logs, sub: sub}, nil -} - -// WatchAftermarketDeviceNodeMinted is a free log subscription operation binding the contract event 0xd624fd4c3311e1803d230d97ce71fd60c4f658c30a31fbe08edcb211fd90f63f. -// -// Solidity: event AftermarketDeviceNodeMinted(uint256 indexed manufacturerId, uint256 tokenId, address indexed aftermarketDeviceAddress, address indexed owner) -func (_Registry *RegistryFilterer) WatchAftermarketDeviceNodeMinted(opts *bind.WatchOpts, sink chan<- *RegistryAftermarketDeviceNodeMinted, manufacturerId []*big.Int, aftermarketDeviceAddress []common.Address, owner []common.Address) (event.Subscription, error) { - - var manufacturerIdRule []interface{} - for _, manufacturerIdItem := range manufacturerId { - manufacturerIdRule = append(manufacturerIdRule, manufacturerIdItem) - } - - var aftermarketDeviceAddressRule []interface{} - for _, aftermarketDeviceAddressItem := range aftermarketDeviceAddress { - aftermarketDeviceAddressRule = append(aftermarketDeviceAddressRule, aftermarketDeviceAddressItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "AftermarketDeviceNodeMinted", manufacturerIdRule, aftermarketDeviceAddressRule, ownerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryAftermarketDeviceNodeMinted) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceNodeMinted", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseAftermarketDeviceNodeMinted is a log parse operation binding the contract event 0xd624fd4c3311e1803d230d97ce71fd60c4f658c30a31fbe08edcb211fd90f63f. -// -// Solidity: event AftermarketDeviceNodeMinted(uint256 indexed manufacturerId, uint256 tokenId, address indexed aftermarketDeviceAddress, address indexed owner) -func (_Registry *RegistryFilterer) ParseAftermarketDeviceNodeMinted(log types.Log) (*RegistryAftermarketDeviceNodeMinted, error) { - event := new(RegistryAftermarketDeviceNodeMinted) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceNodeMinted", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryAftermarketDevicePairedIterator is returned from FilterAftermarketDevicePaired and is used to iterate over the raw logs and unpacked data for AftermarketDevicePaired events raised by the Registry contract. -type RegistryAftermarketDevicePairedIterator struct { - Event *RegistryAftermarketDevicePaired // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryAftermarketDevicePairedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDevicePaired) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDevicePaired) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryAftermarketDevicePairedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryAftermarketDevicePairedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryAftermarketDevicePaired represents a AftermarketDevicePaired event raised by the Registry contract. -type RegistryAftermarketDevicePaired struct { - AftermarketDeviceNode *big.Int - VehicleNode *big.Int - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAftermarketDevicePaired is a free log retrieval operation binding the contract event 0x89ec132808bbf01af00b90fd34e04fd6cfb8dba2813ca5446a415500b83c7938. -// -// Solidity: event AftermarketDevicePaired(uint256 aftermarketDeviceNode, uint256 vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) FilterAftermarketDevicePaired(opts *bind.FilterOpts, owner []common.Address) (*RegistryAftermarketDevicePairedIterator, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "AftermarketDevicePaired", ownerRule) - if err != nil { - return nil, err - } - return &RegistryAftermarketDevicePairedIterator{contract: _Registry.contract, event: "AftermarketDevicePaired", logs: logs, sub: sub}, nil -} - -// WatchAftermarketDevicePaired is a free log subscription operation binding the contract event 0x89ec132808bbf01af00b90fd34e04fd6cfb8dba2813ca5446a415500b83c7938. -// -// Solidity: event AftermarketDevicePaired(uint256 aftermarketDeviceNode, uint256 vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) WatchAftermarketDevicePaired(opts *bind.WatchOpts, sink chan<- *RegistryAftermarketDevicePaired, owner []common.Address) (event.Subscription, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "AftermarketDevicePaired", ownerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryAftermarketDevicePaired) - if err := _Registry.contract.UnpackLog(event, "AftermarketDevicePaired", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseAftermarketDevicePaired is a log parse operation binding the contract event 0x89ec132808bbf01af00b90fd34e04fd6cfb8dba2813ca5446a415500b83c7938. -// -// Solidity: event AftermarketDevicePaired(uint256 aftermarketDeviceNode, uint256 vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) ParseAftermarketDevicePaired(log types.Log) (*RegistryAftermarketDevicePaired, error) { - event := new(RegistryAftermarketDevicePaired) - if err := _Registry.contract.UnpackLog(event, "AftermarketDevicePaired", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryAftermarketDeviceTransferredDevAdminIterator is returned from FilterAftermarketDeviceTransferredDevAdmin and is used to iterate over the raw logs and unpacked data for AftermarketDeviceTransferredDevAdmin events raised by the Registry contract. -type RegistryAftermarketDeviceTransferredDevAdminIterator struct { - Event *RegistryAftermarketDeviceTransferredDevAdmin // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryAftermarketDeviceTransferredDevAdminIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceTransferredDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceTransferredDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryAftermarketDeviceTransferredDevAdminIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryAftermarketDeviceTransferredDevAdminIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryAftermarketDeviceTransferredDevAdmin represents a AftermarketDeviceTransferredDevAdmin event raised by the Registry contract. -type RegistryAftermarketDeviceTransferredDevAdmin struct { - AftermarketDeviceNode *big.Int - OldOwner common.Address - NewOwner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAftermarketDeviceTransferredDevAdmin is a free log retrieval operation binding the contract event 0xaabf86a9bd61090827f5b0300192acf8de59d19921c52d81661675293105a8d8. -// -// Solidity: event AftermarketDeviceTransferredDevAdmin(uint256 indexed aftermarketDeviceNode, address indexed oldOwner, address indexed newOwner) -func (_Registry *RegistryFilterer) FilterAftermarketDeviceTransferredDevAdmin(opts *bind.FilterOpts, aftermarketDeviceNode []*big.Int, oldOwner []common.Address, newOwner []common.Address) (*RegistryAftermarketDeviceTransferredDevAdminIterator, error) { - - var aftermarketDeviceNodeRule []interface{} - for _, aftermarketDeviceNodeItem := range aftermarketDeviceNode { - aftermarketDeviceNodeRule = append(aftermarketDeviceNodeRule, aftermarketDeviceNodeItem) - } - var oldOwnerRule []interface{} - for _, oldOwnerItem := range oldOwner { - oldOwnerRule = append(oldOwnerRule, oldOwnerItem) - } - var newOwnerRule []interface{} - for _, newOwnerItem := range newOwner { - newOwnerRule = append(newOwnerRule, newOwnerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "AftermarketDeviceTransferredDevAdmin", aftermarketDeviceNodeRule, oldOwnerRule, newOwnerRule) - if err != nil { - return nil, err - } - return &RegistryAftermarketDeviceTransferredDevAdminIterator{contract: _Registry.contract, event: "AftermarketDeviceTransferredDevAdmin", logs: logs, sub: sub}, nil -} - -// WatchAftermarketDeviceTransferredDevAdmin is a free log subscription operation binding the contract event 0xaabf86a9bd61090827f5b0300192acf8de59d19921c52d81661675293105a8d8. -// -// Solidity: event AftermarketDeviceTransferredDevAdmin(uint256 indexed aftermarketDeviceNode, address indexed oldOwner, address indexed newOwner) -func (_Registry *RegistryFilterer) WatchAftermarketDeviceTransferredDevAdmin(opts *bind.WatchOpts, sink chan<- *RegistryAftermarketDeviceTransferredDevAdmin, aftermarketDeviceNode []*big.Int, oldOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { - - var aftermarketDeviceNodeRule []interface{} - for _, aftermarketDeviceNodeItem := range aftermarketDeviceNode { - aftermarketDeviceNodeRule = append(aftermarketDeviceNodeRule, aftermarketDeviceNodeItem) - } - var oldOwnerRule []interface{} - for _, oldOwnerItem := range oldOwner { - oldOwnerRule = append(oldOwnerRule, oldOwnerItem) - } - var newOwnerRule []interface{} - for _, newOwnerItem := range newOwner { - newOwnerRule = append(newOwnerRule, newOwnerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "AftermarketDeviceTransferredDevAdmin", aftermarketDeviceNodeRule, oldOwnerRule, newOwnerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryAftermarketDeviceTransferredDevAdmin) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceTransferredDevAdmin", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseAftermarketDeviceTransferredDevAdmin is a log parse operation binding the contract event 0xaabf86a9bd61090827f5b0300192acf8de59d19921c52d81661675293105a8d8. -// -// Solidity: event AftermarketDeviceTransferredDevAdmin(uint256 indexed aftermarketDeviceNode, address indexed oldOwner, address indexed newOwner) -func (_Registry *RegistryFilterer) ParseAftermarketDeviceTransferredDevAdmin(log types.Log) (*RegistryAftermarketDeviceTransferredDevAdmin, error) { - event := new(RegistryAftermarketDeviceTransferredDevAdmin) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceTransferredDevAdmin", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryAftermarketDeviceUnclaimedDevAdminIterator is returned from FilterAftermarketDeviceUnclaimedDevAdmin and is used to iterate over the raw logs and unpacked data for AftermarketDeviceUnclaimedDevAdmin events raised by the Registry contract. -type RegistryAftermarketDeviceUnclaimedDevAdminIterator struct { - Event *RegistryAftermarketDeviceUnclaimedDevAdmin // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryAftermarketDeviceUnclaimedDevAdminIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceUnclaimedDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceUnclaimedDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryAftermarketDeviceUnclaimedDevAdminIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryAftermarketDeviceUnclaimedDevAdminIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryAftermarketDeviceUnclaimedDevAdmin represents a AftermarketDeviceUnclaimedDevAdmin event raised by the Registry contract. -type RegistryAftermarketDeviceUnclaimedDevAdmin struct { - AftermarketDeviceNode *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAftermarketDeviceUnclaimedDevAdmin is a free log retrieval operation binding the contract event 0xd2a3fcd44d76e5d8eb77caa34c23f3d95ba16844e0ac03c41fd12c91f799e951. -// -// Solidity: event AftermarketDeviceUnclaimedDevAdmin(uint256 indexed aftermarketDeviceNode) -func (_Registry *RegistryFilterer) FilterAftermarketDeviceUnclaimedDevAdmin(opts *bind.FilterOpts, aftermarketDeviceNode []*big.Int) (*RegistryAftermarketDeviceUnclaimedDevAdminIterator, error) { - - var aftermarketDeviceNodeRule []interface{} - for _, aftermarketDeviceNodeItem := range aftermarketDeviceNode { - aftermarketDeviceNodeRule = append(aftermarketDeviceNodeRule, aftermarketDeviceNodeItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "AftermarketDeviceUnclaimedDevAdmin", aftermarketDeviceNodeRule) - if err != nil { - return nil, err - } - return &RegistryAftermarketDeviceUnclaimedDevAdminIterator{contract: _Registry.contract, event: "AftermarketDeviceUnclaimedDevAdmin", logs: logs, sub: sub}, nil -} - -// WatchAftermarketDeviceUnclaimedDevAdmin is a free log subscription operation binding the contract event 0xd2a3fcd44d76e5d8eb77caa34c23f3d95ba16844e0ac03c41fd12c91f799e951. -// -// Solidity: event AftermarketDeviceUnclaimedDevAdmin(uint256 indexed aftermarketDeviceNode) -func (_Registry *RegistryFilterer) WatchAftermarketDeviceUnclaimedDevAdmin(opts *bind.WatchOpts, sink chan<- *RegistryAftermarketDeviceUnclaimedDevAdmin, aftermarketDeviceNode []*big.Int) (event.Subscription, error) { - - var aftermarketDeviceNodeRule []interface{} - for _, aftermarketDeviceNodeItem := range aftermarketDeviceNode { - aftermarketDeviceNodeRule = append(aftermarketDeviceNodeRule, aftermarketDeviceNodeItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "AftermarketDeviceUnclaimedDevAdmin", aftermarketDeviceNodeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryAftermarketDeviceUnclaimedDevAdmin) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceUnclaimedDevAdmin", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseAftermarketDeviceUnclaimedDevAdmin is a log parse operation binding the contract event 0xd2a3fcd44d76e5d8eb77caa34c23f3d95ba16844e0ac03c41fd12c91f799e951. -// -// Solidity: event AftermarketDeviceUnclaimedDevAdmin(uint256 indexed aftermarketDeviceNode) -func (_Registry *RegistryFilterer) ParseAftermarketDeviceUnclaimedDevAdmin(log types.Log) (*RegistryAftermarketDeviceUnclaimedDevAdmin, error) { - event := new(RegistryAftermarketDeviceUnclaimedDevAdmin) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceUnclaimedDevAdmin", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryAftermarketDeviceUnpairedIterator is returned from FilterAftermarketDeviceUnpaired and is used to iterate over the raw logs and unpacked data for AftermarketDeviceUnpaired events raised by the Registry contract. -type RegistryAftermarketDeviceUnpairedIterator struct { - Event *RegistryAftermarketDeviceUnpaired // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryAftermarketDeviceUnpairedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceUnpaired) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceUnpaired) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryAftermarketDeviceUnpairedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryAftermarketDeviceUnpairedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryAftermarketDeviceUnpaired represents a AftermarketDeviceUnpaired event raised by the Registry contract. -type RegistryAftermarketDeviceUnpaired struct { - AftermarketDeviceNode *big.Int - VehicleNode *big.Int - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAftermarketDeviceUnpaired is a free log retrieval operation binding the contract event 0xd9135724aa6cdaa5b3ea73e3e0d74cb1a3a6d3cddcb9d58583f05f17bac82a8e. -// -// Solidity: event AftermarketDeviceUnpaired(uint256 aftermarketDeviceNode, uint256 vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) FilterAftermarketDeviceUnpaired(opts *bind.FilterOpts, owner []common.Address) (*RegistryAftermarketDeviceUnpairedIterator, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "AftermarketDeviceUnpaired", ownerRule) - if err != nil { - return nil, err - } - return &RegistryAftermarketDeviceUnpairedIterator{contract: _Registry.contract, event: "AftermarketDeviceUnpaired", logs: logs, sub: sub}, nil -} - -// WatchAftermarketDeviceUnpaired is a free log subscription operation binding the contract event 0xd9135724aa6cdaa5b3ea73e3e0d74cb1a3a6d3cddcb9d58583f05f17bac82a8e. -// -// Solidity: event AftermarketDeviceUnpaired(uint256 aftermarketDeviceNode, uint256 vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) WatchAftermarketDeviceUnpaired(opts *bind.WatchOpts, sink chan<- *RegistryAftermarketDeviceUnpaired, owner []common.Address) (event.Subscription, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "AftermarketDeviceUnpaired", ownerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryAftermarketDeviceUnpaired) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceUnpaired", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseAftermarketDeviceUnpaired is a log parse operation binding the contract event 0xd9135724aa6cdaa5b3ea73e3e0d74cb1a3a6d3cddcb9d58583f05f17bac82a8e. -// -// Solidity: event AftermarketDeviceUnpaired(uint256 aftermarketDeviceNode, uint256 vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) ParseAftermarketDeviceUnpaired(log types.Log) (*RegistryAftermarketDeviceUnpaired, error) { - event := new(RegistryAftermarketDeviceUnpaired) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceUnpaired", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryAftermarketDeviceUnpairedDevAdminIterator is returned from FilterAftermarketDeviceUnpairedDevAdmin and is used to iterate over the raw logs and unpacked data for AftermarketDeviceUnpairedDevAdmin events raised by the Registry contract. -type RegistryAftermarketDeviceUnpairedDevAdminIterator struct { - Event *RegistryAftermarketDeviceUnpairedDevAdmin // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryAftermarketDeviceUnpairedDevAdminIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceUnpairedDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryAftermarketDeviceUnpairedDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryAftermarketDeviceUnpairedDevAdminIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryAftermarketDeviceUnpairedDevAdminIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryAftermarketDeviceUnpairedDevAdmin represents a AftermarketDeviceUnpairedDevAdmin event raised by the Registry contract. -type RegistryAftermarketDeviceUnpairedDevAdmin struct { - AftermarketDeviceNode *big.Int - VehicleNode *big.Int - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAftermarketDeviceUnpairedDevAdmin is a free log retrieval operation binding the contract event 0x1ba4ec81d8261daefdabcf390fb1434fb92bc9a103e4cdc764ca43fa37d0ab0d. -// -// Solidity: event AftermarketDeviceUnpairedDevAdmin(uint256 indexed aftermarketDeviceNode, uint256 indexed vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) FilterAftermarketDeviceUnpairedDevAdmin(opts *bind.FilterOpts, aftermarketDeviceNode []*big.Int, vehicleNode []*big.Int, owner []common.Address) (*RegistryAftermarketDeviceUnpairedDevAdminIterator, error) { - - var aftermarketDeviceNodeRule []interface{} - for _, aftermarketDeviceNodeItem := range aftermarketDeviceNode { - aftermarketDeviceNodeRule = append(aftermarketDeviceNodeRule, aftermarketDeviceNodeItem) - } - var vehicleNodeRule []interface{} - for _, vehicleNodeItem := range vehicleNode { - vehicleNodeRule = append(vehicleNodeRule, vehicleNodeItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "AftermarketDeviceUnpairedDevAdmin", aftermarketDeviceNodeRule, vehicleNodeRule, ownerRule) - if err != nil { - return nil, err - } - return &RegistryAftermarketDeviceUnpairedDevAdminIterator{contract: _Registry.contract, event: "AftermarketDeviceUnpairedDevAdmin", logs: logs, sub: sub}, nil -} - -// WatchAftermarketDeviceUnpairedDevAdmin is a free log subscription operation binding the contract event 0x1ba4ec81d8261daefdabcf390fb1434fb92bc9a103e4cdc764ca43fa37d0ab0d. -// -// Solidity: event AftermarketDeviceUnpairedDevAdmin(uint256 indexed aftermarketDeviceNode, uint256 indexed vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) WatchAftermarketDeviceUnpairedDevAdmin(opts *bind.WatchOpts, sink chan<- *RegistryAftermarketDeviceUnpairedDevAdmin, aftermarketDeviceNode []*big.Int, vehicleNode []*big.Int, owner []common.Address) (event.Subscription, error) { - - var aftermarketDeviceNodeRule []interface{} - for _, aftermarketDeviceNodeItem := range aftermarketDeviceNode { - aftermarketDeviceNodeRule = append(aftermarketDeviceNodeRule, aftermarketDeviceNodeItem) - } - var vehicleNodeRule []interface{} - for _, vehicleNodeItem := range vehicleNode { - vehicleNodeRule = append(vehicleNodeRule, vehicleNodeItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "AftermarketDeviceUnpairedDevAdmin", aftermarketDeviceNodeRule, vehicleNodeRule, ownerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryAftermarketDeviceUnpairedDevAdmin) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceUnpairedDevAdmin", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseAftermarketDeviceUnpairedDevAdmin is a log parse operation binding the contract event 0x1ba4ec81d8261daefdabcf390fb1434fb92bc9a103e4cdc764ca43fa37d0ab0d. -// -// Solidity: event AftermarketDeviceUnpairedDevAdmin(uint256 indexed aftermarketDeviceNode, uint256 indexed vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) ParseAftermarketDeviceUnpairedDevAdmin(log types.Log) (*RegistryAftermarketDeviceUnpairedDevAdmin, error) { - event := new(RegistryAftermarketDeviceUnpairedDevAdmin) - if err := _Registry.contract.UnpackLog(event, "AftermarketDeviceUnpairedDevAdmin", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryBaseDataURISetIterator is returned from FilterBaseDataURISet and is used to iterate over the raw logs and unpacked data for BaseDataURISet events raised by the Registry contract. -type RegistryBaseDataURISetIterator struct { - Event *RegistryBaseDataURISet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryBaseDataURISetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryBaseDataURISet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryBaseDataURISet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryBaseDataURISetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryBaseDataURISetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryBaseDataURISet represents a BaseDataURISet event raised by the Registry contract. -type RegistryBaseDataURISet struct { - IdProxyAddress common.Address - DataUri string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterBaseDataURISet is a free log retrieval operation binding the contract event 0x9f53d8a6c486c216c3b3fd5d6d4a133c4d66db260694bc0cfe0696d99458851f. -// -// Solidity: event BaseDataURISet(address idProxyAddress, string dataUri) -func (_Registry *RegistryFilterer) FilterBaseDataURISet(opts *bind.FilterOpts) (*RegistryBaseDataURISetIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "BaseDataURISet") - if err != nil { - return nil, err - } - return &RegistryBaseDataURISetIterator{contract: _Registry.contract, event: "BaseDataURISet", logs: logs, sub: sub}, nil -} - -// WatchBaseDataURISet is a free log subscription operation binding the contract event 0x9f53d8a6c486c216c3b3fd5d6d4a133c4d66db260694bc0cfe0696d99458851f. -// -// Solidity: event BaseDataURISet(address idProxyAddress, string dataUri) -func (_Registry *RegistryFilterer) WatchBaseDataURISet(opts *bind.WatchOpts, sink chan<- *RegistryBaseDataURISet) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "BaseDataURISet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryBaseDataURISet) - if err := _Registry.contract.UnpackLog(event, "BaseDataURISet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseBaseDataURISet is a log parse operation binding the contract event 0x9f53d8a6c486c216c3b3fd5d6d4a133c4d66db260694bc0cfe0696d99458851f. -// -// Solidity: event BaseDataURISet(address idProxyAddress, string dataUri) -func (_Registry *RegistryFilterer) ParseBaseDataURISet(log types.Log) (*RegistryBaseDataURISet, error) { - event := new(RegistryBaseDataURISet) - if err := _Registry.contract.UnpackLog(event, "BaseDataURISet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryBeneficiarySetIterator is returned from FilterBeneficiarySet and is used to iterate over the raw logs and unpacked data for BeneficiarySet events raised by the Registry contract. -type RegistryBeneficiarySetIterator struct { - Event *RegistryBeneficiarySet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryBeneficiarySetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryBeneficiarySet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryBeneficiarySet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryBeneficiarySetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryBeneficiarySetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryBeneficiarySet represents a BeneficiarySet event raised by the Registry contract. -type RegistryBeneficiarySet struct { - IdProxyAddress common.Address - NodeId *big.Int - Beneficiary common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterBeneficiarySet is a free log retrieval operation binding the contract event 0xf6f6de47a057b68d993d1ca4c1b8a95e51b10d7efbf516bc3c591eb6c4f209ee. -// -// Solidity: event BeneficiarySet(address indexed idProxyAddress, uint256 indexed nodeId, address indexed beneficiary) -func (_Registry *RegistryFilterer) FilterBeneficiarySet(opts *bind.FilterOpts, idProxyAddress []common.Address, nodeId []*big.Int, beneficiary []common.Address) (*RegistryBeneficiarySetIterator, error) { - - var idProxyAddressRule []interface{} - for _, idProxyAddressItem := range idProxyAddress { - idProxyAddressRule = append(idProxyAddressRule, idProxyAddressItem) - } - var nodeIdRule []interface{} - for _, nodeIdItem := range nodeId { - nodeIdRule = append(nodeIdRule, nodeIdItem) - } - var beneficiaryRule []interface{} - for _, beneficiaryItem := range beneficiary { - beneficiaryRule = append(beneficiaryRule, beneficiaryItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "BeneficiarySet", idProxyAddressRule, nodeIdRule, beneficiaryRule) - if err != nil { - return nil, err - } - return &RegistryBeneficiarySetIterator{contract: _Registry.contract, event: "BeneficiarySet", logs: logs, sub: sub}, nil -} - -// WatchBeneficiarySet is a free log subscription operation binding the contract event 0xf6f6de47a057b68d993d1ca4c1b8a95e51b10d7efbf516bc3c591eb6c4f209ee. -// -// Solidity: event BeneficiarySet(address indexed idProxyAddress, uint256 indexed nodeId, address indexed beneficiary) -func (_Registry *RegistryFilterer) WatchBeneficiarySet(opts *bind.WatchOpts, sink chan<- *RegistryBeneficiarySet, idProxyAddress []common.Address, nodeId []*big.Int, beneficiary []common.Address) (event.Subscription, error) { - - var idProxyAddressRule []interface{} - for _, idProxyAddressItem := range idProxyAddress { - idProxyAddressRule = append(idProxyAddressRule, idProxyAddressItem) - } - var nodeIdRule []interface{} - for _, nodeIdItem := range nodeId { - nodeIdRule = append(nodeIdRule, nodeIdItem) - } - var beneficiaryRule []interface{} - for _, beneficiaryItem := range beneficiary { - beneficiaryRule = append(beneficiaryRule, beneficiaryItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "BeneficiarySet", idProxyAddressRule, nodeIdRule, beneficiaryRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryBeneficiarySet) - if err := _Registry.contract.UnpackLog(event, "BeneficiarySet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseBeneficiarySet is a log parse operation binding the contract event 0xf6f6de47a057b68d993d1ca4c1b8a95e51b10d7efbf516bc3c591eb6c4f209ee. -// -// Solidity: event BeneficiarySet(address indexed idProxyAddress, uint256 indexed nodeId, address indexed beneficiary) -func (_Registry *RegistryFilterer) ParseBeneficiarySet(log types.Log) (*RegistryBeneficiarySet, error) { - event := new(RegistryBeneficiarySet) - if err := _Registry.contract.UnpackLog(event, "BeneficiarySet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryControllerSetIterator is returned from FilterControllerSet and is used to iterate over the raw logs and unpacked data for ControllerSet events raised by the Registry contract. -type RegistryControllerSetIterator struct { - Event *RegistryControllerSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryControllerSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryControllerSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryControllerSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryControllerSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryControllerSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryControllerSet represents a ControllerSet event raised by the Registry contract. -type RegistryControllerSet struct { - Controller common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterControllerSet is a free log retrieval operation binding the contract event 0x79f74fd5964b6943d8a1865abfb7f668c92fa3f32c0a2e3195da7d0946703ad7. -// -// Solidity: event ControllerSet(address indexed controller) -func (_Registry *RegistryFilterer) FilterControllerSet(opts *bind.FilterOpts, controller []common.Address) (*RegistryControllerSetIterator, error) { - - var controllerRule []interface{} - for _, controllerItem := range controller { - controllerRule = append(controllerRule, controllerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "ControllerSet", controllerRule) - if err != nil { - return nil, err - } - return &RegistryControllerSetIterator{contract: _Registry.contract, event: "ControllerSet", logs: logs, sub: sub}, nil -} - -// WatchControllerSet is a free log subscription operation binding the contract event 0x79f74fd5964b6943d8a1865abfb7f668c92fa3f32c0a2e3195da7d0946703ad7. -// -// Solidity: event ControllerSet(address indexed controller) -func (_Registry *RegistryFilterer) WatchControllerSet(opts *bind.WatchOpts, sink chan<- *RegistryControllerSet, controller []common.Address) (event.Subscription, error) { - - var controllerRule []interface{} - for _, controllerItem := range controller { - controllerRule = append(controllerRule, controllerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "ControllerSet", controllerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryControllerSet) - if err := _Registry.contract.UnpackLog(event, "ControllerSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseControllerSet is a log parse operation binding the contract event 0x79f74fd5964b6943d8a1865abfb7f668c92fa3f32c0a2e3195da7d0946703ad7. -// -// Solidity: event ControllerSet(address indexed controller) -func (_Registry *RegistryFilterer) ParseControllerSet(log types.Log) (*RegistryControllerSet, error) { - event := new(RegistryControllerSet) - if err := _Registry.contract.UnpackLog(event, "ControllerSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryDeviceDefinitionDeletedIterator is returned from FilterDeviceDefinitionDeleted and is used to iterate over the raw logs and unpacked data for DeviceDefinitionDeleted events raised by the Registry contract. -type RegistryDeviceDefinitionDeletedIterator struct { - Event *RegistryDeviceDefinitionDeleted // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryDeviceDefinitionDeletedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryDeviceDefinitionDeleted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryDeviceDefinitionDeleted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryDeviceDefinitionDeletedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryDeviceDefinitionDeletedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryDeviceDefinitionDeleted represents a DeviceDefinitionDeleted event raised by the Registry contract. -type RegistryDeviceDefinitionDeleted struct { - TableId *big.Int - Id string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterDeviceDefinitionDeleted is a free log retrieval operation binding the contract event 0x29504454a41793fb917c032e7baa04f0e74dd570dafc91d64cecff606f3411ca. -// -// Solidity: event DeviceDefinitionDeleted(uint256 indexed tableId, string id) -func (_Registry *RegistryFilterer) FilterDeviceDefinitionDeleted(opts *bind.FilterOpts, tableId []*big.Int) (*RegistryDeviceDefinitionDeletedIterator, error) { - - var tableIdRule []interface{} - for _, tableIdItem := range tableId { - tableIdRule = append(tableIdRule, tableIdItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "DeviceDefinitionDeleted", tableIdRule) - if err != nil { - return nil, err - } - return &RegistryDeviceDefinitionDeletedIterator{contract: _Registry.contract, event: "DeviceDefinitionDeleted", logs: logs, sub: sub}, nil -} - -// WatchDeviceDefinitionDeleted is a free log subscription operation binding the contract event 0x29504454a41793fb917c032e7baa04f0e74dd570dafc91d64cecff606f3411ca. -// -// Solidity: event DeviceDefinitionDeleted(uint256 indexed tableId, string id) -func (_Registry *RegistryFilterer) WatchDeviceDefinitionDeleted(opts *bind.WatchOpts, sink chan<- *RegistryDeviceDefinitionDeleted, tableId []*big.Int) (event.Subscription, error) { - - var tableIdRule []interface{} - for _, tableIdItem := range tableId { - tableIdRule = append(tableIdRule, tableIdItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "DeviceDefinitionDeleted", tableIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryDeviceDefinitionDeleted) - if err := _Registry.contract.UnpackLog(event, "DeviceDefinitionDeleted", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseDeviceDefinitionDeleted is a log parse operation binding the contract event 0x29504454a41793fb917c032e7baa04f0e74dd570dafc91d64cecff606f3411ca. -// -// Solidity: event DeviceDefinitionDeleted(uint256 indexed tableId, string id) -func (_Registry *RegistryFilterer) ParseDeviceDefinitionDeleted(log types.Log) (*RegistryDeviceDefinitionDeleted, error) { - event := new(RegistryDeviceDefinitionDeleted) - if err := _Registry.contract.UnpackLog(event, "DeviceDefinitionDeleted", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryDeviceDefinitionIdSetIterator is returned from FilterDeviceDefinitionIdSet and is used to iterate over the raw logs and unpacked data for DeviceDefinitionIdSet events raised by the Registry contract. -type RegistryDeviceDefinitionIdSetIterator struct { - Event *RegistryDeviceDefinitionIdSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryDeviceDefinitionIdSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryDeviceDefinitionIdSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryDeviceDefinitionIdSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryDeviceDefinitionIdSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryDeviceDefinitionIdSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryDeviceDefinitionIdSet represents a DeviceDefinitionIdSet event raised by the Registry contract. -type RegistryDeviceDefinitionIdSet struct { - VehicleId *big.Int - DdId string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterDeviceDefinitionIdSet is a free log retrieval operation binding the contract event 0x11880ae675ee346586e2fe83800263cdf21bada6dba1a0623cad2163338a6fad. -// -// Solidity: event DeviceDefinitionIdSet(uint256 indexed vehicleId, string ddId) -func (_Registry *RegistryFilterer) FilterDeviceDefinitionIdSet(opts *bind.FilterOpts, vehicleId []*big.Int) (*RegistryDeviceDefinitionIdSetIterator, error) { - - var vehicleIdRule []interface{} - for _, vehicleIdItem := range vehicleId { - vehicleIdRule = append(vehicleIdRule, vehicleIdItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "DeviceDefinitionIdSet", vehicleIdRule) - if err != nil { - return nil, err - } - return &RegistryDeviceDefinitionIdSetIterator{contract: _Registry.contract, event: "DeviceDefinitionIdSet", logs: logs, sub: sub}, nil -} - -// WatchDeviceDefinitionIdSet is a free log subscription operation binding the contract event 0x11880ae675ee346586e2fe83800263cdf21bada6dba1a0623cad2163338a6fad. -// -// Solidity: event DeviceDefinitionIdSet(uint256 indexed vehicleId, string ddId) -func (_Registry *RegistryFilterer) WatchDeviceDefinitionIdSet(opts *bind.WatchOpts, sink chan<- *RegistryDeviceDefinitionIdSet, vehicleId []*big.Int) (event.Subscription, error) { - - var vehicleIdRule []interface{} - for _, vehicleIdItem := range vehicleId { - vehicleIdRule = append(vehicleIdRule, vehicleIdItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "DeviceDefinitionIdSet", vehicleIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryDeviceDefinitionIdSet) - if err := _Registry.contract.UnpackLog(event, "DeviceDefinitionIdSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseDeviceDefinitionIdSet is a log parse operation binding the contract event 0x11880ae675ee346586e2fe83800263cdf21bada6dba1a0623cad2163338a6fad. -// -// Solidity: event DeviceDefinitionIdSet(uint256 indexed vehicleId, string ddId) -func (_Registry *RegistryFilterer) ParseDeviceDefinitionIdSet(log types.Log) (*RegistryDeviceDefinitionIdSet, error) { - event := new(RegistryDeviceDefinitionIdSet) - if err := _Registry.contract.UnpackLog(event, "DeviceDefinitionIdSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryDeviceDefinitionInsertedIterator is returned from FilterDeviceDefinitionInserted and is used to iterate over the raw logs and unpacked data for DeviceDefinitionInserted events raised by the Registry contract. -type RegistryDeviceDefinitionInsertedIterator struct { - Event *RegistryDeviceDefinitionInserted // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryDeviceDefinitionInsertedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryDeviceDefinitionInserted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryDeviceDefinitionInserted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryDeviceDefinitionInsertedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryDeviceDefinitionInsertedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryDeviceDefinitionInserted represents a DeviceDefinitionInserted event raised by the Registry contract. -type RegistryDeviceDefinitionInserted struct { - TableId *big.Int - Id string - Model string - Year *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterDeviceDefinitionInserted is a free log retrieval operation binding the contract event 0x462ef08cd7ac75ba02b3d84fe43ba15ae23f90a51484c6536057e951c2b629bb. -// -// Solidity: event DeviceDefinitionInserted(uint256 indexed tableId, string id, string model, uint256 year) -func (_Registry *RegistryFilterer) FilterDeviceDefinitionInserted(opts *bind.FilterOpts, tableId []*big.Int) (*RegistryDeviceDefinitionInsertedIterator, error) { - - var tableIdRule []interface{} - for _, tableIdItem := range tableId { - tableIdRule = append(tableIdRule, tableIdItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "DeviceDefinitionInserted", tableIdRule) - if err != nil { - return nil, err - } - return &RegistryDeviceDefinitionInsertedIterator{contract: _Registry.contract, event: "DeviceDefinitionInserted", logs: logs, sub: sub}, nil -} - -// WatchDeviceDefinitionInserted is a free log subscription operation binding the contract event 0x462ef08cd7ac75ba02b3d84fe43ba15ae23f90a51484c6536057e951c2b629bb. -// -// Solidity: event DeviceDefinitionInserted(uint256 indexed tableId, string id, string model, uint256 year) -func (_Registry *RegistryFilterer) WatchDeviceDefinitionInserted(opts *bind.WatchOpts, sink chan<- *RegistryDeviceDefinitionInserted, tableId []*big.Int) (event.Subscription, error) { - - var tableIdRule []interface{} - for _, tableIdItem := range tableId { - tableIdRule = append(tableIdRule, tableIdItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "DeviceDefinitionInserted", tableIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryDeviceDefinitionInserted) - if err := _Registry.contract.UnpackLog(event, "DeviceDefinitionInserted", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseDeviceDefinitionInserted is a log parse operation binding the contract event 0x462ef08cd7ac75ba02b3d84fe43ba15ae23f90a51484c6536057e951c2b629bb. -// -// Solidity: event DeviceDefinitionInserted(uint256 indexed tableId, string id, string model, uint256 year) -func (_Registry *RegistryFilterer) ParseDeviceDefinitionInserted(log types.Log) (*RegistryDeviceDefinitionInserted, error) { - event := new(RegistryDeviceDefinitionInserted) - if err := _Registry.contract.UnpackLog(event, "DeviceDefinitionInserted", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryDeviceDefinitionTableCreatedIterator is returned from FilterDeviceDefinitionTableCreated and is used to iterate over the raw logs and unpacked data for DeviceDefinitionTableCreated events raised by the Registry contract. -type RegistryDeviceDefinitionTableCreatedIterator struct { - Event *RegistryDeviceDefinitionTableCreated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryDeviceDefinitionTableCreatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryDeviceDefinitionTableCreated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryDeviceDefinitionTableCreated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryDeviceDefinitionTableCreatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryDeviceDefinitionTableCreatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryDeviceDefinitionTableCreated represents a DeviceDefinitionTableCreated event raised by the Registry contract. -type RegistryDeviceDefinitionTableCreated struct { - TableOwner common.Address - ManufacturerId *big.Int - TableId *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterDeviceDefinitionTableCreated is a free log retrieval operation binding the contract event 0x34045c03bca909729abb696ffeefc454874a5b7967ee473daeafa7b45c91999e. -// -// Solidity: event DeviceDefinitionTableCreated(address indexed tableOwner, uint256 indexed manufacturerId, uint256 indexed tableId) -func (_Registry *RegistryFilterer) FilterDeviceDefinitionTableCreated(opts *bind.FilterOpts, tableOwner []common.Address, manufacturerId []*big.Int, tableId []*big.Int) (*RegistryDeviceDefinitionTableCreatedIterator, error) { - - var tableOwnerRule []interface{} - for _, tableOwnerItem := range tableOwner { - tableOwnerRule = append(tableOwnerRule, tableOwnerItem) - } - var manufacturerIdRule []interface{} - for _, manufacturerIdItem := range manufacturerId { - manufacturerIdRule = append(manufacturerIdRule, manufacturerIdItem) - } - var tableIdRule []interface{} - for _, tableIdItem := range tableId { - tableIdRule = append(tableIdRule, tableIdItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "DeviceDefinitionTableCreated", tableOwnerRule, manufacturerIdRule, tableIdRule) - if err != nil { - return nil, err - } - return &RegistryDeviceDefinitionTableCreatedIterator{contract: _Registry.contract, event: "DeviceDefinitionTableCreated", logs: logs, sub: sub}, nil -} - -// WatchDeviceDefinitionTableCreated is a free log subscription operation binding the contract event 0x34045c03bca909729abb696ffeefc454874a5b7967ee473daeafa7b45c91999e. -// -// Solidity: event DeviceDefinitionTableCreated(address indexed tableOwner, uint256 indexed manufacturerId, uint256 indexed tableId) -func (_Registry *RegistryFilterer) WatchDeviceDefinitionTableCreated(opts *bind.WatchOpts, sink chan<- *RegistryDeviceDefinitionTableCreated, tableOwner []common.Address, manufacturerId []*big.Int, tableId []*big.Int) (event.Subscription, error) { - - var tableOwnerRule []interface{} - for _, tableOwnerItem := range tableOwner { - tableOwnerRule = append(tableOwnerRule, tableOwnerItem) - } - var manufacturerIdRule []interface{} - for _, manufacturerIdItem := range manufacturerId { - manufacturerIdRule = append(manufacturerIdRule, manufacturerIdItem) - } - var tableIdRule []interface{} - for _, tableIdItem := range tableId { - tableIdRule = append(tableIdRule, tableIdItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "DeviceDefinitionTableCreated", tableOwnerRule, manufacturerIdRule, tableIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryDeviceDefinitionTableCreated) - if err := _Registry.contract.UnpackLog(event, "DeviceDefinitionTableCreated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseDeviceDefinitionTableCreated is a log parse operation binding the contract event 0x34045c03bca909729abb696ffeefc454874a5b7967ee473daeafa7b45c91999e. -// -// Solidity: event DeviceDefinitionTableCreated(address indexed tableOwner, uint256 indexed manufacturerId, uint256 indexed tableId) -func (_Registry *RegistryFilterer) ParseDeviceDefinitionTableCreated(log types.Log) (*RegistryDeviceDefinitionTableCreated, error) { - event := new(RegistryDeviceDefinitionTableCreated) - if err := _Registry.contract.UnpackLog(event, "DeviceDefinitionTableCreated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryDeviceDefinitionUpdatedIterator is returned from FilterDeviceDefinitionUpdated and is used to iterate over the raw logs and unpacked data for DeviceDefinitionUpdated events raised by the Registry contract. -type RegistryDeviceDefinitionUpdatedIterator struct { - Event *RegistryDeviceDefinitionUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryDeviceDefinitionUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryDeviceDefinitionUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryDeviceDefinitionUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryDeviceDefinitionUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryDeviceDefinitionUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryDeviceDefinitionUpdated represents a DeviceDefinitionUpdated event raised by the Registry contract. -type RegistryDeviceDefinitionUpdated struct { - TableId *big.Int - Id string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterDeviceDefinitionUpdated is a free log retrieval operation binding the contract event 0x67c3ba003a03bea0bbf3e3b8b976139e07cca2c5b0cc89131d95f2a998796bf6. -// -// Solidity: event DeviceDefinitionUpdated(uint256 indexed tableId, string id) -func (_Registry *RegistryFilterer) FilterDeviceDefinitionUpdated(opts *bind.FilterOpts, tableId []*big.Int) (*RegistryDeviceDefinitionUpdatedIterator, error) { - - var tableIdRule []interface{} - for _, tableIdItem := range tableId { - tableIdRule = append(tableIdRule, tableIdItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "DeviceDefinitionUpdated", tableIdRule) - if err != nil { - return nil, err - } - return &RegistryDeviceDefinitionUpdatedIterator{contract: _Registry.contract, event: "DeviceDefinitionUpdated", logs: logs, sub: sub}, nil -} - -// WatchDeviceDefinitionUpdated is a free log subscription operation binding the contract event 0x67c3ba003a03bea0bbf3e3b8b976139e07cca2c5b0cc89131d95f2a998796bf6. -// -// Solidity: event DeviceDefinitionUpdated(uint256 indexed tableId, string id) -func (_Registry *RegistryFilterer) WatchDeviceDefinitionUpdated(opts *bind.WatchOpts, sink chan<- *RegistryDeviceDefinitionUpdated, tableId []*big.Int) (event.Subscription, error) { - - var tableIdRule []interface{} - for _, tableIdItem := range tableId { - tableIdRule = append(tableIdRule, tableIdItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "DeviceDefinitionUpdated", tableIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryDeviceDefinitionUpdated) - if err := _Registry.contract.UnpackLog(event, "DeviceDefinitionUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseDeviceDefinitionUpdated is a log parse operation binding the contract event 0x67c3ba003a03bea0bbf3e3b8b976139e07cca2c5b0cc89131d95f2a998796bf6. -// -// Solidity: event DeviceDefinitionUpdated(uint256 indexed tableId, string id) -func (_Registry *RegistryFilterer) ParseDeviceDefinitionUpdated(log types.Log) (*RegistryDeviceDefinitionUpdated, error) { - event := new(RegistryDeviceDefinitionUpdated) - if err := _Registry.contract.UnpackLog(event, "DeviceDefinitionUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryDimoCreditSetIterator is returned from FilterDimoCreditSet and is used to iterate over the raw logs and unpacked data for DimoCreditSet events raised by the Registry contract. -type RegistryDimoCreditSetIterator struct { - Event *RegistryDimoCreditSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryDimoCreditSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryDimoCreditSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryDimoCreditSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryDimoCreditSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryDimoCreditSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryDimoCreditSet represents a DimoCreditSet event raised by the Registry contract. -type RegistryDimoCreditSet struct { - DimoCredit common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterDimoCreditSet is a free log retrieval operation binding the contract event 0x6f17bce437ce6897c71e9d81fa557073d0f924fbafbace72ebd44e39cbba6506. -// -// Solidity: event DimoCreditSet(address indexed dimoCredit) -func (_Registry *RegistryFilterer) FilterDimoCreditSet(opts *bind.FilterOpts, dimoCredit []common.Address) (*RegistryDimoCreditSetIterator, error) { - - var dimoCreditRule []interface{} - for _, dimoCreditItem := range dimoCredit { - dimoCreditRule = append(dimoCreditRule, dimoCreditItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "DimoCreditSet", dimoCreditRule) - if err != nil { - return nil, err - } - return &RegistryDimoCreditSetIterator{contract: _Registry.contract, event: "DimoCreditSet", logs: logs, sub: sub}, nil -} - -// WatchDimoCreditSet is a free log subscription operation binding the contract event 0x6f17bce437ce6897c71e9d81fa557073d0f924fbafbace72ebd44e39cbba6506. -// -// Solidity: event DimoCreditSet(address indexed dimoCredit) -func (_Registry *RegistryFilterer) WatchDimoCreditSet(opts *bind.WatchOpts, sink chan<- *RegistryDimoCreditSet, dimoCredit []common.Address) (event.Subscription, error) { - - var dimoCreditRule []interface{} - for _, dimoCreditItem := range dimoCredit { - dimoCreditRule = append(dimoCreditRule, dimoCreditItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "DimoCreditSet", dimoCreditRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryDimoCreditSet) - if err := _Registry.contract.UnpackLog(event, "DimoCreditSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseDimoCreditSet is a log parse operation binding the contract event 0x6f17bce437ce6897c71e9d81fa557073d0f924fbafbace72ebd44e39cbba6506. -// -// Solidity: event DimoCreditSet(address indexed dimoCredit) -func (_Registry *RegistryFilterer) ParseDimoCreditSet(log types.Log) (*RegistryDimoCreditSet, error) { - event := new(RegistryDimoCreditSet) - if err := _Registry.contract.UnpackLog(event, "DimoCreditSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryDimoStreamrEnsSetIterator is returned from FilterDimoStreamrEnsSet and is used to iterate over the raw logs and unpacked data for DimoStreamrEnsSet events raised by the Registry contract. -type RegistryDimoStreamrEnsSetIterator struct { - Event *RegistryDimoStreamrEnsSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryDimoStreamrEnsSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryDimoStreamrEnsSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryDimoStreamrEnsSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryDimoStreamrEnsSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryDimoStreamrEnsSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryDimoStreamrEnsSet represents a DimoStreamrEnsSet event raised by the Registry contract. -type RegistryDimoStreamrEnsSet struct { - DimoStreamrEns string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterDimoStreamrEnsSet is a free log retrieval operation binding the contract event 0x5c6e4ce43bdb4e1b32c15a4e01073b36c28f6f16a024609785a545634d83ba69. -// -// Solidity: event DimoStreamrEnsSet(string dimoStreamrEns) -func (_Registry *RegistryFilterer) FilterDimoStreamrEnsSet(opts *bind.FilterOpts) (*RegistryDimoStreamrEnsSetIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "DimoStreamrEnsSet") - if err != nil { - return nil, err - } - return &RegistryDimoStreamrEnsSetIterator{contract: _Registry.contract, event: "DimoStreamrEnsSet", logs: logs, sub: sub}, nil -} - -// WatchDimoStreamrEnsSet is a free log subscription operation binding the contract event 0x5c6e4ce43bdb4e1b32c15a4e01073b36c28f6f16a024609785a545634d83ba69. -// -// Solidity: event DimoStreamrEnsSet(string dimoStreamrEns) -func (_Registry *RegistryFilterer) WatchDimoStreamrEnsSet(opts *bind.WatchOpts, sink chan<- *RegistryDimoStreamrEnsSet) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "DimoStreamrEnsSet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryDimoStreamrEnsSet) - if err := _Registry.contract.UnpackLog(event, "DimoStreamrEnsSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseDimoStreamrEnsSet is a log parse operation binding the contract event 0x5c6e4ce43bdb4e1b32c15a4e01073b36c28f6f16a024609785a545634d83ba69. -// -// Solidity: event DimoStreamrEnsSet(string dimoStreamrEns) -func (_Registry *RegistryFilterer) ParseDimoStreamrEnsSet(log types.Log) (*RegistryDimoStreamrEnsSet, error) { - event := new(RegistryDimoStreamrEnsSet) - if err := _Registry.contract.UnpackLog(event, "DimoStreamrEnsSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryDimoStreamrNodeSetIterator is returned from FilterDimoStreamrNodeSet and is used to iterate over the raw logs and unpacked data for DimoStreamrNodeSet events raised by the Registry contract. -type RegistryDimoStreamrNodeSetIterator struct { - Event *RegistryDimoStreamrNodeSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryDimoStreamrNodeSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryDimoStreamrNodeSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryDimoStreamrNodeSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryDimoStreamrNodeSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryDimoStreamrNodeSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryDimoStreamrNodeSet represents a DimoStreamrNodeSet event raised by the Registry contract. -type RegistryDimoStreamrNodeSet struct { - DimoStreamrNode common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterDimoStreamrNodeSet is a free log retrieval operation binding the contract event 0x49a3b2d583fcf868092d6cb62f348da2ae9e03698d56a5104a9dd5ea5cafbae7. -// -// Solidity: event DimoStreamrNodeSet(address dimoStreamrNode) -func (_Registry *RegistryFilterer) FilterDimoStreamrNodeSet(opts *bind.FilterOpts) (*RegistryDimoStreamrNodeSetIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "DimoStreamrNodeSet") - if err != nil { - return nil, err - } - return &RegistryDimoStreamrNodeSetIterator{contract: _Registry.contract, event: "DimoStreamrNodeSet", logs: logs, sub: sub}, nil -} - -// WatchDimoStreamrNodeSet is a free log subscription operation binding the contract event 0x49a3b2d583fcf868092d6cb62f348da2ae9e03698d56a5104a9dd5ea5cafbae7. -// -// Solidity: event DimoStreamrNodeSet(address dimoStreamrNode) -func (_Registry *RegistryFilterer) WatchDimoStreamrNodeSet(opts *bind.WatchOpts, sink chan<- *RegistryDimoStreamrNodeSet) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "DimoStreamrNodeSet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryDimoStreamrNodeSet) - if err := _Registry.contract.UnpackLog(event, "DimoStreamrNodeSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseDimoStreamrNodeSet is a log parse operation binding the contract event 0x49a3b2d583fcf868092d6cb62f348da2ae9e03698d56a5104a9dd5ea5cafbae7. -// -// Solidity: event DimoStreamrNodeSet(address dimoStreamrNode) -func (_Registry *RegistryFilterer) ParseDimoStreamrNodeSet(log types.Log) (*RegistryDimoStreamrNodeSet, error) { - event := new(RegistryDimoStreamrNodeSet) - if err := _Registry.contract.UnpackLog(event, "DimoStreamrNodeSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryDimoTokenSetIterator is returned from FilterDimoTokenSet and is used to iterate over the raw logs and unpacked data for DimoTokenSet events raised by the Registry contract. -type RegistryDimoTokenSetIterator struct { - Event *RegistryDimoTokenSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryDimoTokenSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryDimoTokenSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryDimoTokenSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryDimoTokenSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryDimoTokenSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryDimoTokenSet represents a DimoTokenSet event raised by the Registry contract. -type RegistryDimoTokenSet struct { - DimoToken common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterDimoTokenSet is a free log retrieval operation binding the contract event 0x3c3a6813362275982da07666bb5b9d4306b5d37c557e51bf60512c8da7a08bc8. -// -// Solidity: event DimoTokenSet(address indexed dimoToken) -func (_Registry *RegistryFilterer) FilterDimoTokenSet(opts *bind.FilterOpts, dimoToken []common.Address) (*RegistryDimoTokenSetIterator, error) { - - var dimoTokenRule []interface{} - for _, dimoTokenItem := range dimoToken { - dimoTokenRule = append(dimoTokenRule, dimoTokenItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "DimoTokenSet", dimoTokenRule) - if err != nil { - return nil, err - } - return &RegistryDimoTokenSetIterator{contract: _Registry.contract, event: "DimoTokenSet", logs: logs, sub: sub}, nil -} - -// WatchDimoTokenSet is a free log subscription operation binding the contract event 0x3c3a6813362275982da07666bb5b9d4306b5d37c557e51bf60512c8da7a08bc8. -// -// Solidity: event DimoTokenSet(address indexed dimoToken) -func (_Registry *RegistryFilterer) WatchDimoTokenSet(opts *bind.WatchOpts, sink chan<- *RegistryDimoTokenSet, dimoToken []common.Address) (event.Subscription, error) { - - var dimoTokenRule []interface{} - for _, dimoTokenItem := range dimoToken { - dimoTokenRule = append(dimoTokenRule, dimoTokenItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "DimoTokenSet", dimoTokenRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryDimoTokenSet) - if err := _Registry.contract.UnpackLog(event, "DimoTokenSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseDimoTokenSet is a log parse operation binding the contract event 0x3c3a6813362275982da07666bb5b9d4306b5d37c557e51bf60512c8da7a08bc8. -// -// Solidity: event DimoTokenSet(address indexed dimoToken) -func (_Registry *RegistryFilterer) ParseDimoTokenSet(log types.Log) (*RegistryDimoTokenSet, error) { - event := new(RegistryDimoTokenSet) - if err := _Registry.contract.UnpackLog(event, "DimoTokenSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryFoundationSetIterator is returned from FilterFoundationSet and is used to iterate over the raw logs and unpacked data for FoundationSet events raised by the Registry contract. -type RegistryFoundationSetIterator struct { - Event *RegistryFoundationSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryFoundationSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryFoundationSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryFoundationSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryFoundationSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryFoundationSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryFoundationSet represents a FoundationSet event raised by the Registry contract. -type RegistryFoundationSet struct { - Foundation common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterFoundationSet is a free log retrieval operation binding the contract event 0xfb3a44111c652758dbcb45122c36ba9fa8d5f2c5b3df984a0196dee5a0bdcc97. -// -// Solidity: event FoundationSet(address indexed foundation) -func (_Registry *RegistryFilterer) FilterFoundationSet(opts *bind.FilterOpts, foundation []common.Address) (*RegistryFoundationSetIterator, error) { - - var foundationRule []interface{} - for _, foundationItem := range foundation { - foundationRule = append(foundationRule, foundationItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "FoundationSet", foundationRule) - if err != nil { - return nil, err - } - return &RegistryFoundationSetIterator{contract: _Registry.contract, event: "FoundationSet", logs: logs, sub: sub}, nil -} - -// WatchFoundationSet is a free log subscription operation binding the contract event 0xfb3a44111c652758dbcb45122c36ba9fa8d5f2c5b3df984a0196dee5a0bdcc97. -// -// Solidity: event FoundationSet(address indexed foundation) -func (_Registry *RegistryFilterer) WatchFoundationSet(opts *bind.WatchOpts, sink chan<- *RegistryFoundationSet, foundation []common.Address) (event.Subscription, error) { - - var foundationRule []interface{} - for _, foundationItem := range foundation { - foundationRule = append(foundationRule, foundationItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "FoundationSet", foundationRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryFoundationSet) - if err := _Registry.contract.UnpackLog(event, "FoundationSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseFoundationSet is a log parse operation binding the contract event 0xfb3a44111c652758dbcb45122c36ba9fa8d5f2c5b3df984a0196dee5a0bdcc97. -// -// Solidity: event FoundationSet(address indexed foundation) -func (_Registry *RegistryFilterer) ParseFoundationSet(log types.Log) (*RegistryFoundationSet, error) { - event := new(RegistryFoundationSet) - if err := _Registry.contract.UnpackLog(event, "FoundationSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryIntegrationAttributeAddedIterator is returned from FilterIntegrationAttributeAdded and is used to iterate over the raw logs and unpacked data for IntegrationAttributeAdded events raised by the Registry contract. -type RegistryIntegrationAttributeAddedIterator struct { - Event *RegistryIntegrationAttributeAdded // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryIntegrationAttributeAddedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryIntegrationAttributeAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryIntegrationAttributeAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryIntegrationAttributeAddedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryIntegrationAttributeAddedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryIntegrationAttributeAdded represents a IntegrationAttributeAdded event raised by the Registry contract. -type RegistryIntegrationAttributeAdded struct { - Attribute string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterIntegrationAttributeAdded is a free log retrieval operation binding the contract event 0x8a60d58f652ffe56b0987cf68f5cf87f9b67e2ceeadfc9de04d2620141749504. -// -// Solidity: event IntegrationAttributeAdded(string attribute) -func (_Registry *RegistryFilterer) FilterIntegrationAttributeAdded(opts *bind.FilterOpts) (*RegistryIntegrationAttributeAddedIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "IntegrationAttributeAdded") - if err != nil { - return nil, err - } - return &RegistryIntegrationAttributeAddedIterator{contract: _Registry.contract, event: "IntegrationAttributeAdded", logs: logs, sub: sub}, nil -} - -// WatchIntegrationAttributeAdded is a free log subscription operation binding the contract event 0x8a60d58f652ffe56b0987cf68f5cf87f9b67e2ceeadfc9de04d2620141749504. -// -// Solidity: event IntegrationAttributeAdded(string attribute) -func (_Registry *RegistryFilterer) WatchIntegrationAttributeAdded(opts *bind.WatchOpts, sink chan<- *RegistryIntegrationAttributeAdded) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "IntegrationAttributeAdded") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryIntegrationAttributeAdded) - if err := _Registry.contract.UnpackLog(event, "IntegrationAttributeAdded", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseIntegrationAttributeAdded is a log parse operation binding the contract event 0x8a60d58f652ffe56b0987cf68f5cf87f9b67e2ceeadfc9de04d2620141749504. -// -// Solidity: event IntegrationAttributeAdded(string attribute) -func (_Registry *RegistryFilterer) ParseIntegrationAttributeAdded(log types.Log) (*RegistryIntegrationAttributeAdded, error) { - event := new(RegistryIntegrationAttributeAdded) - if err := _Registry.contract.UnpackLog(event, "IntegrationAttributeAdded", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryIntegrationAttributeSetIterator is returned from FilterIntegrationAttributeSet and is used to iterate over the raw logs and unpacked data for IntegrationAttributeSet events raised by the Registry contract. -type RegistryIntegrationAttributeSetIterator struct { - Event *RegistryIntegrationAttributeSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryIntegrationAttributeSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryIntegrationAttributeSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryIntegrationAttributeSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryIntegrationAttributeSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryIntegrationAttributeSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryIntegrationAttributeSet represents a IntegrationAttributeSet event raised by the Registry contract. -type RegistryIntegrationAttributeSet struct { - TokenId *big.Int - Attribute string - Info string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterIntegrationAttributeSet is a free log retrieval operation binding the contract event 0x7ad258fae6070243285178171825b61e931d6d4786b7964aa4268e3dd8635f5b. -// -// Solidity: event IntegrationAttributeSet(uint256 indexed tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) FilterIntegrationAttributeSet(opts *bind.FilterOpts, tokenId []*big.Int) (*RegistryIntegrationAttributeSetIterator, error) { - - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "IntegrationAttributeSet", tokenIdRule) - if err != nil { - return nil, err - } - return &RegistryIntegrationAttributeSetIterator{contract: _Registry.contract, event: "IntegrationAttributeSet", logs: logs, sub: sub}, nil -} - -// WatchIntegrationAttributeSet is a free log subscription operation binding the contract event 0x7ad258fae6070243285178171825b61e931d6d4786b7964aa4268e3dd8635f5b. -// -// Solidity: event IntegrationAttributeSet(uint256 indexed tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) WatchIntegrationAttributeSet(opts *bind.WatchOpts, sink chan<- *RegistryIntegrationAttributeSet, tokenId []*big.Int) (event.Subscription, error) { - - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "IntegrationAttributeSet", tokenIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryIntegrationAttributeSet) - if err := _Registry.contract.UnpackLog(event, "IntegrationAttributeSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseIntegrationAttributeSet is a log parse operation binding the contract event 0x7ad258fae6070243285178171825b61e931d6d4786b7964aa4268e3dd8635f5b. -// -// Solidity: event IntegrationAttributeSet(uint256 indexed tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) ParseIntegrationAttributeSet(log types.Log) (*RegistryIntegrationAttributeSet, error) { - event := new(RegistryIntegrationAttributeSet) - if err := _Registry.contract.UnpackLog(event, "IntegrationAttributeSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryIntegrationIdProxySetIterator is returned from FilterIntegrationIdProxySet and is used to iterate over the raw logs and unpacked data for IntegrationIdProxySet events raised by the Registry contract. -type RegistryIntegrationIdProxySetIterator struct { - Event *RegistryIntegrationIdProxySet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryIntegrationIdProxySetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryIntegrationIdProxySet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryIntegrationIdProxySet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryIntegrationIdProxySetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryIntegrationIdProxySetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryIntegrationIdProxySet represents a IntegrationIdProxySet event raised by the Registry contract. -type RegistryIntegrationIdProxySet struct { - Proxy common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterIntegrationIdProxySet is a free log retrieval operation binding the contract event 0x25dd5f73797a6c0ea7e44d94e7c58a4fdee93b784c99db224ba8a49832741ac2. -// -// Solidity: event IntegrationIdProxySet(address proxy) -func (_Registry *RegistryFilterer) FilterIntegrationIdProxySet(opts *bind.FilterOpts) (*RegistryIntegrationIdProxySetIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "IntegrationIdProxySet") - if err != nil { - return nil, err - } - return &RegistryIntegrationIdProxySetIterator{contract: _Registry.contract, event: "IntegrationIdProxySet", logs: logs, sub: sub}, nil -} - -// WatchIntegrationIdProxySet is a free log subscription operation binding the contract event 0x25dd5f73797a6c0ea7e44d94e7c58a4fdee93b784c99db224ba8a49832741ac2. -// -// Solidity: event IntegrationIdProxySet(address proxy) -func (_Registry *RegistryFilterer) WatchIntegrationIdProxySet(opts *bind.WatchOpts, sink chan<- *RegistryIntegrationIdProxySet) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "IntegrationIdProxySet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryIntegrationIdProxySet) - if err := _Registry.contract.UnpackLog(event, "IntegrationIdProxySet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseIntegrationIdProxySet is a log parse operation binding the contract event 0x25dd5f73797a6c0ea7e44d94e7c58a4fdee93b784c99db224ba8a49832741ac2. -// -// Solidity: event IntegrationIdProxySet(address proxy) -func (_Registry *RegistryFilterer) ParseIntegrationIdProxySet(log types.Log) (*RegistryIntegrationIdProxySet, error) { - event := new(RegistryIntegrationIdProxySet) - if err := _Registry.contract.UnpackLog(event, "IntegrationIdProxySet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryIntegrationNodeMintedIterator is returned from FilterIntegrationNodeMinted and is used to iterate over the raw logs and unpacked data for IntegrationNodeMinted events raised by the Registry contract. -type RegistryIntegrationNodeMintedIterator struct { - Event *RegistryIntegrationNodeMinted // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryIntegrationNodeMintedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryIntegrationNodeMinted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryIntegrationNodeMinted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryIntegrationNodeMintedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryIntegrationNodeMintedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryIntegrationNodeMinted represents a IntegrationNodeMinted event raised by the Registry contract. -type RegistryIntegrationNodeMinted struct { - TokenId *big.Int - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterIntegrationNodeMinted is a free log retrieval operation binding the contract event 0x98490372c5dc5c685bd6d9efd43eaf17e5ac95f4d4a77be5a2769330e0afa2e9. -// -// Solidity: event IntegrationNodeMinted(uint256 indexed tokenId, address indexed owner) -func (_Registry *RegistryFilterer) FilterIntegrationNodeMinted(opts *bind.FilterOpts, tokenId []*big.Int, owner []common.Address) (*RegistryIntegrationNodeMintedIterator, error) { - - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "IntegrationNodeMinted", tokenIdRule, ownerRule) - if err != nil { - return nil, err - } - return &RegistryIntegrationNodeMintedIterator{contract: _Registry.contract, event: "IntegrationNodeMinted", logs: logs, sub: sub}, nil -} - -// WatchIntegrationNodeMinted is a free log subscription operation binding the contract event 0x98490372c5dc5c685bd6d9efd43eaf17e5ac95f4d4a77be5a2769330e0afa2e9. -// -// Solidity: event IntegrationNodeMinted(uint256 indexed tokenId, address indexed owner) -func (_Registry *RegistryFilterer) WatchIntegrationNodeMinted(opts *bind.WatchOpts, sink chan<- *RegistryIntegrationNodeMinted, tokenId []*big.Int, owner []common.Address) (event.Subscription, error) { - - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "IntegrationNodeMinted", tokenIdRule, ownerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryIntegrationNodeMinted) - if err := _Registry.contract.UnpackLog(event, "IntegrationNodeMinted", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseIntegrationNodeMinted is a log parse operation binding the contract event 0x98490372c5dc5c685bd6d9efd43eaf17e5ac95f4d4a77be5a2769330e0afa2e9. -// -// Solidity: event IntegrationNodeMinted(uint256 indexed tokenId, address indexed owner) -func (_Registry *RegistryFilterer) ParseIntegrationNodeMinted(log types.Log) (*RegistryIntegrationNodeMinted, error) { - event := new(RegistryIntegrationNodeMinted) - if err := _Registry.contract.UnpackLog(event, "IntegrationNodeMinted", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryManufacturerAttributeAddedIterator is returned from FilterManufacturerAttributeAdded and is used to iterate over the raw logs and unpacked data for ManufacturerAttributeAdded events raised by the Registry contract. -type RegistryManufacturerAttributeAddedIterator struct { - Event *RegistryManufacturerAttributeAdded // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryManufacturerAttributeAddedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryManufacturerAttributeAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryManufacturerAttributeAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryManufacturerAttributeAddedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryManufacturerAttributeAddedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryManufacturerAttributeAdded represents a ManufacturerAttributeAdded event raised by the Registry contract. -type RegistryManufacturerAttributeAdded struct { - Attribute string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterManufacturerAttributeAdded is a free log retrieval operation binding the contract event 0x47ff34ba477617ab4dc2aefe5ea26ba19a207b052ec44d59b86c2ff3e7fd53b3. -// -// Solidity: event ManufacturerAttributeAdded(string attribute) -func (_Registry *RegistryFilterer) FilterManufacturerAttributeAdded(opts *bind.FilterOpts) (*RegistryManufacturerAttributeAddedIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "ManufacturerAttributeAdded") - if err != nil { - return nil, err - } - return &RegistryManufacturerAttributeAddedIterator{contract: _Registry.contract, event: "ManufacturerAttributeAdded", logs: logs, sub: sub}, nil -} - -// WatchManufacturerAttributeAdded is a free log subscription operation binding the contract event 0x47ff34ba477617ab4dc2aefe5ea26ba19a207b052ec44d59b86c2ff3e7fd53b3. -// -// Solidity: event ManufacturerAttributeAdded(string attribute) -func (_Registry *RegistryFilterer) WatchManufacturerAttributeAdded(opts *bind.WatchOpts, sink chan<- *RegistryManufacturerAttributeAdded) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "ManufacturerAttributeAdded") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryManufacturerAttributeAdded) - if err := _Registry.contract.UnpackLog(event, "ManufacturerAttributeAdded", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseManufacturerAttributeAdded is a log parse operation binding the contract event 0x47ff34ba477617ab4dc2aefe5ea26ba19a207b052ec44d59b86c2ff3e7fd53b3. -// -// Solidity: event ManufacturerAttributeAdded(string attribute) -func (_Registry *RegistryFilterer) ParseManufacturerAttributeAdded(log types.Log) (*RegistryManufacturerAttributeAdded, error) { - event := new(RegistryManufacturerAttributeAdded) - if err := _Registry.contract.UnpackLog(event, "ManufacturerAttributeAdded", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryManufacturerAttributeSetIterator is returned from FilterManufacturerAttributeSet and is used to iterate over the raw logs and unpacked data for ManufacturerAttributeSet events raised by the Registry contract. -type RegistryManufacturerAttributeSetIterator struct { - Event *RegistryManufacturerAttributeSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryManufacturerAttributeSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryManufacturerAttributeSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryManufacturerAttributeSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryManufacturerAttributeSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryManufacturerAttributeSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryManufacturerAttributeSet represents a ManufacturerAttributeSet event raised by the Registry contract. -type RegistryManufacturerAttributeSet struct { - TokenId *big.Int - Attribute string - Info string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterManufacturerAttributeSet is a free log retrieval operation binding the contract event 0xb81a4ce1a42b79dd48c79a2c5a0b170cebf3c78b5ecb25df31066eb9b656a929. -// -// Solidity: event ManufacturerAttributeSet(uint256 tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) FilterManufacturerAttributeSet(opts *bind.FilterOpts) (*RegistryManufacturerAttributeSetIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "ManufacturerAttributeSet") - if err != nil { - return nil, err - } - return &RegistryManufacturerAttributeSetIterator{contract: _Registry.contract, event: "ManufacturerAttributeSet", logs: logs, sub: sub}, nil -} - -// WatchManufacturerAttributeSet is a free log subscription operation binding the contract event 0xb81a4ce1a42b79dd48c79a2c5a0b170cebf3c78b5ecb25df31066eb9b656a929. -// -// Solidity: event ManufacturerAttributeSet(uint256 tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) WatchManufacturerAttributeSet(opts *bind.WatchOpts, sink chan<- *RegistryManufacturerAttributeSet) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "ManufacturerAttributeSet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryManufacturerAttributeSet) - if err := _Registry.contract.UnpackLog(event, "ManufacturerAttributeSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseManufacturerAttributeSet is a log parse operation binding the contract event 0xb81a4ce1a42b79dd48c79a2c5a0b170cebf3c78b5ecb25df31066eb9b656a929. -// -// Solidity: event ManufacturerAttributeSet(uint256 tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) ParseManufacturerAttributeSet(log types.Log) (*RegistryManufacturerAttributeSet, error) { - event := new(RegistryManufacturerAttributeSet) - if err := _Registry.contract.UnpackLog(event, "ManufacturerAttributeSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryManufacturerIdProxySetIterator is returned from FilterManufacturerIdProxySet and is used to iterate over the raw logs and unpacked data for ManufacturerIdProxySet events raised by the Registry contract. -type RegistryManufacturerIdProxySetIterator struct { - Event *RegistryManufacturerIdProxySet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryManufacturerIdProxySetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryManufacturerIdProxySet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryManufacturerIdProxySet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryManufacturerIdProxySetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryManufacturerIdProxySetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryManufacturerIdProxySet represents a ManufacturerIdProxySet event raised by the Registry contract. -type RegistryManufacturerIdProxySet struct { - Proxy common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterManufacturerIdProxySet is a free log retrieval operation binding the contract event 0xf9bca5f2d5444f9fbb6e6d0fb2b4c2cda766bd110a1326420b883ffc6978f5e2. -// -// Solidity: event ManufacturerIdProxySet(address indexed proxy) -func (_Registry *RegistryFilterer) FilterManufacturerIdProxySet(opts *bind.FilterOpts, proxy []common.Address) (*RegistryManufacturerIdProxySetIterator, error) { - - var proxyRule []interface{} - for _, proxyItem := range proxy { - proxyRule = append(proxyRule, proxyItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "ManufacturerIdProxySet", proxyRule) - if err != nil { - return nil, err - } - return &RegistryManufacturerIdProxySetIterator{contract: _Registry.contract, event: "ManufacturerIdProxySet", logs: logs, sub: sub}, nil -} - -// WatchManufacturerIdProxySet is a free log subscription operation binding the contract event 0xf9bca5f2d5444f9fbb6e6d0fb2b4c2cda766bd110a1326420b883ffc6978f5e2. -// -// Solidity: event ManufacturerIdProxySet(address indexed proxy) -func (_Registry *RegistryFilterer) WatchManufacturerIdProxySet(opts *bind.WatchOpts, sink chan<- *RegistryManufacturerIdProxySet, proxy []common.Address) (event.Subscription, error) { - - var proxyRule []interface{} - for _, proxyItem := range proxy { - proxyRule = append(proxyRule, proxyItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "ManufacturerIdProxySet", proxyRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryManufacturerIdProxySet) - if err := _Registry.contract.UnpackLog(event, "ManufacturerIdProxySet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseManufacturerIdProxySet is a log parse operation binding the contract event 0xf9bca5f2d5444f9fbb6e6d0fb2b4c2cda766bd110a1326420b883ffc6978f5e2. -// -// Solidity: event ManufacturerIdProxySet(address indexed proxy) -func (_Registry *RegistryFilterer) ParseManufacturerIdProxySet(log types.Log) (*RegistryManufacturerIdProxySet, error) { - event := new(RegistryManufacturerIdProxySet) - if err := _Registry.contract.UnpackLog(event, "ManufacturerIdProxySet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryManufacturerLicenseSetIterator is returned from FilterManufacturerLicenseSet and is used to iterate over the raw logs and unpacked data for ManufacturerLicenseSet events raised by the Registry contract. -type RegistryManufacturerLicenseSetIterator struct { - Event *RegistryManufacturerLicenseSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryManufacturerLicenseSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryManufacturerLicenseSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryManufacturerLicenseSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryManufacturerLicenseSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryManufacturerLicenseSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryManufacturerLicenseSet represents a ManufacturerLicenseSet event raised by the Registry contract. -type RegistryManufacturerLicenseSet struct { - ManufacturerLicense common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterManufacturerLicenseSet is a free log retrieval operation binding the contract event 0x52ce79552a0de48e63f55aa197389ac337a67a7fed9ba71fe580aeaedd7a05e9. -// -// Solidity: event ManufacturerLicenseSet(address indexed manufacturerLicense) -func (_Registry *RegistryFilterer) FilterManufacturerLicenseSet(opts *bind.FilterOpts, manufacturerLicense []common.Address) (*RegistryManufacturerLicenseSetIterator, error) { - - var manufacturerLicenseRule []interface{} - for _, manufacturerLicenseItem := range manufacturerLicense { - manufacturerLicenseRule = append(manufacturerLicenseRule, manufacturerLicenseItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "ManufacturerLicenseSet", manufacturerLicenseRule) - if err != nil { - return nil, err - } - return &RegistryManufacturerLicenseSetIterator{contract: _Registry.contract, event: "ManufacturerLicenseSet", logs: logs, sub: sub}, nil -} - -// WatchManufacturerLicenseSet is a free log subscription operation binding the contract event 0x52ce79552a0de48e63f55aa197389ac337a67a7fed9ba71fe580aeaedd7a05e9. -// -// Solidity: event ManufacturerLicenseSet(address indexed manufacturerLicense) -func (_Registry *RegistryFilterer) WatchManufacturerLicenseSet(opts *bind.WatchOpts, sink chan<- *RegistryManufacturerLicenseSet, manufacturerLicense []common.Address) (event.Subscription, error) { - - var manufacturerLicenseRule []interface{} - for _, manufacturerLicenseItem := range manufacturerLicense { - manufacturerLicenseRule = append(manufacturerLicenseRule, manufacturerLicenseItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "ManufacturerLicenseSet", manufacturerLicenseRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryManufacturerLicenseSet) - if err := _Registry.contract.UnpackLog(event, "ManufacturerLicenseSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseManufacturerLicenseSet is a log parse operation binding the contract event 0x52ce79552a0de48e63f55aa197389ac337a67a7fed9ba71fe580aeaedd7a05e9. -// -// Solidity: event ManufacturerLicenseSet(address indexed manufacturerLicense) -func (_Registry *RegistryFilterer) ParseManufacturerLicenseSet(log types.Log) (*RegistryManufacturerLicenseSet, error) { - event := new(RegistryManufacturerLicenseSet) - if err := _Registry.contract.UnpackLog(event, "ManufacturerLicenseSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryManufacturerNodeMintedIterator is returned from FilterManufacturerNodeMinted and is used to iterate over the raw logs and unpacked data for ManufacturerNodeMinted events raised by the Registry contract. -type RegistryManufacturerNodeMintedIterator struct { - Event *RegistryManufacturerNodeMinted // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryManufacturerNodeMintedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryManufacturerNodeMinted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryManufacturerNodeMinted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryManufacturerNodeMintedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryManufacturerNodeMintedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryManufacturerNodeMinted represents a ManufacturerNodeMinted event raised by the Registry contract. -type RegistryManufacturerNodeMinted struct { - Name string - TokenId *big.Int - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterManufacturerNodeMinted is a free log retrieval operation binding the contract event 0xc1279f9a9b23f63ed6e8fe22568fdb1962597404fb8ecb1d4b1722ac5e7a4343. -// -// Solidity: event ManufacturerNodeMinted(string name, uint256 tokenId, address indexed owner) -func (_Registry *RegistryFilterer) FilterManufacturerNodeMinted(opts *bind.FilterOpts, owner []common.Address) (*RegistryManufacturerNodeMintedIterator, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "ManufacturerNodeMinted", ownerRule) - if err != nil { - return nil, err - } - return &RegistryManufacturerNodeMintedIterator{contract: _Registry.contract, event: "ManufacturerNodeMinted", logs: logs, sub: sub}, nil -} - -// WatchManufacturerNodeMinted is a free log subscription operation binding the contract event 0xc1279f9a9b23f63ed6e8fe22568fdb1962597404fb8ecb1d4b1722ac5e7a4343. -// -// Solidity: event ManufacturerNodeMinted(string name, uint256 tokenId, address indexed owner) -func (_Registry *RegistryFilterer) WatchManufacturerNodeMinted(opts *bind.WatchOpts, sink chan<- *RegistryManufacturerNodeMinted, owner []common.Address) (event.Subscription, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "ManufacturerNodeMinted", ownerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryManufacturerNodeMinted) - if err := _Registry.contract.UnpackLog(event, "ManufacturerNodeMinted", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseManufacturerNodeMinted is a log parse operation binding the contract event 0xc1279f9a9b23f63ed6e8fe22568fdb1962597404fb8ecb1d4b1722ac5e7a4343. -// -// Solidity: event ManufacturerNodeMinted(string name, uint256 tokenId, address indexed owner) -func (_Registry *RegistryFilterer) ParseManufacturerNodeMinted(log types.Log) (*RegistryManufacturerNodeMinted, error) { - event := new(RegistryManufacturerNodeMinted) - if err := _Registry.contract.UnpackLog(event, "ManufacturerNodeMinted", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryManufacturerTableSetIterator is returned from FilterManufacturerTableSet and is used to iterate over the raw logs and unpacked data for ManufacturerTableSet events raised by the Registry contract. -type RegistryManufacturerTableSetIterator struct { - Event *RegistryManufacturerTableSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryManufacturerTableSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryManufacturerTableSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryManufacturerTableSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryManufacturerTableSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryManufacturerTableSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryManufacturerTableSet represents a ManufacturerTableSet event raised by the Registry contract. -type RegistryManufacturerTableSet struct { - ManufacturerId *big.Int - TableId *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterManufacturerTableSet is a free log retrieval operation binding the contract event 0x753affc1c97f48f4eb21cf9ca5906ba280ab310171483c29e73826d74505b3cf. -// -// Solidity: event ManufacturerTableSet(uint256 indexed manufacturerId, uint256 indexed tableId) -func (_Registry *RegistryFilterer) FilterManufacturerTableSet(opts *bind.FilterOpts, manufacturerId []*big.Int, tableId []*big.Int) (*RegistryManufacturerTableSetIterator, error) { - - var manufacturerIdRule []interface{} - for _, manufacturerIdItem := range manufacturerId { - manufacturerIdRule = append(manufacturerIdRule, manufacturerIdItem) - } - var tableIdRule []interface{} - for _, tableIdItem := range tableId { - tableIdRule = append(tableIdRule, tableIdItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "ManufacturerTableSet", manufacturerIdRule, tableIdRule) - if err != nil { - return nil, err - } - return &RegistryManufacturerTableSetIterator{contract: _Registry.contract, event: "ManufacturerTableSet", logs: logs, sub: sub}, nil -} - -// WatchManufacturerTableSet is a free log subscription operation binding the contract event 0x753affc1c97f48f4eb21cf9ca5906ba280ab310171483c29e73826d74505b3cf. -// -// Solidity: event ManufacturerTableSet(uint256 indexed manufacturerId, uint256 indexed tableId) -func (_Registry *RegistryFilterer) WatchManufacturerTableSet(opts *bind.WatchOpts, sink chan<- *RegistryManufacturerTableSet, manufacturerId []*big.Int, tableId []*big.Int) (event.Subscription, error) { - - var manufacturerIdRule []interface{} - for _, manufacturerIdItem := range manufacturerId { - manufacturerIdRule = append(manufacturerIdRule, manufacturerIdItem) - } - var tableIdRule []interface{} - for _, tableIdItem := range tableId { - tableIdRule = append(tableIdRule, tableIdItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "ManufacturerTableSet", manufacturerIdRule, tableIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryManufacturerTableSet) - if err := _Registry.contract.UnpackLog(event, "ManufacturerTableSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseManufacturerTableSet is a log parse operation binding the contract event 0x753affc1c97f48f4eb21cf9ca5906ba280ab310171483c29e73826d74505b3cf. -// -// Solidity: event ManufacturerTableSet(uint256 indexed manufacturerId, uint256 indexed tableId) -func (_Registry *RegistryFilterer) ParseManufacturerTableSet(log types.Log) (*RegistryManufacturerTableSet, error) { - event := new(RegistryManufacturerTableSet) - if err := _Registry.contract.UnpackLog(event, "ManufacturerTableSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryModuleAddedIterator is returned from FilterModuleAdded and is used to iterate over the raw logs and unpacked data for ModuleAdded events raised by the Registry contract. -type RegistryModuleAddedIterator struct { - Event *RegistryModuleAdded // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryModuleAddedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryModuleAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryModuleAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryModuleAddedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryModuleAddedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryModuleAdded represents a ModuleAdded event raised by the Registry contract. -type RegistryModuleAdded struct { - ModuleAddr common.Address - Selectors [][4]byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterModuleAdded is a free log retrieval operation binding the contract event 0x02d0c334c706cd2f08faf7bc03674fc7f3970dd8921776c655069cde33b7fb29. -// -// Solidity: event ModuleAdded(address indexed moduleAddr, bytes4[] selectors) -func (_Registry *RegistryFilterer) FilterModuleAdded(opts *bind.FilterOpts, moduleAddr []common.Address) (*RegistryModuleAddedIterator, error) { - - var moduleAddrRule []interface{} - for _, moduleAddrItem := range moduleAddr { - moduleAddrRule = append(moduleAddrRule, moduleAddrItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "ModuleAdded", moduleAddrRule) - if err != nil { - return nil, err - } - return &RegistryModuleAddedIterator{contract: _Registry.contract, event: "ModuleAdded", logs: logs, sub: sub}, nil -} - -// WatchModuleAdded is a free log subscription operation binding the contract event 0x02d0c334c706cd2f08faf7bc03674fc7f3970dd8921776c655069cde33b7fb29. -// -// Solidity: event ModuleAdded(address indexed moduleAddr, bytes4[] selectors) -func (_Registry *RegistryFilterer) WatchModuleAdded(opts *bind.WatchOpts, sink chan<- *RegistryModuleAdded, moduleAddr []common.Address) (event.Subscription, error) { - - var moduleAddrRule []interface{} - for _, moduleAddrItem := range moduleAddr { - moduleAddrRule = append(moduleAddrRule, moduleAddrItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "ModuleAdded", moduleAddrRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryModuleAdded) - if err := _Registry.contract.UnpackLog(event, "ModuleAdded", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseModuleAdded is a log parse operation binding the contract event 0x02d0c334c706cd2f08faf7bc03674fc7f3970dd8921776c655069cde33b7fb29. -// -// Solidity: event ModuleAdded(address indexed moduleAddr, bytes4[] selectors) -func (_Registry *RegistryFilterer) ParseModuleAdded(log types.Log) (*RegistryModuleAdded, error) { - event := new(RegistryModuleAdded) - if err := _Registry.contract.UnpackLog(event, "ModuleAdded", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryModuleRemovedIterator is returned from FilterModuleRemoved and is used to iterate over the raw logs and unpacked data for ModuleRemoved events raised by the Registry contract. -type RegistryModuleRemovedIterator struct { - Event *RegistryModuleRemoved // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryModuleRemovedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryModuleRemoved) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryModuleRemoved) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryModuleRemovedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryModuleRemovedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryModuleRemoved represents a ModuleRemoved event raised by the Registry contract. -type RegistryModuleRemoved struct { - ModuleAddr common.Address - Selectors [][4]byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterModuleRemoved is a free log retrieval operation binding the contract event 0x7c3eb4f9083f75cbed2bd3f703e24b4bbcb77d345d3c50945f3abf3e967755cb. -// -// Solidity: event ModuleRemoved(address indexed moduleAddr, bytes4[] selectors) -func (_Registry *RegistryFilterer) FilterModuleRemoved(opts *bind.FilterOpts, moduleAddr []common.Address) (*RegistryModuleRemovedIterator, error) { - - var moduleAddrRule []interface{} - for _, moduleAddrItem := range moduleAddr { - moduleAddrRule = append(moduleAddrRule, moduleAddrItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "ModuleRemoved", moduleAddrRule) - if err != nil { - return nil, err - } - return &RegistryModuleRemovedIterator{contract: _Registry.contract, event: "ModuleRemoved", logs: logs, sub: sub}, nil -} - -// WatchModuleRemoved is a free log subscription operation binding the contract event 0x7c3eb4f9083f75cbed2bd3f703e24b4bbcb77d345d3c50945f3abf3e967755cb. -// -// Solidity: event ModuleRemoved(address indexed moduleAddr, bytes4[] selectors) -func (_Registry *RegistryFilterer) WatchModuleRemoved(opts *bind.WatchOpts, sink chan<- *RegistryModuleRemoved, moduleAddr []common.Address) (event.Subscription, error) { - - var moduleAddrRule []interface{} - for _, moduleAddrItem := range moduleAddr { - moduleAddrRule = append(moduleAddrRule, moduleAddrItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "ModuleRemoved", moduleAddrRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryModuleRemoved) - if err := _Registry.contract.UnpackLog(event, "ModuleRemoved", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseModuleRemoved is a log parse operation binding the contract event 0x7c3eb4f9083f75cbed2bd3f703e24b4bbcb77d345d3c50945f3abf3e967755cb. -// -// Solidity: event ModuleRemoved(address indexed moduleAddr, bytes4[] selectors) -func (_Registry *RegistryFilterer) ParseModuleRemoved(log types.Log) (*RegistryModuleRemoved, error) { - event := new(RegistryModuleRemoved) - if err := _Registry.contract.UnpackLog(event, "ModuleRemoved", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryModuleUpdatedIterator is returned from FilterModuleUpdated and is used to iterate over the raw logs and unpacked data for ModuleUpdated events raised by the Registry contract. -type RegistryModuleUpdatedIterator struct { - Event *RegistryModuleUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryModuleUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryModuleUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryModuleUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryModuleUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryModuleUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryModuleUpdated represents a ModuleUpdated event raised by the Registry contract. -type RegistryModuleUpdated struct { - OldImplementation common.Address - NewImplementation common.Address - OldSelectors [][4]byte - NewSelectors [][4]byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterModuleUpdated is a free log retrieval operation binding the contract event 0xa062c2c046aa14dc9284b13bde77061cb034f0aa820f20057af6b164651eaa08. -// -// Solidity: event ModuleUpdated(address indexed oldImplementation, address indexed newImplementation, bytes4[] oldSelectors, bytes4[] newSelectors) -func (_Registry *RegistryFilterer) FilterModuleUpdated(opts *bind.FilterOpts, oldImplementation []common.Address, newImplementation []common.Address) (*RegistryModuleUpdatedIterator, error) { - - var oldImplementationRule []interface{} - for _, oldImplementationItem := range oldImplementation { - oldImplementationRule = append(oldImplementationRule, oldImplementationItem) - } - var newImplementationRule []interface{} - for _, newImplementationItem := range newImplementation { - newImplementationRule = append(newImplementationRule, newImplementationItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "ModuleUpdated", oldImplementationRule, newImplementationRule) - if err != nil { - return nil, err - } - return &RegistryModuleUpdatedIterator{contract: _Registry.contract, event: "ModuleUpdated", logs: logs, sub: sub}, nil -} - -// WatchModuleUpdated is a free log subscription operation binding the contract event 0xa062c2c046aa14dc9284b13bde77061cb034f0aa820f20057af6b164651eaa08. -// -// Solidity: event ModuleUpdated(address indexed oldImplementation, address indexed newImplementation, bytes4[] oldSelectors, bytes4[] newSelectors) -func (_Registry *RegistryFilterer) WatchModuleUpdated(opts *bind.WatchOpts, sink chan<- *RegistryModuleUpdated, oldImplementation []common.Address, newImplementation []common.Address) (event.Subscription, error) { - - var oldImplementationRule []interface{} - for _, oldImplementationItem := range oldImplementation { - oldImplementationRule = append(oldImplementationRule, oldImplementationItem) - } - var newImplementationRule []interface{} - for _, newImplementationItem := range newImplementation { - newImplementationRule = append(newImplementationRule, newImplementationItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "ModuleUpdated", oldImplementationRule, newImplementationRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryModuleUpdated) - if err := _Registry.contract.UnpackLog(event, "ModuleUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseModuleUpdated is a log parse operation binding the contract event 0xa062c2c046aa14dc9284b13bde77061cb034f0aa820f20057af6b164651eaa08. -// -// Solidity: event ModuleUpdated(address indexed oldImplementation, address indexed newImplementation, bytes4[] oldSelectors, bytes4[] newSelectors) -func (_Registry *RegistryFilterer) ParseModuleUpdated(log types.Log) (*RegistryModuleUpdated, error) { - event := new(RegistryModuleUpdated) - if err := _Registry.contract.UnpackLog(event, "ModuleUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryOperationCostSetIterator is returned from FilterOperationCostSet and is used to iterate over the raw logs and unpacked data for OperationCostSet events raised by the Registry contract. -type RegistryOperationCostSetIterator struct { - Event *RegistryOperationCostSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryOperationCostSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryOperationCostSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryOperationCostSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryOperationCostSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryOperationCostSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryOperationCostSet represents a OperationCostSet event raised by the Registry contract. -type RegistryOperationCostSet struct { - Operation [32]byte - Cost *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterOperationCostSet is a free log retrieval operation binding the contract event 0x2f2e341f7af8c198c5fe4136f45dee9ed56441686b2357204a9d440c12c4f6af. -// -// Solidity: event OperationCostSet(bytes32 operation, uint256 cost) -func (_Registry *RegistryFilterer) FilterOperationCostSet(opts *bind.FilterOpts) (*RegistryOperationCostSetIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "OperationCostSet") - if err != nil { - return nil, err - } - return &RegistryOperationCostSetIterator{contract: _Registry.contract, event: "OperationCostSet", logs: logs, sub: sub}, nil -} - -// WatchOperationCostSet is a free log subscription operation binding the contract event 0x2f2e341f7af8c198c5fe4136f45dee9ed56441686b2357204a9d440c12c4f6af. -// -// Solidity: event OperationCostSet(bytes32 operation, uint256 cost) -func (_Registry *RegistryFilterer) WatchOperationCostSet(opts *bind.WatchOpts, sink chan<- *RegistryOperationCostSet) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "OperationCostSet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryOperationCostSet) - if err := _Registry.contract.UnpackLog(event, "OperationCostSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseOperationCostSet is a log parse operation binding the contract event 0x2f2e341f7af8c198c5fe4136f45dee9ed56441686b2357204a9d440c12c4f6af. -// -// Solidity: event OperationCostSet(bytes32 operation, uint256 cost) -func (_Registry *RegistryFilterer) ParseOperationCostSet(log types.Log) (*RegistryOperationCostSet, error) { - event := new(RegistryOperationCostSet) - if err := _Registry.contract.UnpackLog(event, "OperationCostSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryRoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the Registry contract. -type RegistryRoleAdminChangedIterator struct { - Event *RegistryRoleAdminChanged // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryRoleAdminChangedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryRoleAdminChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryRoleAdminChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryRoleAdminChangedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryRoleAdminChangedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryRoleAdminChanged represents a RoleAdminChanged event raised by the Registry contract. -type RegistryRoleAdminChanged struct { - Role [32]byte - PreviousAdminRole [32]byte - NewAdminRole [32]byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterRoleAdminChanged is a free log retrieval operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. -// -// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) -func (_Registry *RegistryFilterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*RegistryRoleAdminChangedIterator, error) { - - var roleRule []interface{} - for _, roleItem := range role { - roleRule = append(roleRule, roleItem) - } - var previousAdminRoleRule []interface{} - for _, previousAdminRoleItem := range previousAdminRole { - previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) - } - var newAdminRoleRule []interface{} - for _, newAdminRoleItem := range newAdminRole { - newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) - if err != nil { - return nil, err - } - return &RegistryRoleAdminChangedIterator{contract: _Registry.contract, event: "RoleAdminChanged", logs: logs, sub: sub}, nil -} - -// WatchRoleAdminChanged is a free log subscription operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. -// -// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) -func (_Registry *RegistryFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *RegistryRoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error) { - - var roleRule []interface{} - for _, roleItem := range role { - roleRule = append(roleRule, roleItem) - } - var previousAdminRoleRule []interface{} - for _, previousAdminRoleItem := range previousAdminRole { - previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) - } - var newAdminRoleRule []interface{} - for _, newAdminRoleItem := range newAdminRole { - newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryRoleAdminChanged) - if err := _Registry.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseRoleAdminChanged is a log parse operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. -// -// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) -func (_Registry *RegistryFilterer) ParseRoleAdminChanged(log types.Log) (*RegistryRoleAdminChanged, error) { - event := new(RegistryRoleAdminChanged) - if err := _Registry.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryRoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the Registry contract. -type RegistryRoleGrantedIterator struct { - Event *RegistryRoleGranted // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryRoleGrantedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryRoleGranted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryRoleGranted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryRoleGrantedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryRoleGrantedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryRoleGranted represents a RoleGranted event raised by the Registry contract. -type RegistryRoleGranted struct { - Role [32]byte - Account common.Address - Sender common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterRoleGranted is a free log retrieval operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. -// -// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) -func (_Registry *RegistryFilterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*RegistryRoleGrantedIterator, error) { - - var roleRule []interface{} - for _, roleItem := range role { - roleRule = append(roleRule, roleItem) - } - var accountRule []interface{} - for _, accountItem := range account { - accountRule = append(accountRule, accountItem) - } - var senderRule []interface{} - for _, senderItem := range sender { - senderRule = append(senderRule, senderItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) - if err != nil { - return nil, err - } - return &RegistryRoleGrantedIterator{contract: _Registry.contract, event: "RoleGranted", logs: logs, sub: sub}, nil -} - -// WatchRoleGranted is a free log subscription operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. -// -// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) -func (_Registry *RegistryFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *RegistryRoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { - - var roleRule []interface{} - for _, roleItem := range role { - roleRule = append(roleRule, roleItem) - } - var accountRule []interface{} - for _, accountItem := range account { - accountRule = append(accountRule, accountItem) - } - var senderRule []interface{} - for _, senderItem := range sender { - senderRule = append(senderRule, senderItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryRoleGranted) - if err := _Registry.contract.UnpackLog(event, "RoleGranted", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseRoleGranted is a log parse operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. -// -// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) -func (_Registry *RegistryFilterer) ParseRoleGranted(log types.Log) (*RegistryRoleGranted, error) { - event := new(RegistryRoleGranted) - if err := _Registry.contract.UnpackLog(event, "RoleGranted", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryRoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the Registry contract. -type RegistryRoleRevokedIterator struct { - Event *RegistryRoleRevoked // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryRoleRevokedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryRoleRevoked) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryRoleRevoked) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryRoleRevokedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryRoleRevokedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryRoleRevoked represents a RoleRevoked event raised by the Registry contract. -type RegistryRoleRevoked struct { - Role [32]byte - Account common.Address - Sender common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterRoleRevoked is a free log retrieval operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. -// -// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) -func (_Registry *RegistryFilterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*RegistryRoleRevokedIterator, error) { - - var roleRule []interface{} - for _, roleItem := range role { - roleRule = append(roleRule, roleItem) - } - var accountRule []interface{} - for _, accountItem := range account { - accountRule = append(accountRule, accountItem) - } - var senderRule []interface{} - for _, senderItem := range sender { - senderRule = append(senderRule, senderItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) - if err != nil { - return nil, err - } - return &RegistryRoleRevokedIterator{contract: _Registry.contract, event: "RoleRevoked", logs: logs, sub: sub}, nil -} - -// WatchRoleRevoked is a free log subscription operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. -// -// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) -func (_Registry *RegistryFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *RegistryRoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { - - var roleRule []interface{} - for _, roleItem := range role { - roleRule = append(roleRule, roleItem) - } - var accountRule []interface{} - for _, accountItem := range account { - accountRule = append(accountRule, accountItem) - } - var senderRule []interface{} - for _, senderItem := range sender { - senderRule = append(senderRule, senderItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryRoleRevoked) - if err := _Registry.contract.UnpackLog(event, "RoleRevoked", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseRoleRevoked is a log parse operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. -// -// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) -func (_Registry *RegistryFilterer) ParseRoleRevoked(log types.Log) (*RegistryRoleRevoked, error) { - event := new(RegistryRoleRevoked) - if err := _Registry.contract.UnpackLog(event, "RoleRevoked", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryStreamRegistrySetIterator is returned from FilterStreamRegistrySet and is used to iterate over the raw logs and unpacked data for StreamRegistrySet events raised by the Registry contract. -type RegistryStreamRegistrySetIterator struct { - Event *RegistryStreamRegistrySet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryStreamRegistrySetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryStreamRegistrySet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryStreamRegistrySet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryStreamRegistrySetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryStreamRegistrySetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryStreamRegistrySet represents a StreamRegistrySet event raised by the Registry contract. -type RegistryStreamRegistrySet struct { - StreamRegistry common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterStreamRegistrySet is a free log retrieval operation binding the contract event 0x42d068f44efba28cc4aa260e8fd67e7d93abf8215c8a61b4dbbc3eaf0ab39f56. -// -// Solidity: event StreamRegistrySet(address streamRegistry) -func (_Registry *RegistryFilterer) FilterStreamRegistrySet(opts *bind.FilterOpts) (*RegistryStreamRegistrySetIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "StreamRegistrySet") - if err != nil { - return nil, err - } - return &RegistryStreamRegistrySetIterator{contract: _Registry.contract, event: "StreamRegistrySet", logs: logs, sub: sub}, nil -} - -// WatchStreamRegistrySet is a free log subscription operation binding the contract event 0x42d068f44efba28cc4aa260e8fd67e7d93abf8215c8a61b4dbbc3eaf0ab39f56. -// -// Solidity: event StreamRegistrySet(address streamRegistry) -func (_Registry *RegistryFilterer) WatchStreamRegistrySet(opts *bind.WatchOpts, sink chan<- *RegistryStreamRegistrySet) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "StreamRegistrySet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryStreamRegistrySet) - if err := _Registry.contract.UnpackLog(event, "StreamRegistrySet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseStreamRegistrySet is a log parse operation binding the contract event 0x42d068f44efba28cc4aa260e8fd67e7d93abf8215c8a61b4dbbc3eaf0ab39f56. -// -// Solidity: event StreamRegistrySet(address streamRegistry) -func (_Registry *RegistryFilterer) ParseStreamRegistrySet(log types.Log) (*RegistryStreamRegistrySet, error) { - event := new(RegistryStreamRegistrySet) - if err := _Registry.contract.UnpackLog(event, "StreamRegistrySet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistrySubscribedToVehicleStreamIterator is returned from FilterSubscribedToVehicleStream and is used to iterate over the raw logs and unpacked data for SubscribedToVehicleStream events raised by the Registry contract. -type RegistrySubscribedToVehicleStreamIterator struct { - Event *RegistrySubscribedToVehicleStream // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistrySubscribedToVehicleStreamIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistrySubscribedToVehicleStream) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistrySubscribedToVehicleStream) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistrySubscribedToVehicleStreamIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistrySubscribedToVehicleStreamIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistrySubscribedToVehicleStream represents a SubscribedToVehicleStream event raised by the Registry contract. -type RegistrySubscribedToVehicleStream struct { - StreamId string - Subscriber common.Address - ExpirationTime *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSubscribedToVehicleStream is a free log retrieval operation binding the contract event 0x316c96770fe2528453ad15ac8843953cbc659399f006200f7d61fe124720d607. -// -// Solidity: event SubscribedToVehicleStream(string streamId, address indexed subscriber, uint256 expirationTime) -func (_Registry *RegistryFilterer) FilterSubscribedToVehicleStream(opts *bind.FilterOpts, subscriber []common.Address) (*RegistrySubscribedToVehicleStreamIterator, error) { - - var subscriberRule []interface{} - for _, subscriberItem := range subscriber { - subscriberRule = append(subscriberRule, subscriberItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "SubscribedToVehicleStream", subscriberRule) - if err != nil { - return nil, err - } - return &RegistrySubscribedToVehicleStreamIterator{contract: _Registry.contract, event: "SubscribedToVehicleStream", logs: logs, sub: sub}, nil -} - -// WatchSubscribedToVehicleStream is a free log subscription operation binding the contract event 0x316c96770fe2528453ad15ac8843953cbc659399f006200f7d61fe124720d607. -// -// Solidity: event SubscribedToVehicleStream(string streamId, address indexed subscriber, uint256 expirationTime) -func (_Registry *RegistryFilterer) WatchSubscribedToVehicleStream(opts *bind.WatchOpts, sink chan<- *RegistrySubscribedToVehicleStream, subscriber []common.Address) (event.Subscription, error) { - - var subscriberRule []interface{} - for _, subscriberItem := range subscriber { - subscriberRule = append(subscriberRule, subscriberItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "SubscribedToVehicleStream", subscriberRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistrySubscribedToVehicleStream) - if err := _Registry.contract.UnpackLog(event, "SubscribedToVehicleStream", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSubscribedToVehicleStream is a log parse operation binding the contract event 0x316c96770fe2528453ad15ac8843953cbc659399f006200f7d61fe124720d607. -// -// Solidity: event SubscribedToVehicleStream(string streamId, address indexed subscriber, uint256 expirationTime) -func (_Registry *RegistryFilterer) ParseSubscribedToVehicleStream(log types.Log) (*RegistrySubscribedToVehicleStream, error) { - event := new(RegistrySubscribedToVehicleStream) - if err := _Registry.contract.UnpackLog(event, "SubscribedToVehicleStream", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistrySyntheticDeviceAttributeAddedIterator is returned from FilterSyntheticDeviceAttributeAdded and is used to iterate over the raw logs and unpacked data for SyntheticDeviceAttributeAdded events raised by the Registry contract. -type RegistrySyntheticDeviceAttributeAddedIterator struct { - Event *RegistrySyntheticDeviceAttributeAdded // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistrySyntheticDeviceAttributeAddedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistrySyntheticDeviceAttributeAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistrySyntheticDeviceAttributeAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistrySyntheticDeviceAttributeAddedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistrySyntheticDeviceAttributeAddedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistrySyntheticDeviceAttributeAdded represents a SyntheticDeviceAttributeAdded event raised by the Registry contract. -type RegistrySyntheticDeviceAttributeAdded struct { - Attribute string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSyntheticDeviceAttributeAdded is a free log retrieval operation binding the contract event 0x6e358be27e6aade9d45fb0b4de4cf68e2dc5630108c30a699ad5cc954d6d05c5. -// -// Solidity: event SyntheticDeviceAttributeAdded(string attribute) -func (_Registry *RegistryFilterer) FilterSyntheticDeviceAttributeAdded(opts *bind.FilterOpts) (*RegistrySyntheticDeviceAttributeAddedIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "SyntheticDeviceAttributeAdded") - if err != nil { - return nil, err - } - return &RegistrySyntheticDeviceAttributeAddedIterator{contract: _Registry.contract, event: "SyntheticDeviceAttributeAdded", logs: logs, sub: sub}, nil -} - -// WatchSyntheticDeviceAttributeAdded is a free log subscription operation binding the contract event 0x6e358be27e6aade9d45fb0b4de4cf68e2dc5630108c30a699ad5cc954d6d05c5. -// -// Solidity: event SyntheticDeviceAttributeAdded(string attribute) -func (_Registry *RegistryFilterer) WatchSyntheticDeviceAttributeAdded(opts *bind.WatchOpts, sink chan<- *RegistrySyntheticDeviceAttributeAdded) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "SyntheticDeviceAttributeAdded") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistrySyntheticDeviceAttributeAdded) - if err := _Registry.contract.UnpackLog(event, "SyntheticDeviceAttributeAdded", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSyntheticDeviceAttributeAdded is a log parse operation binding the contract event 0x6e358be27e6aade9d45fb0b4de4cf68e2dc5630108c30a699ad5cc954d6d05c5. -// -// Solidity: event SyntheticDeviceAttributeAdded(string attribute) -func (_Registry *RegistryFilterer) ParseSyntheticDeviceAttributeAdded(log types.Log) (*RegistrySyntheticDeviceAttributeAdded, error) { - event := new(RegistrySyntheticDeviceAttributeAdded) - if err := _Registry.contract.UnpackLog(event, "SyntheticDeviceAttributeAdded", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistrySyntheticDeviceAttributeSetIterator is returned from FilterSyntheticDeviceAttributeSet and is used to iterate over the raw logs and unpacked data for SyntheticDeviceAttributeSet events raised by the Registry contract. -type RegistrySyntheticDeviceAttributeSetIterator struct { - Event *RegistrySyntheticDeviceAttributeSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistrySyntheticDeviceAttributeSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistrySyntheticDeviceAttributeSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistrySyntheticDeviceAttributeSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistrySyntheticDeviceAttributeSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistrySyntheticDeviceAttributeSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistrySyntheticDeviceAttributeSet represents a SyntheticDeviceAttributeSet event raised by the Registry contract. -type RegistrySyntheticDeviceAttributeSet struct { - TokenId *big.Int - Attribute string - Info string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSyntheticDeviceAttributeSet is a free log retrieval operation binding the contract event 0xe89d3dc758bde24a2e62ff9b8b2e7e099d7d181ca58160bce0f3fd4939da0dd1. -// -// Solidity: event SyntheticDeviceAttributeSet(uint256 indexed tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) FilterSyntheticDeviceAttributeSet(opts *bind.FilterOpts, tokenId []*big.Int) (*RegistrySyntheticDeviceAttributeSetIterator, error) { - - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "SyntheticDeviceAttributeSet", tokenIdRule) - if err != nil { - return nil, err - } - return &RegistrySyntheticDeviceAttributeSetIterator{contract: _Registry.contract, event: "SyntheticDeviceAttributeSet", logs: logs, sub: sub}, nil -} - -// WatchSyntheticDeviceAttributeSet is a free log subscription operation binding the contract event 0xe89d3dc758bde24a2e62ff9b8b2e7e099d7d181ca58160bce0f3fd4939da0dd1. -// -// Solidity: event SyntheticDeviceAttributeSet(uint256 indexed tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) WatchSyntheticDeviceAttributeSet(opts *bind.WatchOpts, sink chan<- *RegistrySyntheticDeviceAttributeSet, tokenId []*big.Int) (event.Subscription, error) { - - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "SyntheticDeviceAttributeSet", tokenIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistrySyntheticDeviceAttributeSet) - if err := _Registry.contract.UnpackLog(event, "SyntheticDeviceAttributeSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSyntheticDeviceAttributeSet is a log parse operation binding the contract event 0xe89d3dc758bde24a2e62ff9b8b2e7e099d7d181ca58160bce0f3fd4939da0dd1. -// -// Solidity: event SyntheticDeviceAttributeSet(uint256 indexed tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) ParseSyntheticDeviceAttributeSet(log types.Log) (*RegistrySyntheticDeviceAttributeSet, error) { - event := new(RegistrySyntheticDeviceAttributeSet) - if err := _Registry.contract.UnpackLog(event, "SyntheticDeviceAttributeSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistrySyntheticDeviceAttributeSetDevAdminIterator is returned from FilterSyntheticDeviceAttributeSetDevAdmin and is used to iterate over the raw logs and unpacked data for SyntheticDeviceAttributeSetDevAdmin events raised by the Registry contract. -type RegistrySyntheticDeviceAttributeSetDevAdminIterator struct { - Event *RegistrySyntheticDeviceAttributeSetDevAdmin // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistrySyntheticDeviceAttributeSetDevAdminIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistrySyntheticDeviceAttributeSetDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistrySyntheticDeviceAttributeSetDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistrySyntheticDeviceAttributeSetDevAdminIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistrySyntheticDeviceAttributeSetDevAdminIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistrySyntheticDeviceAttributeSetDevAdmin represents a SyntheticDeviceAttributeSetDevAdmin event raised by the Registry contract. -type RegistrySyntheticDeviceAttributeSetDevAdmin struct { - TokenId *big.Int - Attribute string - Info string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSyntheticDeviceAttributeSetDevAdmin is a free log retrieval operation binding the contract event 0x8ad1818721bed7b9d8f765123a04baa9895dbe02ebfa9c7e886e207ee43f4360. -// -// Solidity: event SyntheticDeviceAttributeSetDevAdmin(uint256 indexed tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) FilterSyntheticDeviceAttributeSetDevAdmin(opts *bind.FilterOpts, tokenId []*big.Int) (*RegistrySyntheticDeviceAttributeSetDevAdminIterator, error) { - - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "SyntheticDeviceAttributeSetDevAdmin", tokenIdRule) - if err != nil { - return nil, err - } - return &RegistrySyntheticDeviceAttributeSetDevAdminIterator{contract: _Registry.contract, event: "SyntheticDeviceAttributeSetDevAdmin", logs: logs, sub: sub}, nil -} - -// WatchSyntheticDeviceAttributeSetDevAdmin is a free log subscription operation binding the contract event 0x8ad1818721bed7b9d8f765123a04baa9895dbe02ebfa9c7e886e207ee43f4360. -// -// Solidity: event SyntheticDeviceAttributeSetDevAdmin(uint256 indexed tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) WatchSyntheticDeviceAttributeSetDevAdmin(opts *bind.WatchOpts, sink chan<- *RegistrySyntheticDeviceAttributeSetDevAdmin, tokenId []*big.Int) (event.Subscription, error) { - - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "SyntheticDeviceAttributeSetDevAdmin", tokenIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistrySyntheticDeviceAttributeSetDevAdmin) - if err := _Registry.contract.UnpackLog(event, "SyntheticDeviceAttributeSetDevAdmin", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSyntheticDeviceAttributeSetDevAdmin is a log parse operation binding the contract event 0x8ad1818721bed7b9d8f765123a04baa9895dbe02ebfa9c7e886e207ee43f4360. -// -// Solidity: event SyntheticDeviceAttributeSetDevAdmin(uint256 indexed tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) ParseSyntheticDeviceAttributeSetDevAdmin(log types.Log) (*RegistrySyntheticDeviceAttributeSetDevAdmin, error) { - event := new(RegistrySyntheticDeviceAttributeSetDevAdmin) - if err := _Registry.contract.UnpackLog(event, "SyntheticDeviceAttributeSetDevAdmin", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistrySyntheticDeviceIdProxySetIterator is returned from FilterSyntheticDeviceIdProxySet and is used to iterate over the raw logs and unpacked data for SyntheticDeviceIdProxySet events raised by the Registry contract. -type RegistrySyntheticDeviceIdProxySetIterator struct { - Event *RegistrySyntheticDeviceIdProxySet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistrySyntheticDeviceIdProxySetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistrySyntheticDeviceIdProxySet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistrySyntheticDeviceIdProxySet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistrySyntheticDeviceIdProxySetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistrySyntheticDeviceIdProxySetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistrySyntheticDeviceIdProxySet represents a SyntheticDeviceIdProxySet event raised by the Registry contract. -type RegistrySyntheticDeviceIdProxySet struct { - Proxy common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSyntheticDeviceIdProxySet is a free log retrieval operation binding the contract event 0x03f4b74ae931497684aeebcd1d5bdf812118bbabca14f32f5d58a226534485da. -// -// Solidity: event SyntheticDeviceIdProxySet(address proxy) -func (_Registry *RegistryFilterer) FilterSyntheticDeviceIdProxySet(opts *bind.FilterOpts) (*RegistrySyntheticDeviceIdProxySetIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "SyntheticDeviceIdProxySet") - if err != nil { - return nil, err - } - return &RegistrySyntheticDeviceIdProxySetIterator{contract: _Registry.contract, event: "SyntheticDeviceIdProxySet", logs: logs, sub: sub}, nil -} - -// WatchSyntheticDeviceIdProxySet is a free log subscription operation binding the contract event 0x03f4b74ae931497684aeebcd1d5bdf812118bbabca14f32f5d58a226534485da. -// -// Solidity: event SyntheticDeviceIdProxySet(address proxy) -func (_Registry *RegistryFilterer) WatchSyntheticDeviceIdProxySet(opts *bind.WatchOpts, sink chan<- *RegistrySyntheticDeviceIdProxySet) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "SyntheticDeviceIdProxySet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistrySyntheticDeviceIdProxySet) - if err := _Registry.contract.UnpackLog(event, "SyntheticDeviceIdProxySet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSyntheticDeviceIdProxySet is a log parse operation binding the contract event 0x03f4b74ae931497684aeebcd1d5bdf812118bbabca14f32f5d58a226534485da. -// -// Solidity: event SyntheticDeviceIdProxySet(address proxy) -func (_Registry *RegistryFilterer) ParseSyntheticDeviceIdProxySet(log types.Log) (*RegistrySyntheticDeviceIdProxySet, error) { - event := new(RegistrySyntheticDeviceIdProxySet) - if err := _Registry.contract.UnpackLog(event, "SyntheticDeviceIdProxySet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistrySyntheticDeviceNodeBurnedIterator is returned from FilterSyntheticDeviceNodeBurned and is used to iterate over the raw logs and unpacked data for SyntheticDeviceNodeBurned events raised by the Registry contract. -type RegistrySyntheticDeviceNodeBurnedIterator struct { - Event *RegistrySyntheticDeviceNodeBurned // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistrySyntheticDeviceNodeBurnedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistrySyntheticDeviceNodeBurned) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistrySyntheticDeviceNodeBurned) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistrySyntheticDeviceNodeBurnedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistrySyntheticDeviceNodeBurnedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistrySyntheticDeviceNodeBurned represents a SyntheticDeviceNodeBurned event raised by the Registry contract. -type RegistrySyntheticDeviceNodeBurned struct { - SyntheticDeviceNode *big.Int - VehicleNode *big.Int - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSyntheticDeviceNodeBurned is a free log retrieval operation binding the contract event 0xe4edc3c1f917608d486e02df63af34158f185b78cef44615aebee26c09064122. -// -// Solidity: event SyntheticDeviceNodeBurned(uint256 indexed syntheticDeviceNode, uint256 indexed vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) FilterSyntheticDeviceNodeBurned(opts *bind.FilterOpts, syntheticDeviceNode []*big.Int, vehicleNode []*big.Int, owner []common.Address) (*RegistrySyntheticDeviceNodeBurnedIterator, error) { - - var syntheticDeviceNodeRule []interface{} - for _, syntheticDeviceNodeItem := range syntheticDeviceNode { - syntheticDeviceNodeRule = append(syntheticDeviceNodeRule, syntheticDeviceNodeItem) - } - var vehicleNodeRule []interface{} - for _, vehicleNodeItem := range vehicleNode { - vehicleNodeRule = append(vehicleNodeRule, vehicleNodeItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "SyntheticDeviceNodeBurned", syntheticDeviceNodeRule, vehicleNodeRule, ownerRule) - if err != nil { - return nil, err - } - return &RegistrySyntheticDeviceNodeBurnedIterator{contract: _Registry.contract, event: "SyntheticDeviceNodeBurned", logs: logs, sub: sub}, nil -} - -// WatchSyntheticDeviceNodeBurned is a free log subscription operation binding the contract event 0xe4edc3c1f917608d486e02df63af34158f185b78cef44615aebee26c09064122. -// -// Solidity: event SyntheticDeviceNodeBurned(uint256 indexed syntheticDeviceNode, uint256 indexed vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) WatchSyntheticDeviceNodeBurned(opts *bind.WatchOpts, sink chan<- *RegistrySyntheticDeviceNodeBurned, syntheticDeviceNode []*big.Int, vehicleNode []*big.Int, owner []common.Address) (event.Subscription, error) { - - var syntheticDeviceNodeRule []interface{} - for _, syntheticDeviceNodeItem := range syntheticDeviceNode { - syntheticDeviceNodeRule = append(syntheticDeviceNodeRule, syntheticDeviceNodeItem) - } - var vehicleNodeRule []interface{} - for _, vehicleNodeItem := range vehicleNode { - vehicleNodeRule = append(vehicleNodeRule, vehicleNodeItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "SyntheticDeviceNodeBurned", syntheticDeviceNodeRule, vehicleNodeRule, ownerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistrySyntheticDeviceNodeBurned) - if err := _Registry.contract.UnpackLog(event, "SyntheticDeviceNodeBurned", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSyntheticDeviceNodeBurned is a log parse operation binding the contract event 0xe4edc3c1f917608d486e02df63af34158f185b78cef44615aebee26c09064122. -// -// Solidity: event SyntheticDeviceNodeBurned(uint256 indexed syntheticDeviceNode, uint256 indexed vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) ParseSyntheticDeviceNodeBurned(log types.Log) (*RegistrySyntheticDeviceNodeBurned, error) { - event := new(RegistrySyntheticDeviceNodeBurned) - if err := _Registry.contract.UnpackLog(event, "SyntheticDeviceNodeBurned", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistrySyntheticDeviceNodeBurnedDevAdminIterator is returned from FilterSyntheticDeviceNodeBurnedDevAdmin and is used to iterate over the raw logs and unpacked data for SyntheticDeviceNodeBurnedDevAdmin events raised by the Registry contract. -type RegistrySyntheticDeviceNodeBurnedDevAdminIterator struct { - Event *RegistrySyntheticDeviceNodeBurnedDevAdmin // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistrySyntheticDeviceNodeBurnedDevAdminIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistrySyntheticDeviceNodeBurnedDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistrySyntheticDeviceNodeBurnedDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistrySyntheticDeviceNodeBurnedDevAdminIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistrySyntheticDeviceNodeBurnedDevAdminIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistrySyntheticDeviceNodeBurnedDevAdmin represents a SyntheticDeviceNodeBurnedDevAdmin event raised by the Registry contract. -type RegistrySyntheticDeviceNodeBurnedDevAdmin struct { - SyntheticDeviceNode *big.Int - VehicleNode *big.Int - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSyntheticDeviceNodeBurnedDevAdmin is a free log retrieval operation binding the contract event 0x81741fdd73b815709bc61e67c1aeb3a0baa2afb920b26347eab2f4f980595cd4. -// -// Solidity: event SyntheticDeviceNodeBurnedDevAdmin(uint256 indexed syntheticDeviceNode, uint256 indexed vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) FilterSyntheticDeviceNodeBurnedDevAdmin(opts *bind.FilterOpts, syntheticDeviceNode []*big.Int, vehicleNode []*big.Int, owner []common.Address) (*RegistrySyntheticDeviceNodeBurnedDevAdminIterator, error) { - - var syntheticDeviceNodeRule []interface{} - for _, syntheticDeviceNodeItem := range syntheticDeviceNode { - syntheticDeviceNodeRule = append(syntheticDeviceNodeRule, syntheticDeviceNodeItem) - } - var vehicleNodeRule []interface{} - for _, vehicleNodeItem := range vehicleNode { - vehicleNodeRule = append(vehicleNodeRule, vehicleNodeItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "SyntheticDeviceNodeBurnedDevAdmin", syntheticDeviceNodeRule, vehicleNodeRule, ownerRule) - if err != nil { - return nil, err - } - return &RegistrySyntheticDeviceNodeBurnedDevAdminIterator{contract: _Registry.contract, event: "SyntheticDeviceNodeBurnedDevAdmin", logs: logs, sub: sub}, nil -} - -// WatchSyntheticDeviceNodeBurnedDevAdmin is a free log subscription operation binding the contract event 0x81741fdd73b815709bc61e67c1aeb3a0baa2afb920b26347eab2f4f980595cd4. -// -// Solidity: event SyntheticDeviceNodeBurnedDevAdmin(uint256 indexed syntheticDeviceNode, uint256 indexed vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) WatchSyntheticDeviceNodeBurnedDevAdmin(opts *bind.WatchOpts, sink chan<- *RegistrySyntheticDeviceNodeBurnedDevAdmin, syntheticDeviceNode []*big.Int, vehicleNode []*big.Int, owner []common.Address) (event.Subscription, error) { - - var syntheticDeviceNodeRule []interface{} - for _, syntheticDeviceNodeItem := range syntheticDeviceNode { - syntheticDeviceNodeRule = append(syntheticDeviceNodeRule, syntheticDeviceNodeItem) - } - var vehicleNodeRule []interface{} - for _, vehicleNodeItem := range vehicleNode { - vehicleNodeRule = append(vehicleNodeRule, vehicleNodeItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "SyntheticDeviceNodeBurnedDevAdmin", syntheticDeviceNodeRule, vehicleNodeRule, ownerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistrySyntheticDeviceNodeBurnedDevAdmin) - if err := _Registry.contract.UnpackLog(event, "SyntheticDeviceNodeBurnedDevAdmin", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSyntheticDeviceNodeBurnedDevAdmin is a log parse operation binding the contract event 0x81741fdd73b815709bc61e67c1aeb3a0baa2afb920b26347eab2f4f980595cd4. -// -// Solidity: event SyntheticDeviceNodeBurnedDevAdmin(uint256 indexed syntheticDeviceNode, uint256 indexed vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) ParseSyntheticDeviceNodeBurnedDevAdmin(log types.Log) (*RegistrySyntheticDeviceNodeBurnedDevAdmin, error) { - event := new(RegistrySyntheticDeviceNodeBurnedDevAdmin) - if err := _Registry.contract.UnpackLog(event, "SyntheticDeviceNodeBurnedDevAdmin", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistrySyntheticDeviceNodeMintedIterator is returned from FilterSyntheticDeviceNodeMinted and is used to iterate over the raw logs and unpacked data for SyntheticDeviceNodeMinted events raised by the Registry contract. -type RegistrySyntheticDeviceNodeMintedIterator struct { - Event *RegistrySyntheticDeviceNodeMinted // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistrySyntheticDeviceNodeMintedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistrySyntheticDeviceNodeMinted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistrySyntheticDeviceNodeMinted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistrySyntheticDeviceNodeMintedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistrySyntheticDeviceNodeMintedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistrySyntheticDeviceNodeMinted represents a SyntheticDeviceNodeMinted event raised by the Registry contract. -type RegistrySyntheticDeviceNodeMinted struct { - IntegrationNode *big.Int - SyntheticDeviceNode *big.Int - VehicleNode *big.Int - SyntheticDeviceAddress common.Address - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSyntheticDeviceNodeMinted is a free log retrieval operation binding the contract event 0x5a560c1adda92bd6cbf9c891dc38e9e2973b7963493f2364caa40a4218346280. -// -// Solidity: event SyntheticDeviceNodeMinted(uint256 integrationNode, uint256 syntheticDeviceNode, uint256 indexed vehicleNode, address indexed syntheticDeviceAddress, address indexed owner) -func (_Registry *RegistryFilterer) FilterSyntheticDeviceNodeMinted(opts *bind.FilterOpts, vehicleNode []*big.Int, syntheticDeviceAddress []common.Address, owner []common.Address) (*RegistrySyntheticDeviceNodeMintedIterator, error) { - - var vehicleNodeRule []interface{} - for _, vehicleNodeItem := range vehicleNode { - vehicleNodeRule = append(vehicleNodeRule, vehicleNodeItem) - } - var syntheticDeviceAddressRule []interface{} - for _, syntheticDeviceAddressItem := range syntheticDeviceAddress { - syntheticDeviceAddressRule = append(syntheticDeviceAddressRule, syntheticDeviceAddressItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "SyntheticDeviceNodeMinted", vehicleNodeRule, syntheticDeviceAddressRule, ownerRule) - if err != nil { - return nil, err - } - return &RegistrySyntheticDeviceNodeMintedIterator{contract: _Registry.contract, event: "SyntheticDeviceNodeMinted", logs: logs, sub: sub}, nil -} - -// WatchSyntheticDeviceNodeMinted is a free log subscription operation binding the contract event 0x5a560c1adda92bd6cbf9c891dc38e9e2973b7963493f2364caa40a4218346280. -// -// Solidity: event SyntheticDeviceNodeMinted(uint256 integrationNode, uint256 syntheticDeviceNode, uint256 indexed vehicleNode, address indexed syntheticDeviceAddress, address indexed owner) -func (_Registry *RegistryFilterer) WatchSyntheticDeviceNodeMinted(opts *bind.WatchOpts, sink chan<- *RegistrySyntheticDeviceNodeMinted, vehicleNode []*big.Int, syntheticDeviceAddress []common.Address, owner []common.Address) (event.Subscription, error) { - - var vehicleNodeRule []interface{} - for _, vehicleNodeItem := range vehicleNode { - vehicleNodeRule = append(vehicleNodeRule, vehicleNodeItem) - } - var syntheticDeviceAddressRule []interface{} - for _, syntheticDeviceAddressItem := range syntheticDeviceAddress { - syntheticDeviceAddressRule = append(syntheticDeviceAddressRule, syntheticDeviceAddressItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "SyntheticDeviceNodeMinted", vehicleNodeRule, syntheticDeviceAddressRule, ownerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistrySyntheticDeviceNodeMinted) - if err := _Registry.contract.UnpackLog(event, "SyntheticDeviceNodeMinted", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSyntheticDeviceNodeMinted is a log parse operation binding the contract event 0x5a560c1adda92bd6cbf9c891dc38e9e2973b7963493f2364caa40a4218346280. -// -// Solidity: event SyntheticDeviceNodeMinted(uint256 integrationNode, uint256 syntheticDeviceNode, uint256 indexed vehicleNode, address indexed syntheticDeviceAddress, address indexed owner) -func (_Registry *RegistryFilterer) ParseSyntheticDeviceNodeMinted(log types.Log) (*RegistrySyntheticDeviceNodeMinted, error) { - event := new(RegistrySyntheticDeviceNodeMinted) - if err := _Registry.contract.UnpackLog(event, "SyntheticDeviceNodeMinted", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryVehicleAttributeAddedIterator is returned from FilterVehicleAttributeAdded and is used to iterate over the raw logs and unpacked data for VehicleAttributeAdded events raised by the Registry contract. -type RegistryVehicleAttributeAddedIterator struct { - Event *RegistryVehicleAttributeAdded // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryVehicleAttributeAddedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleAttributeAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleAttributeAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryVehicleAttributeAddedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryVehicleAttributeAddedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryVehicleAttributeAdded represents a VehicleAttributeAdded event raised by the Registry contract. -type RegistryVehicleAttributeAdded struct { - Attribute string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterVehicleAttributeAdded is a free log retrieval operation binding the contract event 0x2b7d41dc33ffd58029f53ebfc3232e4f343480b078458bc17c527583e0172c1a. -// -// Solidity: event VehicleAttributeAdded(string attribute) -func (_Registry *RegistryFilterer) FilterVehicleAttributeAdded(opts *bind.FilterOpts) (*RegistryVehicleAttributeAddedIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "VehicleAttributeAdded") - if err != nil { - return nil, err - } - return &RegistryVehicleAttributeAddedIterator{contract: _Registry.contract, event: "VehicleAttributeAdded", logs: logs, sub: sub}, nil -} - -// WatchVehicleAttributeAdded is a free log subscription operation binding the contract event 0x2b7d41dc33ffd58029f53ebfc3232e4f343480b078458bc17c527583e0172c1a. -// -// Solidity: event VehicleAttributeAdded(string attribute) -func (_Registry *RegistryFilterer) WatchVehicleAttributeAdded(opts *bind.WatchOpts, sink chan<- *RegistryVehicleAttributeAdded) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "VehicleAttributeAdded") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryVehicleAttributeAdded) - if err := _Registry.contract.UnpackLog(event, "VehicleAttributeAdded", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseVehicleAttributeAdded is a log parse operation binding the contract event 0x2b7d41dc33ffd58029f53ebfc3232e4f343480b078458bc17c527583e0172c1a. -// -// Solidity: event VehicleAttributeAdded(string attribute) -func (_Registry *RegistryFilterer) ParseVehicleAttributeAdded(log types.Log) (*RegistryVehicleAttributeAdded, error) { - event := new(RegistryVehicleAttributeAdded) - if err := _Registry.contract.UnpackLog(event, "VehicleAttributeAdded", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryVehicleAttributeRemovedIterator is returned from FilterVehicleAttributeRemoved and is used to iterate over the raw logs and unpacked data for VehicleAttributeRemoved events raised by the Registry contract. -type RegistryVehicleAttributeRemovedIterator struct { - Event *RegistryVehicleAttributeRemoved // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryVehicleAttributeRemovedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleAttributeRemoved) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleAttributeRemoved) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryVehicleAttributeRemovedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryVehicleAttributeRemovedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryVehicleAttributeRemoved represents a VehicleAttributeRemoved event raised by the Registry contract. -type RegistryVehicleAttributeRemoved struct { - Attribute string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterVehicleAttributeRemoved is a free log retrieval operation binding the contract event 0x9b4bf3774d4e97d237196fc2a2d3f0764f4a7987c5a5db94f029cc8357f72b45. -// -// Solidity: event VehicleAttributeRemoved(string attribute) -func (_Registry *RegistryFilterer) FilterVehicleAttributeRemoved(opts *bind.FilterOpts) (*RegistryVehicleAttributeRemovedIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "VehicleAttributeRemoved") - if err != nil { - return nil, err - } - return &RegistryVehicleAttributeRemovedIterator{contract: _Registry.contract, event: "VehicleAttributeRemoved", logs: logs, sub: sub}, nil -} - -// WatchVehicleAttributeRemoved is a free log subscription operation binding the contract event 0x9b4bf3774d4e97d237196fc2a2d3f0764f4a7987c5a5db94f029cc8357f72b45. -// -// Solidity: event VehicleAttributeRemoved(string attribute) -func (_Registry *RegistryFilterer) WatchVehicleAttributeRemoved(opts *bind.WatchOpts, sink chan<- *RegistryVehicleAttributeRemoved) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "VehicleAttributeRemoved") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryVehicleAttributeRemoved) - if err := _Registry.contract.UnpackLog(event, "VehicleAttributeRemoved", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseVehicleAttributeRemoved is a log parse operation binding the contract event 0x9b4bf3774d4e97d237196fc2a2d3f0764f4a7987c5a5db94f029cc8357f72b45. -// -// Solidity: event VehicleAttributeRemoved(string attribute) -func (_Registry *RegistryFilterer) ParseVehicleAttributeRemoved(log types.Log) (*RegistryVehicleAttributeRemoved, error) { - event := new(RegistryVehicleAttributeRemoved) - if err := _Registry.contract.UnpackLog(event, "VehicleAttributeRemoved", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryVehicleAttributeSetIterator is returned from FilterVehicleAttributeSet and is used to iterate over the raw logs and unpacked data for VehicleAttributeSet events raised by the Registry contract. -type RegistryVehicleAttributeSetIterator struct { - Event *RegistryVehicleAttributeSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryVehicleAttributeSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleAttributeSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleAttributeSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryVehicleAttributeSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryVehicleAttributeSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryVehicleAttributeSet represents a VehicleAttributeSet event raised by the Registry contract. -type RegistryVehicleAttributeSet struct { - TokenId *big.Int - Attribute string - Info string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterVehicleAttributeSet is a free log retrieval operation binding the contract event 0x3a259e5d4c53f11c343582a8291a82a8cc0b36ec211d5ab48c2f29ebb068e5fb. -// -// Solidity: event VehicleAttributeSet(uint256 tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) FilterVehicleAttributeSet(opts *bind.FilterOpts) (*RegistryVehicleAttributeSetIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "VehicleAttributeSet") - if err != nil { - return nil, err - } - return &RegistryVehicleAttributeSetIterator{contract: _Registry.contract, event: "VehicleAttributeSet", logs: logs, sub: sub}, nil -} - -// WatchVehicleAttributeSet is a free log subscription operation binding the contract event 0x3a259e5d4c53f11c343582a8291a82a8cc0b36ec211d5ab48c2f29ebb068e5fb. -// -// Solidity: event VehicleAttributeSet(uint256 tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) WatchVehicleAttributeSet(opts *bind.WatchOpts, sink chan<- *RegistryVehicleAttributeSet) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "VehicleAttributeSet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryVehicleAttributeSet) - if err := _Registry.contract.UnpackLog(event, "VehicleAttributeSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseVehicleAttributeSet is a log parse operation binding the contract event 0x3a259e5d4c53f11c343582a8291a82a8cc0b36ec211d5ab48c2f29ebb068e5fb. -// -// Solidity: event VehicleAttributeSet(uint256 tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) ParseVehicleAttributeSet(log types.Log) (*RegistryVehicleAttributeSet, error) { - event := new(RegistryVehicleAttributeSet) - if err := _Registry.contract.UnpackLog(event, "VehicleAttributeSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryVehicleAttributeSetDevAdminIterator is returned from FilterVehicleAttributeSetDevAdmin and is used to iterate over the raw logs and unpacked data for VehicleAttributeSetDevAdmin events raised by the Registry contract. -type RegistryVehicleAttributeSetDevAdminIterator struct { - Event *RegistryVehicleAttributeSetDevAdmin // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryVehicleAttributeSetDevAdminIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleAttributeSetDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleAttributeSetDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryVehicleAttributeSetDevAdminIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryVehicleAttributeSetDevAdminIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryVehicleAttributeSetDevAdmin represents a VehicleAttributeSetDevAdmin event raised by the Registry contract. -type RegistryVehicleAttributeSetDevAdmin struct { - TokenId *big.Int - Attribute string - Info string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterVehicleAttributeSetDevAdmin is a free log retrieval operation binding the contract event 0x1d91e00c26e65ad33a7ff60138cf8250090a290b59ec754323b9f5e6be929896. -// -// Solidity: event VehicleAttributeSetDevAdmin(uint256 indexed tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) FilterVehicleAttributeSetDevAdmin(opts *bind.FilterOpts, tokenId []*big.Int) (*RegistryVehicleAttributeSetDevAdminIterator, error) { - - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "VehicleAttributeSetDevAdmin", tokenIdRule) - if err != nil { - return nil, err - } - return &RegistryVehicleAttributeSetDevAdminIterator{contract: _Registry.contract, event: "VehicleAttributeSetDevAdmin", logs: logs, sub: sub}, nil -} - -// WatchVehicleAttributeSetDevAdmin is a free log subscription operation binding the contract event 0x1d91e00c26e65ad33a7ff60138cf8250090a290b59ec754323b9f5e6be929896. -// -// Solidity: event VehicleAttributeSetDevAdmin(uint256 indexed tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) WatchVehicleAttributeSetDevAdmin(opts *bind.WatchOpts, sink chan<- *RegistryVehicleAttributeSetDevAdmin, tokenId []*big.Int) (event.Subscription, error) { - - var tokenIdRule []interface{} - for _, tokenIdItem := range tokenId { - tokenIdRule = append(tokenIdRule, tokenIdItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "VehicleAttributeSetDevAdmin", tokenIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryVehicleAttributeSetDevAdmin) - if err := _Registry.contract.UnpackLog(event, "VehicleAttributeSetDevAdmin", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseVehicleAttributeSetDevAdmin is a log parse operation binding the contract event 0x1d91e00c26e65ad33a7ff60138cf8250090a290b59ec754323b9f5e6be929896. -// -// Solidity: event VehicleAttributeSetDevAdmin(uint256 indexed tokenId, string attribute, string info) -func (_Registry *RegistryFilterer) ParseVehicleAttributeSetDevAdmin(log types.Log) (*RegistryVehicleAttributeSetDevAdmin, error) { - event := new(RegistryVehicleAttributeSetDevAdmin) - if err := _Registry.contract.UnpackLog(event, "VehicleAttributeSetDevAdmin", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryVehicleIdProxySetIterator is returned from FilterVehicleIdProxySet and is used to iterate over the raw logs and unpacked data for VehicleIdProxySet events raised by the Registry contract. -type RegistryVehicleIdProxySetIterator struct { - Event *RegistryVehicleIdProxySet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryVehicleIdProxySetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleIdProxySet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleIdProxySet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryVehicleIdProxySetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryVehicleIdProxySetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryVehicleIdProxySet represents a VehicleIdProxySet event raised by the Registry contract. -type RegistryVehicleIdProxySet struct { - Proxy common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterVehicleIdProxySet is a free log retrieval operation binding the contract event 0x3e7484c4e57f7d92e9f02eba6cd805d89112e48db8c21aeb8485fcf0020e479d. -// -// Solidity: event VehicleIdProxySet(address indexed proxy) -func (_Registry *RegistryFilterer) FilterVehicleIdProxySet(opts *bind.FilterOpts, proxy []common.Address) (*RegistryVehicleIdProxySetIterator, error) { - - var proxyRule []interface{} - for _, proxyItem := range proxy { - proxyRule = append(proxyRule, proxyItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "VehicleIdProxySet", proxyRule) - if err != nil { - return nil, err - } - return &RegistryVehicleIdProxySetIterator{contract: _Registry.contract, event: "VehicleIdProxySet", logs: logs, sub: sub}, nil -} - -// WatchVehicleIdProxySet is a free log subscription operation binding the contract event 0x3e7484c4e57f7d92e9f02eba6cd805d89112e48db8c21aeb8485fcf0020e479d. -// -// Solidity: event VehicleIdProxySet(address indexed proxy) -func (_Registry *RegistryFilterer) WatchVehicleIdProxySet(opts *bind.WatchOpts, sink chan<- *RegistryVehicleIdProxySet, proxy []common.Address) (event.Subscription, error) { - - var proxyRule []interface{} - for _, proxyItem := range proxy { - proxyRule = append(proxyRule, proxyItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "VehicleIdProxySet", proxyRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryVehicleIdProxySet) - if err := _Registry.contract.UnpackLog(event, "VehicleIdProxySet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseVehicleIdProxySet is a log parse operation binding the contract event 0x3e7484c4e57f7d92e9f02eba6cd805d89112e48db8c21aeb8485fcf0020e479d. -// -// Solidity: event VehicleIdProxySet(address indexed proxy) -func (_Registry *RegistryFilterer) ParseVehicleIdProxySet(log types.Log) (*RegistryVehicleIdProxySet, error) { - event := new(RegistryVehicleIdProxySet) - if err := _Registry.contract.UnpackLog(event, "VehicleIdProxySet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryVehicleNodeBurnedIterator is returned from FilterVehicleNodeBurned and is used to iterate over the raw logs and unpacked data for VehicleNodeBurned events raised by the Registry contract. -type RegistryVehicleNodeBurnedIterator struct { - Event *RegistryVehicleNodeBurned // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryVehicleNodeBurnedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleNodeBurned) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleNodeBurned) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryVehicleNodeBurnedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryVehicleNodeBurnedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryVehicleNodeBurned represents a VehicleNodeBurned event raised by the Registry contract. -type RegistryVehicleNodeBurned struct { - VehicleNode *big.Int - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterVehicleNodeBurned is a free log retrieval operation binding the contract event 0x7b36384f0fcf18da09247269a4716eecbcbc475a5b2bc7aa371fc1164789508d. -// -// Solidity: event VehicleNodeBurned(uint256 indexed vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) FilterVehicleNodeBurned(opts *bind.FilterOpts, vehicleNode []*big.Int, owner []common.Address) (*RegistryVehicleNodeBurnedIterator, error) { - - var vehicleNodeRule []interface{} - for _, vehicleNodeItem := range vehicleNode { - vehicleNodeRule = append(vehicleNodeRule, vehicleNodeItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "VehicleNodeBurned", vehicleNodeRule, ownerRule) - if err != nil { - return nil, err - } - return &RegistryVehicleNodeBurnedIterator{contract: _Registry.contract, event: "VehicleNodeBurned", logs: logs, sub: sub}, nil -} - -// WatchVehicleNodeBurned is a free log subscription operation binding the contract event 0x7b36384f0fcf18da09247269a4716eecbcbc475a5b2bc7aa371fc1164789508d. -// -// Solidity: event VehicleNodeBurned(uint256 indexed vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) WatchVehicleNodeBurned(opts *bind.WatchOpts, sink chan<- *RegistryVehicleNodeBurned, vehicleNode []*big.Int, owner []common.Address) (event.Subscription, error) { - - var vehicleNodeRule []interface{} - for _, vehicleNodeItem := range vehicleNode { - vehicleNodeRule = append(vehicleNodeRule, vehicleNodeItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "VehicleNodeBurned", vehicleNodeRule, ownerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryVehicleNodeBurned) - if err := _Registry.contract.UnpackLog(event, "VehicleNodeBurned", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseVehicleNodeBurned is a log parse operation binding the contract event 0x7b36384f0fcf18da09247269a4716eecbcbc475a5b2bc7aa371fc1164789508d. -// -// Solidity: event VehicleNodeBurned(uint256 indexed vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) ParseVehicleNodeBurned(log types.Log) (*RegistryVehicleNodeBurned, error) { - event := new(RegistryVehicleNodeBurned) - if err := _Registry.contract.UnpackLog(event, "VehicleNodeBurned", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryVehicleNodeBurnedDevAdminIterator is returned from FilterVehicleNodeBurnedDevAdmin and is used to iterate over the raw logs and unpacked data for VehicleNodeBurnedDevAdmin events raised by the Registry contract. -type RegistryVehicleNodeBurnedDevAdminIterator struct { - Event *RegistryVehicleNodeBurnedDevAdmin // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryVehicleNodeBurnedDevAdminIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleNodeBurnedDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleNodeBurnedDevAdmin) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryVehicleNodeBurnedDevAdminIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryVehicleNodeBurnedDevAdminIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryVehicleNodeBurnedDevAdmin represents a VehicleNodeBurnedDevAdmin event raised by the Registry contract. -type RegistryVehicleNodeBurnedDevAdmin struct { - VehicleNode *big.Int - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterVehicleNodeBurnedDevAdmin is a free log retrieval operation binding the contract event 0xb956d02723efc0f9c3b60b95271d0b2c35628307c1f98a8f4c9a7f521d9dd0ff. -// -// Solidity: event VehicleNodeBurnedDevAdmin(uint256 indexed vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) FilterVehicleNodeBurnedDevAdmin(opts *bind.FilterOpts, vehicleNode []*big.Int, owner []common.Address) (*RegistryVehicleNodeBurnedDevAdminIterator, error) { - - var vehicleNodeRule []interface{} - for _, vehicleNodeItem := range vehicleNode { - vehicleNodeRule = append(vehicleNodeRule, vehicleNodeItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "VehicleNodeBurnedDevAdmin", vehicleNodeRule, ownerRule) - if err != nil { - return nil, err - } - return &RegistryVehicleNodeBurnedDevAdminIterator{contract: _Registry.contract, event: "VehicleNodeBurnedDevAdmin", logs: logs, sub: sub}, nil -} - -// WatchVehicleNodeBurnedDevAdmin is a free log subscription operation binding the contract event 0xb956d02723efc0f9c3b60b95271d0b2c35628307c1f98a8f4c9a7f521d9dd0ff. -// -// Solidity: event VehicleNodeBurnedDevAdmin(uint256 indexed vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) WatchVehicleNodeBurnedDevAdmin(opts *bind.WatchOpts, sink chan<- *RegistryVehicleNodeBurnedDevAdmin, vehicleNode []*big.Int, owner []common.Address) (event.Subscription, error) { - - var vehicleNodeRule []interface{} - for _, vehicleNodeItem := range vehicleNode { - vehicleNodeRule = append(vehicleNodeRule, vehicleNodeItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "VehicleNodeBurnedDevAdmin", vehicleNodeRule, ownerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryVehicleNodeBurnedDevAdmin) - if err := _Registry.contract.UnpackLog(event, "VehicleNodeBurnedDevAdmin", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseVehicleNodeBurnedDevAdmin is a log parse operation binding the contract event 0xb956d02723efc0f9c3b60b95271d0b2c35628307c1f98a8f4c9a7f521d9dd0ff. -// -// Solidity: event VehicleNodeBurnedDevAdmin(uint256 indexed vehicleNode, address indexed owner) -func (_Registry *RegistryFilterer) ParseVehicleNodeBurnedDevAdmin(log types.Log) (*RegistryVehicleNodeBurnedDevAdmin, error) { - event := new(RegistryVehicleNodeBurnedDevAdmin) - if err := _Registry.contract.UnpackLog(event, "VehicleNodeBurnedDevAdmin", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryVehicleNodeMintedIterator is returned from FilterVehicleNodeMinted and is used to iterate over the raw logs and unpacked data for VehicleNodeMinted events raised by the Registry contract. -type RegistryVehicleNodeMintedIterator struct { - Event *RegistryVehicleNodeMinted // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryVehicleNodeMintedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleNodeMinted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleNodeMinted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryVehicleNodeMintedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryVehicleNodeMintedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryVehicleNodeMinted represents a VehicleNodeMinted event raised by the Registry contract. -type RegistryVehicleNodeMinted struct { - ManufacturerNode *big.Int - TokenId *big.Int - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterVehicleNodeMinted is a free log retrieval operation binding the contract event 0xd471ae8ab3c01edc986909c344bb50f982b21772fcac173103ef8b9924375ec6. -// -// Solidity: event VehicleNodeMinted(uint256 manufacturerNode, uint256 tokenId, address owner) -func (_Registry *RegistryFilterer) FilterVehicleNodeMinted(opts *bind.FilterOpts) (*RegistryVehicleNodeMintedIterator, error) { - - logs, sub, err := _Registry.contract.FilterLogs(opts, "VehicleNodeMinted") - if err != nil { - return nil, err - } - return &RegistryVehicleNodeMintedIterator{contract: _Registry.contract, event: "VehicleNodeMinted", logs: logs, sub: sub}, nil -} - -// WatchVehicleNodeMinted is a free log subscription operation binding the contract event 0xd471ae8ab3c01edc986909c344bb50f982b21772fcac173103ef8b9924375ec6. -// -// Solidity: event VehicleNodeMinted(uint256 manufacturerNode, uint256 tokenId, address owner) -func (_Registry *RegistryFilterer) WatchVehicleNodeMinted(opts *bind.WatchOpts, sink chan<- *RegistryVehicleNodeMinted) (event.Subscription, error) { - - logs, sub, err := _Registry.contract.WatchLogs(opts, "VehicleNodeMinted") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryVehicleNodeMinted) - if err := _Registry.contract.UnpackLog(event, "VehicleNodeMinted", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseVehicleNodeMinted is a log parse operation binding the contract event 0xd471ae8ab3c01edc986909c344bb50f982b21772fcac173103ef8b9924375ec6. -// -// Solidity: event VehicleNodeMinted(uint256 manufacturerNode, uint256 tokenId, address owner) -func (_Registry *RegistryFilterer) ParseVehicleNodeMinted(log types.Log) (*RegistryVehicleNodeMinted, error) { - event := new(RegistryVehicleNodeMinted) - if err := _Registry.contract.UnpackLog(event, "VehicleNodeMinted", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryVehicleNodeMintedWithDeviceDefinitionIterator is returned from FilterVehicleNodeMintedWithDeviceDefinition and is used to iterate over the raw logs and unpacked data for VehicleNodeMintedWithDeviceDefinition events raised by the Registry contract. -type RegistryVehicleNodeMintedWithDeviceDefinitionIterator struct { - Event *RegistryVehicleNodeMintedWithDeviceDefinition // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryVehicleNodeMintedWithDeviceDefinitionIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleNodeMintedWithDeviceDefinition) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleNodeMintedWithDeviceDefinition) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryVehicleNodeMintedWithDeviceDefinitionIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryVehicleNodeMintedWithDeviceDefinitionIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryVehicleNodeMintedWithDeviceDefinition represents a VehicleNodeMintedWithDeviceDefinition event raised by the Registry contract. -type RegistryVehicleNodeMintedWithDeviceDefinition struct { - ManufacturerId *big.Int - VehicleId *big.Int - Owner common.Address - DeviceDefinitionId string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterVehicleNodeMintedWithDeviceDefinition is a free log retrieval operation binding the contract event 0xc7c7d9ac150ee7eff1ae17be6e6c250d9f574d019d47cd741f693feb1929496c. -// -// Solidity: event VehicleNodeMintedWithDeviceDefinition(uint256 indexed manufacturerId, uint256 indexed vehicleId, address indexed owner, string deviceDefinitionId) -func (_Registry *RegistryFilterer) FilterVehicleNodeMintedWithDeviceDefinition(opts *bind.FilterOpts, manufacturerId []*big.Int, vehicleId []*big.Int, owner []common.Address) (*RegistryVehicleNodeMintedWithDeviceDefinitionIterator, error) { - - var manufacturerIdRule []interface{} - for _, manufacturerIdItem := range manufacturerId { - manufacturerIdRule = append(manufacturerIdRule, manufacturerIdItem) - } - var vehicleIdRule []interface{} - for _, vehicleIdItem := range vehicleId { - vehicleIdRule = append(vehicleIdRule, vehicleIdItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "VehicleNodeMintedWithDeviceDefinition", manufacturerIdRule, vehicleIdRule, ownerRule) - if err != nil { - return nil, err - } - return &RegistryVehicleNodeMintedWithDeviceDefinitionIterator{contract: _Registry.contract, event: "VehicleNodeMintedWithDeviceDefinition", logs: logs, sub: sub}, nil -} - -// WatchVehicleNodeMintedWithDeviceDefinition is a free log subscription operation binding the contract event 0xc7c7d9ac150ee7eff1ae17be6e6c250d9f574d019d47cd741f693feb1929496c. -// -// Solidity: event VehicleNodeMintedWithDeviceDefinition(uint256 indexed manufacturerId, uint256 indexed vehicleId, address indexed owner, string deviceDefinitionId) -func (_Registry *RegistryFilterer) WatchVehicleNodeMintedWithDeviceDefinition(opts *bind.WatchOpts, sink chan<- *RegistryVehicleNodeMintedWithDeviceDefinition, manufacturerId []*big.Int, vehicleId []*big.Int, owner []common.Address) (event.Subscription, error) { - - var manufacturerIdRule []interface{} - for _, manufacturerIdItem := range manufacturerId { - manufacturerIdRule = append(manufacturerIdRule, manufacturerIdItem) - } - var vehicleIdRule []interface{} - for _, vehicleIdItem := range vehicleId { - vehicleIdRule = append(vehicleIdRule, vehicleIdItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "VehicleNodeMintedWithDeviceDefinition", manufacturerIdRule, vehicleIdRule, ownerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryVehicleNodeMintedWithDeviceDefinition) - if err := _Registry.contract.UnpackLog(event, "VehicleNodeMintedWithDeviceDefinition", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseVehicleNodeMintedWithDeviceDefinition is a log parse operation binding the contract event 0xc7c7d9ac150ee7eff1ae17be6e6c250d9f574d019d47cd741f693feb1929496c. -// -// Solidity: event VehicleNodeMintedWithDeviceDefinition(uint256 indexed manufacturerId, uint256 indexed vehicleId, address indexed owner, string deviceDefinitionId) -func (_Registry *RegistryFilterer) ParseVehicleNodeMintedWithDeviceDefinition(log types.Log) (*RegistryVehicleNodeMintedWithDeviceDefinition, error) { - event := new(RegistryVehicleNodeMintedWithDeviceDefinition) - if err := _Registry.contract.UnpackLog(event, "VehicleNodeMintedWithDeviceDefinition", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryVehicleStreamSetIterator is returned from FilterVehicleStreamSet and is used to iterate over the raw logs and unpacked data for VehicleStreamSet events raised by the Registry contract. -type RegistryVehicleStreamSetIterator struct { - Event *RegistryVehicleStreamSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryVehicleStreamSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleStreamSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleStreamSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryVehicleStreamSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryVehicleStreamSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryVehicleStreamSet represents a VehicleStreamSet event raised by the Registry contract. -type RegistryVehicleStreamSet struct { - VehicleId *big.Int - StreamId string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterVehicleStreamSet is a free log retrieval operation binding the contract event 0x09d0a7809cb7d90906448d57618581b65ca306d116e2b991721b9ef877d890de. -// -// Solidity: event VehicleStreamSet(uint256 indexed vehicleId, string streamId) -func (_Registry *RegistryFilterer) FilterVehicleStreamSet(opts *bind.FilterOpts, vehicleId []*big.Int) (*RegistryVehicleStreamSetIterator, error) { - - var vehicleIdRule []interface{} - for _, vehicleIdItem := range vehicleId { - vehicleIdRule = append(vehicleIdRule, vehicleIdItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "VehicleStreamSet", vehicleIdRule) - if err != nil { - return nil, err - } - return &RegistryVehicleStreamSetIterator{contract: _Registry.contract, event: "VehicleStreamSet", logs: logs, sub: sub}, nil -} - -// WatchVehicleStreamSet is a free log subscription operation binding the contract event 0x09d0a7809cb7d90906448d57618581b65ca306d116e2b991721b9ef877d890de. -// -// Solidity: event VehicleStreamSet(uint256 indexed vehicleId, string streamId) -func (_Registry *RegistryFilterer) WatchVehicleStreamSet(opts *bind.WatchOpts, sink chan<- *RegistryVehicleStreamSet, vehicleId []*big.Int) (event.Subscription, error) { - - var vehicleIdRule []interface{} - for _, vehicleIdItem := range vehicleId { - vehicleIdRule = append(vehicleIdRule, vehicleIdItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "VehicleStreamSet", vehicleIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryVehicleStreamSet) - if err := _Registry.contract.UnpackLog(event, "VehicleStreamSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseVehicleStreamSet is a log parse operation binding the contract event 0x09d0a7809cb7d90906448d57618581b65ca306d116e2b991721b9ef877d890de. -// -// Solidity: event VehicleStreamSet(uint256 indexed vehicleId, string streamId) -func (_Registry *RegistryFilterer) ParseVehicleStreamSet(log types.Log) (*RegistryVehicleStreamSet, error) { - event := new(RegistryVehicleStreamSet) - if err := _Registry.contract.UnpackLog(event, "VehicleStreamSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// RegistryVehicleStreamUnsetIterator is returned from FilterVehicleStreamUnset and is used to iterate over the raw logs and unpacked data for VehicleStreamUnset events raised by the Registry contract. -type RegistryVehicleStreamUnsetIterator struct { - Event *RegistryVehicleStreamUnset // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RegistryVehicleStreamUnsetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleStreamUnset) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RegistryVehicleStreamUnset) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RegistryVehicleStreamUnsetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RegistryVehicleStreamUnsetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RegistryVehicleStreamUnset represents a VehicleStreamUnset event raised by the Registry contract. -type RegistryVehicleStreamUnset struct { - VehicleId *big.Int - StreamId string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterVehicleStreamUnset is a free log retrieval operation binding the contract event 0x14692607635062a59787a92503915f7eca22e88b9bb3474438d0b393ad0ecf0d. -// -// Solidity: event VehicleStreamUnset(uint256 indexed vehicleId, string streamId) -func (_Registry *RegistryFilterer) FilterVehicleStreamUnset(opts *bind.FilterOpts, vehicleId []*big.Int) (*RegistryVehicleStreamUnsetIterator, error) { - - var vehicleIdRule []interface{} - for _, vehicleIdItem := range vehicleId { - vehicleIdRule = append(vehicleIdRule, vehicleIdItem) - } - - logs, sub, err := _Registry.contract.FilterLogs(opts, "VehicleStreamUnset", vehicleIdRule) - if err != nil { - return nil, err - } - return &RegistryVehicleStreamUnsetIterator{contract: _Registry.contract, event: "VehicleStreamUnset", logs: logs, sub: sub}, nil -} - -// WatchVehicleStreamUnset is a free log subscription operation binding the contract event 0x14692607635062a59787a92503915f7eca22e88b9bb3474438d0b393ad0ecf0d. -// -// Solidity: event VehicleStreamUnset(uint256 indexed vehicleId, string streamId) -func (_Registry *RegistryFilterer) WatchVehicleStreamUnset(opts *bind.WatchOpts, sink chan<- *RegistryVehicleStreamUnset, vehicleId []*big.Int) (event.Subscription, error) { - - var vehicleIdRule []interface{} - for _, vehicleIdItem := range vehicleId { - vehicleIdRule = append(vehicleIdRule, vehicleIdItem) - } - - logs, sub, err := _Registry.contract.WatchLogs(opts, "VehicleStreamUnset", vehicleIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RegistryVehicleStreamUnset) - if err := _Registry.contract.UnpackLog(event, "VehicleStreamUnset", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseVehicleStreamUnset is a log parse operation binding the contract event 0x14692607635062a59787a92503915f7eca22e88b9bb3474438d0b393ad0ecf0d. -// -// Solidity: event VehicleStreamUnset(uint256 indexed vehicleId, string streamId) -func (_Registry *RegistryFilterer) ParseVehicleStreamUnset(log types.Log) (*RegistryVehicleStreamUnset, error) { - event := new(RegistryVehicleStreamUnset) - if err := _Registry.contract.UnpackLog(event, "VehicleStreamUnset", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/internal/core/commands/bulk_validate_vin.go b/internal/core/commands/bulk_validate_vin.go index f9569a19..8801228a 100644 --- a/internal/core/commands/bulk_validate_vin.go +++ b/internal/core/commands/bulk_validate_vin.go @@ -9,6 +9,7 @@ import ( coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" "github.com/DIMO-Network/device-definitions-api/internal/core/queries" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/exceptions" + p_grpc "github.com/DIMO-Network/device-definitions-api/pkg/grpc" "github.com/DIMO-Network/shared/pkg/db" ) @@ -65,19 +66,11 @@ func (dc BulkValidateVinCommandHandler) Handle(ctx context.Context, query mediat devideDefinition, err := dc.DeviceDefinitionDataHandler.Handle(ctx, &queries.GetDeviceDefinitionByIDQuery{DeviceDefinitionID: decodedVIN.DefinitionId}) //nolint if err == nil { - dd := devideDefinition.(*coremodels.GetDeviceDefinitionQueryResult) - dm := coremodels.Manufacturer{ - TokenID: dd.MakeTokenID, - Name: dd.MakeName, + row, rowErr := decodedVINFrom(vin, decodedVIN, devideDefinition) + if rowErr != nil { + return nil, rowErr } - - decodedVINs = append(decodedVINs, DecodedVIN{ - VIN: vin, - DefinitionID: decodedVIN.DefinitionId, - DeviceYear: decodedVIN.Year, - DeviceMake: dm, - DeviceModel: devideDefinition.(*coremodels.GetDeviceDefinitionQueryResult).DeviceStyles[0].SubModel, - }) + decodedVINs = append(decodedVINs, row) } } @@ -88,3 +81,34 @@ func (dc BulkValidateVinCommandHandler) Handle(ctx context.Context, query mediat return response, nil } + +// decodedVINFrom builds one result row out of the decode and whatever +// GetDeviceDefinitionByIDQuery answered for its definition id. +// +// That handler answers the catalog's *coremodels.Template. The checked form +// is deliberate: an unchecked assertion here took the whole request down with +// a panic on the SUCCESS path -- every VIN that decoded and whose definition +// was in the catalog -- because it named a result type the handler had +// stopped returning. A surprise type is a broken contract worth reporting, +// not worth crashing over. +// +// DeviceModel is the template's model. It used to be the first device style's +// sub-model, which was both a different thing from the field's name and an +// unchecked index into a slice that is empty for any definition with no +// styles. +func decodedVINFrom(vin string, decoded *p_grpc.DecodeVinResponse, definition interface{}) (DecodedVIN, error) { + tmpl, ok := definition.(*coremodels.Template) + if !ok || tmpl == nil { + return DecodedVIN{}, fmt.Errorf("device definition %s: expected *models.Template from GetDeviceDefinitionByIDQuery, got %T", decoded.DefinitionId, definition) + } + return DecodedVIN{ + VIN: vin, + DefinitionID: decoded.DefinitionId, + DeviceYear: decoded.Year, + DeviceMake: coremodels.Manufacturer{ + TokenID: tmpl.Manufacturer.TokenID, + Name: tmpl.Manufacturer.Name, + }, + DeviceModel: tmpl.Model, + }, nil +} diff --git a/internal/core/commands/bulk_validate_vin_test.go b/internal/core/commands/bulk_validate_vin_test.go new file mode 100644 index 00000000..d9774ba2 --- /dev/null +++ b/internal/core/commands/bulk_validate_vin_test.go @@ -0,0 +1,72 @@ +package commands + +import ( + "testing" + + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" + p_grpc "github.com/DIMO-Network/device-definitions-api/pkg/grpc" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// GetDeviceDefinitionByIDQuery answers with the catalog's *coremodels.Template +// since the R2 migration. Building a result row out of it needs no database. + +func decodeResponse() *p_grpc.DecodeVinResponse { + return &p_grpc.DecodeVinResponse{ + DefinitionId: "toyota_camry_2026", + Year: 2026, + Model: "Camry", + } +} + +// The handler answers a template, and this is the type assertion that used to +// name a different one: a panic on the success path, for every VIN that +// decodes and whose definition is in the catalog. +func TestDecodedVINFromReadsTheTemplateTheHandlerAnswers(t *testing.T) { + tmpl := &coremodels.Template{ + ID: "toyota_camry_2026", + DeviceType: "vehicle", + Manufacturer: coremodels.TemplateManufacturer{Slug: "toyota", Name: "Toyota", TokenID: 131}, + Model: "Camry", + Year: 2026, + } + + got, err := decodedVINFrom("4T1C11AK8NU123456", decodeResponse(), tmpl) + + require.NoError(t, err) + assert.Equal(t, "4T1C11AK8NU123456", got.VIN) + assert.Equal(t, "toyota_camry_2026", got.DefinitionID) + assert.Equal(t, int32(2026), got.DeviceYear) + assert.Equal(t, "Camry", got.DeviceModel) + assert.Equal(t, coremodels.Manufacturer{TokenID: 131, Name: "Toyota"}, got.DeviceMake) +} + +// A template with no manufacturer token id is still a usable row: tokenId is +// optional in the contract, and the name is required. +func TestDecodedVINFromAcceptsATemplateWithNoManufacturerTokenID(t *testing.T) { + tmpl := &coremodels.Template{ + ID: "toyota_camry_2026", + Manufacturer: coremodels.TemplateManufacturer{Slug: "toyota", Name: "Toyota"}, + Model: "Camry", + Year: 2026, + } + + got, err := decodedVINFrom("4T1C11AK8NU123456", decodeResponse(), tmpl) + + require.NoError(t, err) + assert.Equal(t, coremodels.Manufacturer{TokenID: 0, Name: "Toyota"}, got.DeviceMake) + assert.Equal(t, "Camry", got.DeviceModel) +} + +// If the handler's return type ever changes again, say so instead of taking +// down the request. +func TestDecodedVINFromReportsASurpriseTypeAsAnError(t *testing.T) { + got, err := decodedVINFrom("4T1C11AK8NU123456", decodeResponse(), &coremodels.GetDeviceDefinitionQueryResult{}) + + require.Error(t, err, "an unexpected result type is an error, not a panic") + assert.Equal(t, DecodedVIN{}, got) + + _, err = decodedVINFrom("4T1C11AK8NU123456", decodeResponse(), nil) + require.Error(t, err, "a nil result is an error, not a panic") +} diff --git a/internal/core/commands/create_dd.go b/internal/core/commands/create_dd.go index e7f8b30c..e57d3945 100644 --- a/internal/core/commands/create_dd.go +++ b/internal/core/commands/create_dd.go @@ -48,7 +48,7 @@ type CreateDeviceDefinitionCommandResult struct { func (*CreateDeviceDefinitionCommand) Key() string { return "CreateDeviceDefinitionCommand" } type CreateDeviceDefinitionCommandHandler struct { - onChainSvc gateways.DeviceDefinitionOnChainService + catalogSvc gateways.DeviceDefinitionCatalogService dbs func() *db.ReaderWriter powerTrainTypeService services.PowerTrainTypeService fuelAPI gateways.FuelAPIService @@ -56,9 +56,9 @@ type CreateDeviceDefinitionCommandHandler struct { identity gateways.IdentityAPI } -func NewCreateDeviceDefinitionCommandHandler(onChainSvc gateways.DeviceDefinitionOnChainService, dbs func() *db.ReaderWriter, +func NewCreateDeviceDefinitionCommandHandler(catalogSvc gateways.DeviceDefinitionCatalogService, dbs func() *db.ReaderWriter, powerTrainTypeService services.PowerTrainTypeService, fuelAPI gateways.FuelAPIService, logger *zerolog.Logger, identity gateways.IdentityAPI) CreateDeviceDefinitionCommandHandler { - return CreateDeviceDefinitionCommandHandler{onChainSvc: onChainSvc, dbs: dbs, + return CreateDeviceDefinitionCommandHandler{catalogSvc: catalogSvc, dbs: dbs, powerTrainTypeService: powerTrainTypeService, fuelAPI: fuelAPI, logger: logger, identity: identity} @@ -128,8 +128,20 @@ func (ch CreateDeviceDefinitionCommandHandler) Handle(ctx context.Context, query ch.logger.Warn().Err(err).Msgf("failed to get images for: %s %d %s", command.Make, command.Year, command.Model) } + // An id definitions-worker can never hold is a bad request, not a server + // fault: the worker answers the create with 422, that error propagated as + // a plain error, and fiber reported the service as broken with a 500 for + // what is a make/model the caller has to correct. A ValidationError is the + // 4xx both the HTTP and gRPC layers already translate. + definitionID, err := common.DeviceDefinitionSlug(stringutils.SlugString(dm.Name), stringutils.SlugString(command.Model), int16(command.Year)) + if err != nil { + return nil, &exceptions.ValidationError{ + Err: fmt.Errorf("no device definition id can be built for %d %s %s: %w", command.Year, dm.Name, command.Model, err), + } + } + ddTbl := coremodels.DeviceDefinitionTablelandModel{ - ID: common.DeviceDefinitionSlug(stringutils.SlugString(dm.Name), stringutils.SlugString(command.Model), int16(command.Year)), + ID: definitionID, KSUID: ksuid.New().String(), Model: command.Model, Year: command.Year, @@ -138,7 +150,11 @@ func (ch CreateDeviceDefinitionCommandHandler) Handle(ctx context.Context, query Metadata: common.ConvertDeviceTypeAttrsToDefinitionMetadata(command.DeviceAttributes), } - create, err := ch.onChainSvc.Create(ctx, command.Make, ddTbl) + // The stored template is not used here: this command already answers with + // the id, which is the value Create used to return and the value + // TransactionID has carried since definitions stopped being written + // on-chain. + _, err = ch.catalogSvc.Create(ctx, command.Make, ddTbl) if err != nil { return nil, err // todo does mediator eat this error? } @@ -147,7 +163,7 @@ func (ch CreateDeviceDefinitionCommandHandler) Handle(ctx context.Context, query ch.logger.Err(err).Msgf("failed to add images to database for: %s %d %s", command.Make, command.Year, command.Model) } - return CreateDeviceDefinitionCommandResult{ID: ddTbl.ID, NameSlug: ddTbl.ID, TransactionID: create}, nil + return CreateDeviceDefinitionCommandResult{ID: ddTbl.ID, NameSlug: ddTbl.ID, TransactionID: &ddTbl.ID}, nil } func (ch CreateDeviceDefinitionCommandHandler) associateImagesToDeviceDefinition(ctx context.Context, definitionID string, img gateways.FuelDeviceImages) error { diff --git a/internal/core/commands/create_dd_id_test.go b/internal/core/commands/create_dd_id_test.go new file mode 100644 index 00000000..63957919 --- /dev/null +++ b/internal/core/commands/create_dd_id_test.go @@ -0,0 +1,107 @@ +package commands + +import ( + "context" + "errors" + "testing" + + sqlmock "github.com/DATA-DOG/go-sqlmock" + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" + mock_services "github.com/DIMO-Network/device-definitions-api/internal/core/services/mocks" + "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/exceptions" + "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" + mock_gateways "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways/mocks" + "github.com/DIMO-Network/shared/pkg/db" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +// The admin create builds the template id from the make and model it was +// given. definitions-worker answers 422 for an id its ID_RE refuses, that +// error propagated as a plain error, and fiber reported it as a 500 -- the +// service telling an operator it is broken when the request is what needs +// correcting. The decode path returns a typed not-found for the very same +// input. +// +// No Postgres: sqlmock answers the device_types read and every gateway is a +// mock. Only the write against a real catalog needs CI. + +func createHandler(t *testing.T) (CreateDeviceDefinitionCommandHandler, sqlmock.Sqlmock, *mock_gateways.MockDeviceDefinitionCatalogService) { + t.Helper() + sqlDB, mock, err := sqlmock.New() + require.NoError(t, err) + t.Cleanup(func() { _ = sqlDB.Close() }) + rw := &db.ReaderWriter{Reader: &db.DB{DB: sqlDB}, Writer: &db.DB{DB: sqlDB}} + + ctrl := gomock.NewController(t) + t.Cleanup(ctrl.Finish) + catalog := mock_gateways.NewMockDeviceDefinitionCatalogService(ctrl) + identity := mock_gateways.NewMockIdentityAPI(ctrl) + fuel := mock_gateways.NewMockFuelAPIService(ctrl) + powertrain := mock_services.NewMockPowerTrainTypeService(ctrl) + logger := zerolog.Nop() + + identity.EXPECT().GetManufacturer(gomock.Any()). + Return(&coremodels.Manufacturer{TokenID: 131, Name: "Toyota"}, nil).AnyTimes() + powertrain.EXPECT().ResolvePowerTrainType(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + Return("ICE", nil).AnyTimes() + fuel.EXPECT().FetchDeviceImages(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + Return(gateways.FuelDeviceImages{}, nil).AnyTimes() + + h := NewCreateDeviceDefinitionCommandHandler(catalog, func() *db.ReaderWriter { return rw }, powertrain, fuel, &logger, identity) + return h, mock, catalog +} + +func expectDeviceTypeRead(mock sqlmock.Sqlmock) { + mock.ExpectQuery(`SELECT .* FROM .*device_types.* WHERE`). + WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow("vehicle", "Vehicle")) +} + +// A model written in a script with no character in the worker's id class +// leaves the model segment empty after the repair, so no template can ever be +// stored at the id. The answer is a 4xx, and nothing is sent to the catalog. +func TestCreateDeviceDefinitionAnswersAValidationErrorForAnUnmintableID(t *testing.T) { + h, mock, catalog := createHandler(t) + expectDeviceTypeRead(mock) + // The premise of the finding: this must never reach the worker, whose 422 + // dd-api cannot act on. + catalog.EXPECT().Create(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + + res, err := h.Handle(context.Background(), &CreateDeviceDefinitionCommand{ + Make: "Toyota", + Model: "ハイエース", + Year: 2020, + }) + + require.Error(t, err) + assert.Nil(t, res) + var validation *exceptions.ValidationError + require.ErrorAs(t, err, &validation, "an id the worker can never hold is a bad request, not a 500") + var internal *exceptions.InternalError + assert.False(t, errors.As(err, &internal), "it must not be reported as a server fault") + assert.Contains(t, err.Error(), "ハイエース") +} + +// The ordinary create still reaches the catalog with the id it built. +func TestCreateDeviceDefinitionSendsAMintableIDToTheCatalog(t *testing.T) { + h, mock, catalog := createHandler(t) + expectDeviceTypeRead(mock) + catalog.EXPECT().Create(gomock.Any(), "Toyota", gomock.Any()). + DoAndReturn(func(_ context.Context, _ string, dd coremodels.DeviceDefinitionTablelandModel) (*coremodels.Template, error) { + assert.Equal(t, "toyota_camry_2026", dd.ID) + return &coremodels.Template{ID: dd.ID}, nil + }) + + res, err := h.Handle(context.Background(), &CreateDeviceDefinitionCommand{ + Make: "Toyota", + Model: "Camry", + Year: 2026, + }) + + require.NoError(t, err) + created, ok := res.(CreateDeviceDefinitionCommandResult) + require.True(t, ok) + assert.Equal(t, "toyota_camry_2026", created.ID) +} diff --git a/internal/core/common/attributes.go b/internal/core/common/attributes.go new file mode 100644 index 00000000..efcb6f84 --- /dev/null +++ b/internal/core/common/attributes.go @@ -0,0 +1,44 @@ +package common + +import ( + "fmt" + "sort" + "strconv" +) + +// AttributeString renders a typed template attribute for the legacy +// string-valued shapes the API still serves. +// +// Template attributes decode into map[string]any, so every number arrives as a +// float64. strconv rather than fmt so 15.8 renders "15.8" and not "1.58e+01", +// and a price of 1250000 renders "1250000" and not "1.25e+06". Both the +// definition path and the device-style path call this, so one definition's +// attributes read the same whichever endpoint served them. +func AttributeString(v any) string { + switch t := v.(type) { + case string: + return t + case bool: + return strconv.FormatBool(t) + case float64: + return strconv.FormatFloat(t, 'f', -1, 64) + case int: + return strconv.Itoa(t) + default: + return fmt.Sprint(v) + } +} + +// SortedAttributeNames returns a template's attribute names in a stable order. +// +// Ranging over the map directly puts the attributes in a different order on +// every call, so two requests for the same definition answered with the same +// attributes in a different arrangement. +func SortedAttributeNames(attributes map[string]any) []string { + names := make([]string, 0, len(attributes)) + for name := range attributes { + names = append(names, name) + } + sort.Strings(names) + return names +} diff --git a/internal/core/common/attributes_test.go b/internal/core/common/attributes_test.go new file mode 100644 index 00000000..b7ebe844 --- /dev/null +++ b/internal/core/common/attributes_test.go @@ -0,0 +1,58 @@ +package common + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// Template attributes decode into map[string]any, so every number is a +// float64. fmt.Sprint formats those with %g -- a price of 1250000 renders as +// "1.25e+06" and 15.8 as "1.58e+01" -- and ranging over the map puts the +// attributes in a different order on every request. Both call sites that +// flatten a template's attributes share this one renderer and this one order. + +func TestAttributeStringRendersNumbersWithoutScientificNotation(t *testing.T) { + tests := []struct { + name string + value any + want string + }{ + {"a price", float64(1250000), "1250000"}, + {"a fuel tank", float64(15.8), "15.8"}, + {"a door count", float64(4), "4"}, + {"a large round number", float64(1e21), "1000000000000000000000"}, + {"a small fraction", float64(0.25), "0.25"}, + {"a string", "AWD", "AWD"}, + {"a bool", true, "true"}, + {"an int", 7, "7"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, AttributeString(tt.value)) + assert.NotContains(t, AttributeString(tt.value), "e+", "a value rendered in scientific notation is not the number a client asked for") + }) + } +} + +// The order has to be the same on every call for the same template, or the +// attribute array shuffles between two requests for one style. +func TestSortedAttributeNamesIsStable(t *testing.T) { + attributes := map[string]any{ + "number_of_doors": float64(4), + "base_msrp": float64(1250000), + "driven_wheels": "AWD", + "fuel_tank_capacity_gal": float64(15.8), + "powertrain_type": "ICE", + } + + want := []string{"base_msrp", "driven_wheels", "fuel_tank_capacity_gal", "number_of_doors", "powertrain_type"} + for i := 0; i < 20; i++ { + assert.Equal(t, want, SortedAttributeNames(attributes)) + } +} + +func TestSortedAttributeNamesHandlesNoAttributes(t *testing.T) { + assert.Empty(t, SortedAttributeNames(nil)) + assert.Empty(t, SortedAttributeNames(map[string]any{})) +} diff --git a/internal/core/common/utils.go b/internal/core/common/utils.go index 1740011d..705e4335 100644 --- a/internal/core/common/utils.go +++ b/internal/core/common/utils.go @@ -2,14 +2,16 @@ package common import ( "encoding/json" + "errors" "fmt" - "net/http" + "regexp" + "strconv" "strings" coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" repoModel "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/db/models" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/exceptions" - "github.com/DIMO-Network/device-definitions-api/pkg/grpc" + stringutils "github.com/DIMO-Network/shared/pkg/strings" "github.com/aarondl/null/v8" ) @@ -45,17 +47,6 @@ func BuildExternalIDs(externalIDsJSON null.JSON) []*coremodels.ExternalID { return externalIDs } -func ExternalIDsToGRPC(externalIDs []*coremodels.ExternalID) []*grpc.ExternalID { - externalIDsGRPC := make([]*grpc.ExternalID, len(externalIDs)) - for i, ei := range externalIDs { - externalIDsGRPC[i] = &grpc.ExternalID{ - Vendor: ei.Vendor, - Id: ei.ID, - } - } - return externalIDsGRPC -} - // GetDefaultImageURL if the images relation is not empty, looks for the best image to use based on some logic func GetDefaultImageURL(images []*repoModel.Image) string { img := "" @@ -292,36 +283,125 @@ func BuildDeviceDefinitionName(year int16, mk string, model string) string { return fmt.Sprintf("%d %s %s", year, mk, model) } -func DeviceDefinitionSlug(makeSlug, modelSlug string, year int16) string { +// definitions-worker accepts template ids matching +// ^[a-z0-9][a-z0-9._&+-]*_[a-z0-9._&+-]+_[0-9]{4}$ (src/template.ts ID_RE) and +// answers 422 for anything else. dd-api cannot learn that from the response in +// any way it can act on: a decode that builds such an id -- volkswagen_up!_2025, +// subaru_tribeca-(ny/nj)_2008 -- 404s on the read, 422s on the create, and +// fails identically on every retry. So the id must never carry a character the +// worker rejects. DeviceDefinitionSlug is the one place every id is built. +var ( + workerIDValid = regexp.MustCompile(`^[a-z0-9][a-z0-9._&+-]*_[a-z0-9._&+-]+_[0-9]{4}$`) + workerIDDisallowed = regexp.MustCompile(`[^a-z0-9._&+-]`) +) + +// The year bounds a definition id must fall inside. ID_RE only constrains the +// year to four digits, so it accepts 0000, 1000, 3500 and 9999 -- exactly what a +// decoder produces when it misreads the model-year VIN digit, and +// indistinguishable from a real template once it is in the catalog, because +// nothing downstream checks it. +// +// The range is deliberately a plausibility check and not "no later than next +// model year". This function also computes the lookup id for definitions that +// already exist, and the production catalog holds templates out to +// bmw_5-series_2031 and honda_fit_2029. A tight upper bound would refuse to +// build their ids and break the decode for every vehicle already minted against +// them -- turning historical bad data into a present outage. 1885 predates the +// first production automobile, so nothing real falls below it. +const ( + minDefinitionYear = 1885 + maxDefinitionYear = 2100 +) + +// DeviceDefinitionSlug builds __, the template id, and +// refuses one definitions-worker can never hold. +// +// The repair below drops characters, and dropping every character of a part +// leaves a segment ID_RE refuses just as firmly as the id it replaced. So the +// builder checks its own output: an id that fails ValidateDefinitionID comes +// back as ("", err) wrapping ErrUnmintableDefinitionID, and the id is not +// returned alongside it -- a caller that ignores the error must not be able to +// write the row or send the PUT anyway. Before this, only one of the five +// production call sites validated, and the contract on ValidateDefinitionID +// ("nothing may PUT, or build a vin_numbers row on, an id that fails it") was +// enforced nowhere else. +// +// An id the worker already accepts is returned exactly as it has always been +// built. The catalog holds ids like volkswagen_id--buzz_2024 (model "ID. Buzz" +// slugs to id--buzz) and bmw_x3-_2026, and reshaping those would point every +// new decode of that model at an id with no template, which the decode then +// creates as a duplicate. Only an id the worker would refuse is repaired: each +// part is slugged, which also covers cmd/device-definitions-api passing the +// make and model raw, and stripped of every character outside the worker's +// class. Nothing else changes, so the raw and slugged inputs for one model +// still agree. An underscore can never survive inside a part: it is the +// separator, and templateFromDefinition reads the manufacturer slug back as +// everything before the first one. +func DeviceDefinitionSlug(makeSlug, modelSlug string, year int16) (string, error) { + // Checked before anything else, and separately from ValidateDefinitionID: the + // fast path below returns as soon as the id matches ID_RE, so a year the + // regex happens to accept would never reach the validator, and the repair + // path cannot fix a bad year by reshaping the make or model anyway. + if int(year) < minDefinitionYear || int(year) > maxDefinitionYear { + return "", fmt.Errorf("%w: implausible model year %d (expected %d-%d)", + ErrUnmintableDefinitionID, year, minDefinitionYear, maxDefinitionYear) + } + modelSlugCleaned := strings.ReplaceAll(modelSlug, ",", "") modelSlugCleaned = strings.ReplaceAll(modelSlugCleaned, "/", "-") modelSlugCleaned = strings.ReplaceAll(modelSlugCleaned, ".", "-") - return fmt.Sprintf("%s_%s_%d", makeSlug, modelSlugCleaned, year) + if id := fmt.Sprintf("%s_%s_%d", makeSlug, modelSlugCleaned, year); workerIDValid.MatchString(id) { + return id, nil + } + repaired := fmt.Sprintf("%s_%s_%d", workerIDPart(makeSlug), workerIDPart(modelSlugCleaned), year) + if err := ValidateDefinitionID(repaired); err != nil { + return "", err + } + return repaired, nil } -func CheckTransactionStatus(txHash, apiKey string, useAmoy bool) (bool, error) { - baseURL := "https://api.polygonscan.com" - if useAmoy { - baseURL = "https://amoy.polygonscan.com" - } - url := fmt.Sprintf("%s/api?module=transaction&action=gettxreceiptstatus&txhash=%s&apikey=%s", baseURL, txHash, apiKey) +// workerIDPart repairs one part of an id the worker would refuse: slug it, then +// drop every character outside the worker's class. +// +// Dropping can empty a part outright -- a model written entirely in a script +// with no character in the class, such as ハイエース or Нива, leaves nothing +// behind -- and ID_RE requires at least one character in each. The repair +// cannot fix that: there is no character to keep. DeviceDefinitionSlug checks +// its own output with ValidateDefinitionID and returns an error rather than +// such an id, so no caller can build on one. +func workerIDPart(part string) string { + return workerIDDisallowed.ReplaceAllString(stringutils.SlugString(part), "") +} - resp, err := http.Get(url) - if err != nil { - return false, err - } - defer resp.Body.Close() +// ErrUnmintableDefinitionID reports an id no template can ever be stored at: +// definitions-worker's ID_RE refuses it, so its create answers 422 and so does +// every retry of every VIN of that model-year, forever. It is a sentinel so a +// caller can tell this apart from a transient write failure with errors.Is and +// stop rather than retry. +var ErrUnmintableDefinitionID = errors.New("definition id is one definitions-worker can never accept") - var txStatus TxStatusResponse - if err := json.NewDecoder(resp.Body).Decode(&txStatus); err != nil { - return false, err +// ValidateDefinitionID reports whether definitions-worker can hold a template +// at this id, and wraps ErrUnmintableDefinitionID when it cannot. +// +// DeviceDefinitionSlug repairs an id by dropping characters, and a repair that +// drops every character of a part leaves a segment empty -- an id ID_RE +// refuses just as firmly as the one the repair replaced. The repair never +// re-checks its own output, so this is the check: nothing may PUT, or build a +// vin_numbers row on, an id that fails it. +func ValidateDefinitionID(id string) error { + if !workerIDValid.MatchString(id) { + return fmt.Errorf("%w: %q", ErrUnmintableDefinitionID, id) } - - // Check the transaction status - if txStatus.Status == "1" && txStatus.Result.Status == "1" { - return true, nil + // The regex above guarantees the last four characters are digits. + year, err := strconv.Atoi(id[len(id)-4:]) + if err != nil { + return fmt.Errorf("%w: %q", ErrUnmintableDefinitionID, id) + } + if year < minDefinitionYear || year > maxDefinitionYear { + return fmt.Errorf("%w: %q has an implausible model year %d (expected %d-%d)", + ErrUnmintableDefinitionID, id, year, minDefinitionYear, maxDefinitionYear) } - return false, nil + return nil } func ConvertMetadataToDeviceAttributes(metadata *coremodels.DeviceDefinitionMetadata) []coremodels.DeviceTypeAttributeEditor { diff --git a/internal/core/common/utils_test.go b/internal/core/common/utils_test.go index 46099290..e38d56dc 100644 --- a/internal/core/common/utils_test.go +++ b/internal/core/common/utils_test.go @@ -2,10 +2,19 @@ package common import ( _ "embed" + "regexp" "testing" + "encoding/json" + "fmt" + "math" + "os" + "strconv" + "strings" + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/db/models" + stringutils "github.com/DIMO-Network/shared/pkg/strings" "github.com/aarondl/null/v8" "github.com/segmentio/ksuid" "github.com/stretchr/testify/assert" @@ -24,28 +33,6 @@ func TestBuildExternalIds(t *testing.T) { assert.Contains(t, got, &coremodels.ExternalID{Vendor: "adac", ID: "890"}) } -func TestExternalIdsToGRPC(t *testing.T) { - - extIDs := []*coremodels.ExternalID{ - {Vendor: "edmunds", ID: "123"}, - {Vendor: "nhtsa", ID: "qwert"}, - {Vendor: "adac", ID: "890"}, - } - - got := ExternalIDsToGRPC(extIDs) - - assert.Equal(t, 3, len(got)) - - assert.Equal(t, "edmunds", got[0].Vendor) - assert.Equal(t, "123", got[0].Id) - - assert.Equal(t, "nhtsa", got[1].Vendor) - assert.Equal(t, "qwert", got[1].Id) - - assert.Equal(t, "adac", got[2].Vendor) - assert.Equal(t, "890", got[2].Id) -} - //go:embed device_type_vehicle_properties.json var deviceTypeVehiclePropertyDataSample []byte @@ -173,7 +160,402 @@ func TestDeviceDefinitionSlug(t *testing.T) { } for _, tt := range tests { t.Run(tt.makeSlug+""+tt.modelSlug, func(t *testing.T) { - assert.Equalf(t, tt.want, DeviceDefinitionSlug(tt.makeSlug, tt.modelSlug, tt.year), "SlugString(%v)", tt.makeSlug) + got, err := DeviceDefinitionSlug(tt.makeSlug, tt.modelSlug, tt.year) + require.NoError(t, err) + assert.Equalf(t, tt.want, got, "SlugString(%v)", tt.makeSlug) + }) + } +} + +// workerIDRegex mirrors definitions-worker/src/template.ts ID_RE. The worker +// answers 422 for any id outside it, and dd-api has no other way to learn +// that: a decode that builds such an id fails on every retry, forever. +var workerIDRegex = regexp.MustCompile(`^[a-z0-9][a-z0-9._&+-]*_[a-z0-9._&+-]+_[0-9]{4}$`) + +func TestDeviceDefinitionSlugMatchesWorkerIDRegex(t *testing.T) { + tests := []struct { + make string + model string + year int16 + want string + }{ + // The two shapes seen in production decodes. + {make: "Volkswagen", model: "up!", year: 2025, want: "volkswagen_up_2025"}, + {make: "Subaru", model: "Tribeca (NY/NJ)", year: 2008, want: "subaru_tribeca-ny-nj_2008"}, + {make: "Ford", model: `"Special" Edition`, year: 2019, want: "ford_special-edition_2019"}, + {make: "Tesla", model: "Model 3", year: 2022, want: "tesla_model-3_2022"}, + {make: "Chrysler", model: "C/D 4.5", year: 2001, want: "chrysler_c-d-4-5_2001"}, + // Characters the worker accepts survive. + {make: "Dodge", model: "Town & Country", year: 2012, want: "dodge_town-&-country_2012"}, + {make: "Mercedes-Benz", model: "GLE 450+", year: 2024, want: "mercedes-benz_gle-450+_2024"}, + // A stripped character leaves its neighbours as they were. + {make: "Kia", model: "Soul !EV!", year: 2020, want: "kia_soul-ev_2020"}, + } + for _, tt := range tests { + t.Run(tt.make+" "+tt.model, func(t *testing.T) { + // The decode path slugs both parts first; the sanitizer must + // hold for what SlugString leaves behind. + got, err := DeviceDefinitionSlug(stringutils.SlugString(tt.make), stringutils.SlugString(tt.model), tt.year) + require.NoError(t, err) + assert.Equal(t, tt.want, got) + assert.Regexp(t, workerIDRegex, got) + + // cmd/device-definitions-api/decode_vin.go passes the decoded + // make and model raw, so the raw shape must be safe as well. + raw, err := DeviceDefinitionSlug(tt.make, tt.model, tt.year) + require.NoError(t, err) + assert.Equal(t, tt.want, raw) + assert.Regexp(t, workerIDRegex, raw) + }) + } +} + +// legacyDeviceDefinitionSlug is DeviceDefinitionSlug as it was before ids were +// checked against the worker. Every id it builds that the worker accepts must +// come out of DeviceDefinitionSlug unchanged, or new decodes of that model stop +// finding their template and create a duplicate. +func legacyDeviceDefinitionSlug(makeSlug, modelSlug string, year int16) string { + modelSlugCleaned := strings.ReplaceAll(modelSlug, ",", "") + modelSlugCleaned = strings.ReplaceAll(modelSlugCleaned, "/", "-") + modelSlugCleaned = strings.ReplaceAll(modelSlugCleaned, ".", "-") + return fmt.Sprintf("%s_%s_%d", makeSlug, modelSlugCleaned, year) +} + +func TestDeviceDefinitionSlugKeepsIDsTheWorkerAccepts(t *testing.T) { + // Live catalog ids whose model slug carries a dash run or a trailing dash. + tests := []struct { + make string + model string + year int16 + }{ + {"volkswagen", "id--buzz", 2024}, + {"volkswagen", "id--buzz-cargo", 2025}, + {"ford", "ranger---ra", 2022}, + {"bmw", "x3-", 2026}, + } + for _, tt := range tests { + want := fmt.Sprintf("%s_%s_%d", tt.make, tt.model, tt.year) + t.Run(want, func(t *testing.T) { + got, err := DeviceDefinitionSlug(tt.make, tt.model, tt.year) + require.NoError(t, err) + assert.Equal(t, want, got) + }) + } + // The decode path slugs "ID. Buzz" to id--buzz; the raw cmd path must agree. + slugged, err := DeviceDefinitionSlug(stringutils.SlugString("Volkswagen"), stringutils.SlugString("ID. Buzz"), 2024) + require.NoError(t, err) + assert.Equal(t, "volkswagen_id--buzz_2024", slugged) + raw, err := DeviceDefinitionSlug("Volkswagen", "ID. Buzz", 2024) + require.NoError(t, err) + assert.Equal(t, "volkswagen_id--buzz_2024", raw) +} + +// The repair in DeviceDefinitionSlug drops every character outside the +// worker's class, so a model written in a script with no characters in that +// class at all -- Japanese, Cyrillic -- leaves the model segment empty. ID_RE +// requires at least one character there, so no template can ever be stored at +// such an id: a create 422s, and so does every retry, forever. These are +// reachable, not hypothetical: vinInfoFromKnown's KnownModel comes from +// smartcar and software connections and its source is not low-confidence. +func TestValidateDefinitionIDRefusesAnIDNoTemplateCanExistAt(t *testing.T) { + unmintable := []struct { + make string + model string + year int16 + }{ + {"Toyota", "ハイエース", 2020}, + {"Lada", "Нива", 2021}, + {"Toyota", "・・・", 2020}, + } + for _, tt := range unmintable { + t.Run(tt.make+" "+tt.model, func(t *testing.T) { + // The premise: the repair produces an id the worker refuses. + repaired := fmt.Sprintf("%s_%s_%d", workerIDPart(stringutils.SlugString(tt.make)), workerIDPart(stringutils.SlugString(tt.model)), tt.year) + assert.NotRegexp(t, workerIDRegex, repaired, "the premise: this id is one the worker refuses") + err := ValidateDefinitionID(repaired) + require.Error(t, err) + assert.ErrorIs(t, err, ErrUnmintableDefinitionID) + assert.Contains(t, err.Error(), repaired, "the id the decode could not build must be in the message") + }) + } +} + +// The builder validates what it produced, so no caller can be handed an id no +// template can exist at -- which is what ValidateDefinitionID's own contract +// demands and what four of the five call sites never did. The id is not +// returned alongside the error: a caller that ignores the error must not be +// able to write one anyway. +func TestDeviceDefinitionSlugRefusesAnIDItCannotRepair(t *testing.T) { + unmintable := []struct { + make string + model string + year int16 + }{ + {"Toyota", "\u30cf\u30a4\u30a8\u30fc\u30b9", 2020}, + {"Lada", "\u041d\u0438\u0432\u0430", 2021}, + {"Toyota", "\u30fb\u30fb\u30fb", 2020}, + } + for _, tt := range unmintable { + t.Run(tt.make+" "+tt.model, func(t *testing.T) { + // Both call shapes: the decode path slugs first, cmd passes raw. + slugged, err := DeviceDefinitionSlug(stringutils.SlugString(tt.make), stringutils.SlugString(tt.model), tt.year) + require.Error(t, err) + assert.ErrorIs(t, err, ErrUnmintableDefinitionID) + assert.Empty(t, slugged, "an id that cannot be built must not be handed back anyway") + + raw, err := DeviceDefinitionSlug(tt.make, tt.model, tt.year) + require.Error(t, err) + assert.ErrorIs(t, err, ErrUnmintableDefinitionID) + assert.Empty(t, raw) + }) + } +} + +// An id the worker accepts comes back with no error, whether it needed the +// repair or not. +func TestDeviceDefinitionSlugAcceptsWhatItCanBuild(t *testing.T) { + ok := []struct { + make string + model string + year int16 + want string + }{ + {"Toyota", "Camry", 2026, "toyota_camry_2026"}, + {"Volkswagen", "up!", 2025, "volkswagen_up_2025"}, + // A part with something left after the drop is repaired, not refused; + // the leading dash the drop leaves behind is inside the worker's class. + {"Toyota", "\u30cf\u30a4\u30a8\u30fc\u30b9 Van", 2020, "toyota_-van_2020"}, + } + for _, tt := range ok { + t.Run(tt.want, func(t *testing.T) { + got, err := DeviceDefinitionSlug(stringutils.SlugString(tt.make), stringutils.SlugString(tt.model), tt.year) + require.NoError(t, err) + assert.Equal(t, tt.want, got) + assert.Regexp(t, workerIDRegex, got) + }) + } +} + +// Everything the worker accepts -- including the repaired ids the repair +// exists to produce and the live catalog shapes it must leave alone -- passes. +func TestValidateDefinitionIDAcceptsEveryIDTheWorkerAccepts(t *testing.T) { + mintable := []string{ + "volkswagen_up_2020", + "subaru_tribeca-ny-nj_2020", + "toyota_camry_2026", + "volkswagen_id--buzz_2024", + "ford_ranger---ra_2022", + "bmw_x3-_2026", + "dodge_town-&-country_2012", + "mercedes-benz_gle-450+_2024", + } + for _, id := range mintable { + t.Run(id, func(t *testing.T) { + assert.Regexp(t, workerIDRegex, id, "the premise: this id is one the worker accepts") + assert.NoError(t, ValidateDefinitionID(id)) + }) + } +} + +// TestDeviceDefinitionSlugAgainstManifest replays every id in a definitions +// manifest through DeviceDefinitionSlug. Run it with +// DEFINITIONS_MANIFEST=path/to/manifest.json (for example a download of +// https://definitions.dimo.org/manifest.json). An id the legacy builder +// produces and the worker accepts must be unchanged; one the worker refuses +// must be repaired into one it accepts. +func TestDeviceDefinitionSlugAgainstManifest(t *testing.T) { + path := os.Getenv("DEFINITIONS_MANIFEST") + if path == "" { + t.Skip("DEFINITIONS_MANIFEST not set") + } + raw, err := os.ReadFile(path) + require.NoError(t, err) + ids := manifestIDs(t, raw) + require.NotEmpty(t, ids) + + var checked, unchanged, repaired int + for _, id := range ids { + first, last := strings.Index(id, "_"), strings.LastIndex(id, "_") + if first <= 0 || last <= first { + continue + } + year, err := strconv.Atoi(id[last+1:]) + if err != nil { + continue + } + mk, model := id[:first], id[first+1:last] + legacy := legacyDeviceDefinitionSlug(mk, model, int16(year)) + got, err := DeviceDefinitionSlug(mk, model, int16(year)) + if !assert.NoError(t, err, "a stored id could not be rebuilt: %s", id) { + continue + } + checked++ + if workerIDRegex.MatchString(legacy) { + if assert.Equal(t, legacy, got, "an id the worker accepts changed: %s", id) { + unchanged++ + } + continue + } + if assert.Regexp(t, workerIDRegex, got, "a refused id was not repaired: %s", id) { + repaired++ + } + } + t.Logf("manifest ids=%d checked=%d unchanged=%d repaired=%d", len(ids), checked, unchanged, repaired) +} + +// manifestIDs reads the definition ids from a manifest whose definitions are +// either a list of objects with an id or an object keyed by id. +func manifestIDs(t *testing.T, raw []byte) []string { + var doc struct { + Definitions json.RawMessage `json:"definitions"` + } + require.NoError(t, json.Unmarshal(raw, &doc)) + var list []struct { + ID string `json:"id"` + } + if err := json.Unmarshal(doc.Definitions, &list); err == nil { + ids := make([]string, 0, len(list)) + for _, d := range list { + if d.ID != "" { + ids = append(ids, d.ID) + } + } + return ids + } + var byID map[string]json.RawMessage + require.NoError(t, json.Unmarshal(doc.Definitions, &byID)) + ids := make([]string, 0, len(byID)) + for id := range byID { + ids = append(ids, id) + } + return ids +} + +// manifestDefinition is one catalog definition as the manifest carries it: the +// stored id, and the manufacturer name, model and year a decode builds it from. +type manifestDefinition struct { + ID string `json:"id"` + Manufacturer struct { + Name string `json:"name"` + } `json:"manufacturer"` + Model string `json:"model"` + Year int `json:"year"` +} + +func manifestDefinitions(t *testing.T, raw []byte) []manifestDefinition { + var doc struct { + Definitions []manifestDefinition `json:"definitions"` + } + require.NoError(t, json.Unmarshal(raw, &doc)) + return doc.Definitions +} + +// TestDeviceDefinitionSlugAgainstManifestNames builds every definition's id +// from its real manufacturer name and model, the inputs a decode starts from, +// through both call shapes: slugged first, as the decode path passes them, and +// raw, as cmd/device-definitions-api does. The shapes must agree, an id the +// legacy builder produced that the worker accepts must be unchanged, and a +// refused one must be repaired into one the worker accepts. Feeding a stored +// id's own parts back in cannot show this: the legacy builder returns most of +// those unchanged by construction. Run with DEFINITIONS_MANIFEST as above. +func TestDeviceDefinitionSlugAgainstManifestNames(t *testing.T) { + path := os.Getenv("DEFINITIONS_MANIFEST") + if path == "" { + t.Skip("DEFINITIONS_MANIFEST not set") + } + raw, err := os.ReadFile(path) + require.NoError(t, err) + defs := manifestDefinitions(t, raw) + require.NotEmpty(t, defs) + + var checked, agree, unchanged, repaired, newRebuildsStored, legacyRebuildsStored int + for _, d := range defs { + name := d.Manufacturer.Name + if name == "" || d.Model == "" || d.Year <= 0 || d.Year > math.MaxInt16 { + continue + } + year := int16(d.Year) + mk, model := stringutils.SlugString(name), stringutils.SlugString(d.Model) + legacy := legacyDeviceDefinitionSlug(mk, model, year) + slugged, errSlugged := DeviceDefinitionSlug(mk, model, year) + rawID, errRaw := DeviceDefinitionSlug(name, d.Model, year) + if !assert.NoError(t, errSlugged, "a stored definition's id could not be rebuilt: %s (%q %q)", d.ID, name, d.Model) || + !assert.NoError(t, errRaw, "a stored definition's id could not be rebuilt from raw inputs: %s (%q %q)", d.ID, name, d.Model) { + continue + } + checked++ + if assert.Equal(t, slugged, rawID, "raw and slugged inputs disagree for %s (%q %q)", d.ID, name, d.Model) { + agree++ + } + if workerIDRegex.MatchString(legacy) { + if assert.Equal(t, legacy, slugged, "an id the worker accepts changed for %s (%q %q)", d.ID, name, d.Model) { + unchanged++ + } + } else if assert.Regexp(t, workerIDRegex, slugged, "a refused id was not repaired for %s (%q %q)", d.ID, name, d.Model) { + repaired++ + } + if slugged == d.ID { + newRebuildsStored++ + } + if legacy == d.ID { + legacyRebuildsStored++ + } + } + t.Logf("definitions=%d checked=%d raw-agrees=%d valid-unchanged=%d repaired=%d rebuilds-stored-id new=%d legacy=%d", + len(defs), checked, agree, unchanged, repaired, newRebuildsStored, legacyRebuildsStored) +} + +// ID_RE constrains the year to four digits and nothing more, so it accepts 0000, +// 1000, 3500 and 9999 -- which is precisely the shape a decoder produces when it +// misreads the model-year VIN digit. Nothing downstream re-checks it, so once +// such a template is in the catalog it is indistinguishable from a real one. +func TestValidateDefinitionIDRefusesImplausibleYears(t *testing.T) { + for _, id := range []string{ + "toyota_camry_0000", + "toyota_camry_1000", + "toyota_camry_1884", + "toyota_camry_3500", + "toyota_camry_9999", + } { + t.Run(id, func(t *testing.T) { + // The premise: ID_RE itself is perfectly happy with this id. + assert.Regexp(t, workerIDRegex, id, "the premise: the worker's own regex accepts this") + + err := ValidateDefinitionID(id) + require.Error(t, err) + assert.ErrorIs(t, err, ErrUnmintableDefinitionID) + assert.Contains(t, err.Error(), id) + }) + } +} + +// The bound is a plausibility check, not "no later than next model year". The +// production catalog holds templates out to bmw_5-series_2031 and +// honda_fit_2029; refusing to build their ids would break the decode for every +// vehicle already minted against them. +func TestValidateDefinitionIDAcceptsYearsAlreadyInTheCatalog(t *testing.T) { + for _, id := range []string{ + "toyota_camry_1988", + "toyota_camry_2020", + "honda_fit_2029", + "bmw_5-series_2031", + } { + t.Run(id, func(t *testing.T) { + assert.NoError(t, ValidateDefinitionID(id)) + }) + } +} + +// DeviceDefinitionSlug returns early as soon as the assembled id matches ID_RE, +// so the year has to be checked before that fast path or it is never checked at +// all. No id may be returned alongside the error. +func TestDeviceDefinitionSlugRefusesImplausibleYears(t *testing.T) { + for _, year := range []int16{0, 1, 999, 1884, 2101, 9999} { + t.Run(fmt.Sprintf("year %d", year), func(t *testing.T) { + id, err := DeviceDefinitionSlug("toyota", "camry", year) + require.Error(t, err) + assert.ErrorIs(t, err, ErrUnmintableDefinitionID) + assert.Empty(t, id, "no id may come back alongside the error") }) } } diff --git a/internal/core/models/device_definition_models.go b/internal/core/models/device_definition_models.go index 5f6946c9..0dd6bbf7 100644 --- a/internal/core/models/device_definition_models.go +++ b/internal/core/models/device_definition_models.go @@ -43,6 +43,7 @@ type VehicleInfo struct { MPGHighway string `json:"mpg_highway,omitempty"` MPGCity string `json:"mpg_city,omitempty"` FuelTankCapacityGal string `json:"fuel_tank_capacity_gal,omitempty"` + BatteryCapacityKwh string `json:"battery_capacity_kwh,omitempty"` MPG string `json:"mpg,omitempty"` } diff --git a/internal/core/models/template.go b/internal/core/models/template.go new file mode 100644 index 00000000..d8a50b91 --- /dev/null +++ b/internal/core/models/template.go @@ -0,0 +1,55 @@ +//nolint:tagliatelle +package models + +// Template mirrors definitions-worker/schema/template.schema.json: a vehicle +// trim-configuration template covering one model-year plus the trims it +// shipped in. Attributes true of every trim live on Attributes; anything +// that differs between trims lives on the trim itself. +// +// Attribute values are typed in the contract -- a number arrives as a +// number -- so they are decoded as any rather than string. +type Template struct { + ID string `json:"id"` + DeviceType string `json:"deviceType"` + Manufacturer TemplateManufacturer `json:"manufacturer"` + Model string `json:"model"` + Year int `json:"year"` + ImageURI string `json:"imageURI,omitempty"` + // HardwareTemplateID is DIMO hardware configuration, not a vehicle + // attribute, which is why it sits outside Attributes and is never + // validated against the vehicle vocabulary. + HardwareTemplateID string `json:"hardwareTemplateId,omitempty"` + Attributes map[string]any `json:"attributes"` + Trims []Trim `json:"trims"` + Version int `json:"version"` + Author string `json:"author,omitempty"` + CreatedAt string `json:"createdAt,omitempty"` + UpdatedAt string `json:"updatedAt,omitempty"` +} + +type TemplateManufacturer struct { + Slug string `json:"slug"` + Name string `json:"name"` + TokenID int `json:"tokenId,omitempty"` +} + +// Trim is one configuration a Template's model-year shipped in. Every +// template carries at least one, even a model-year sold in a single +// configuration. +type Trim struct { + Name string `json:"name"` + Selectors TrimSelectors `json:"selectors"` + // HardwareTemplateID overrides the template's value for this trim only; + // same "not a vehicle attribute" rule as Template.HardwareTemplateID. + HardwareTemplateID string `json:"hardwareTemplateId,omitempty"` + Attributes map[string]any `json:"attributes"` +} + +// TrimSelectors are the signals a decoded VIN is matched against to narrow a +// Template to exactly one Trim. A trim matches when every selector present +// matches. +type TrimSelectors struct { + ManufacturerCode []string `json:"manufacturerCode,omitempty"` + StyleName []string `json:"styleName,omitempty"` + VINPattern string `json:"vinPattern,omitempty"` +} diff --git a/internal/core/models/vin_decoding_models.go b/internal/core/models/vin_decoding_models.go index e0e03b82..3e6910b6 100644 --- a/internal/core/models/vin_decoding_models.go +++ b/internal/core/models/vin_decoding_models.go @@ -35,6 +35,13 @@ type VINDecodingInfoData struct { MetaData null.JSON Raw []byte FuelType string + // ManufacturerCode is the OEM-issued trim/style code, when the decode + // provider supplies one. Only drivly does today (DrivlyVINResponse.ManufacturerCode); + // every other provider leaves this empty, the same way they already + // leave StyleName/FuelType empty when they have nothing to report -- + // an empty code just means manufacturerCode-keyed trim selectors can't + // match for that decode, not an error. + ManufacturerCode string } // VINDecodingVendorExtra extra information from decoding process to store for failures @@ -303,6 +310,7 @@ func (v *VincarioInfoResponse) GetMetadata() (null.JSON, error) { "mpg_highway": nil, "mpg_city": nil, "fuel_tank_capacity_gal": nil, + "battery_capacity_kwh": nil, "mpg": nil, } @@ -359,6 +367,7 @@ type DrivlyVINResponse struct { Wheelbase string `json:"wheelbase"` Fuel string `json:"fuel"` FuelTankCapacityGal float64 `json:"fuelTankCapacityGal"` + BatteryCapacityKwh float64 `json:"batteryCapacityKwh"` Mpg int `json:"mpg"` MpgCity int `json:"mpgCity"` MpgHighway int `json:"mpgHighway"` diff --git a/internal/core/queries/decode_vin.go b/internal/core/queries/decode_vin.go index 7546ede6..36440ce5 100644 --- a/internal/core/queries/decode_vin.go +++ b/internal/core/queries/decode_vin.go @@ -10,6 +10,7 @@ import ( "github.com/DIMO-Network/shared/pkg/logfields" + "github.com/tidwall/gjson" "github.com/tidwall/sjson" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/metrics" @@ -33,6 +34,11 @@ import ( "github.com/segmentio/ksuid" ) +// failedDecodeTTL is how long a recorded decode failure suppresses a retry for +// the same VIN. See the gate in Handle for why this is bounded rather than +// permanent. +const failedDecodeTTL = 14 * 24 * time.Hour + type DecodeVINQueryHandler struct { dbs func() *db.ReaderWriter vinDecodingService services.VINDecodingService @@ -40,7 +46,7 @@ type DecodeVINQueryHandler struct { vinRepository repositories.VINRepository fuelAPIService gateways.FuelAPIService powerTrainTypeService services.PowerTrainTypeService - deviceDefinitionOnChainService gateways.DeviceDefinitionOnChainService + deviceDefinitionCatalogService gateways.DeviceDefinitionCatalogService identity gateways.IdentityAPI } @@ -58,7 +64,7 @@ func NewDecodeVINQueryHandler(dbs func() *db.ReaderWriter, vinDecodingService se logger *zerolog.Logger, fuelAPIService gateways.FuelAPIService, powerTrainTypeService services.PowerTrainTypeService, - deviceDefinitionOnChainService gateways.DeviceDefinitionOnChainService, + deviceDefinitionCatalogService gateways.DeviceDefinitionCatalogService, identity gateways.IdentityAPI) DecodeVINQueryHandler { return DecodeVINQueryHandler{ dbs: dbs, @@ -67,7 +73,7 @@ func NewDecodeVINQueryHandler(dbs func() *db.ReaderWriter, vinDecodingService se vinRepository: vinRepository, fuelAPIService: fuelAPIService, powerTrainTypeService: powerTrainTypeService, - deviceDefinitionOnChainService: deviceDefinitionOnChainService, + deviceDefinitionCatalogService: deviceDefinitionCatalogService, identity: identity, } } @@ -106,25 +112,40 @@ func (dc DecodeVINQueryHandler) Handle(ctx context.Context, query *DecodeVINQuer ) metrics.Success.With(prometheus.Labels{"method": VinRequests}).Inc() - txVinNumbers, err := dc.dbs().Writer.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable}) + // The transaction opens and closes inside this call. Everything below it + // is slow -- hydrateResponseFromVinNumber alone makes a catalog request + // and a reader query -- and none of it may run while a writer connection + // and a serializable snapshot are held. + vinDecodeNumber, err := dc.readCachedVinNumber(ctx, vinObj.String()) if err != nil { - return nil, errors.Wrap(err, "error when beginning transaction") - } - defer txVinNumbers.Rollback() //nolint - vinDecodeNumber, err := models.VinNumbers( - models.VinNumberWhere.Vin.EQ(vinObj.String())). - One(ctx, txVinNumbers) - if err != nil && !errors.Is(err, sql.ErrNoRows) { metrics.InternalError.With(prometheus.Labels{"method": VinErrors}).Inc() - return nil, errors.Wrap(err, "error when querying for existing VIN number") + return nil, err } // if database vin_number match found, just return it here - if r := dc.hydrateResponseFromVinNumber(vinDecodeNumber); r != nil { - metrics.Success.With(prometheus.Labels{"method": VinExists}).Inc() - return r, nil + cached, errCached := dc.hydrateResponseFromVinNumber(ctx, vinDecodeNumber) + if errCached != nil { + metrics.InternalError.With(prometheus.Labels{"method": VinErrors}).Inc() + return nil, errCached } - // check if vin has failed in the past, and if it has just fail now - vinAlreadyFailed, _ := models.FailedVinDecodes(models.FailedVinDecodeWhere.Vin.EQ(vinObj.String())).Exists(ctx, dc.dbs().Writer) + if cached != nil { + metrics.Success.With(prometheus.Labels{"method": VinExists}).Inc() + return cached, nil + } + // Check whether this VIN failed recently, and if so fail fast rather than + // paying for the whole vendor fan-out again. + // + // The window matters. A row here means every vendor we tried had nothing for + // this VIN, which is worth remembering for a while: the fan-out is slow and + // billed per call. It is not worth remembering forever. Decoding coverage + // only ever grows -- a new provider, a new country branch, a fixed + // model-name extractor -- and an unbounded gate converts every historical + // miss into a permanent one that no amount of decoder improvement can + // recover, only a manual DELETE. Ageing the row out means each improvement + // picks up the backlog on its own. + vinAlreadyFailed, _ := models.FailedVinDecodes( + models.FailedVinDecodeWhere.Vin.EQ(vinObj.String()), + models.FailedVinDecodeWhere.CreatedAt.GT(time.Now().Add(-failedDecodeTTL)), + ).Exists(ctx, dc.dbs().Writer) if vinAlreadyFailed { return nil, fmt.Errorf("vin %s failed decoding already", vinObj.String()) } @@ -155,13 +176,23 @@ func (dc DecodeVINQueryHandler) Handle(ctx context.Context, query *DecodeVINQuer if vinInfo == nil || vinInfo.Model == "" { vinInfo, vinExtra, err = dc.vinDecodingService.GetVIN(ctx, vinObj.String(), coremodels.AllProviders, query.Country) // this will try drivly first unless of japan } + // GetVIN overwrites the initialiser above, and reports no vendor extra at + // all on the paths that fail before any vendor is tried: the invalid-VIN + // guard, and the 0SC test-VIN branch, which now reads a template from the + // catalog and hands back that read's error. The failure branch below reads + // six fields off this pointer, so a nil here panicked the decode instead of + // recording the failure -- and a decode that records nothing repeats the + // whole vendor fan-out, and the same panic, on every retry forever. + if vinExtra == nil { + vinExtra = &coremodels.VINDecodingVendorExtra{} + } // if no luck decoding VIN, try buildingVinInfo from known data passed in, typically smartcar or software connections if err != nil { if len(query.KnownModel) > 0 && query.KnownYear > 0 { // note if this is successful, err gets set to nil // todo: the knownModel should correspond with the Make - vinInfo, err = dc.vinInfoFromKnown(vinObj, query.KnownModel, query.KnownYear) + vinInfo, err = dc.vinInfoFromKnown(ctx, vinObj, query.KnownModel, query.KnownYear) } } @@ -187,7 +218,27 @@ func (dc DecodeVINQueryHandler) Handle(ctx context.Context, query *DecodeVINQuer CountryCode: null.StringFrom(query.Country), ManufacturerName: null.StringFrom(resp.Manufacturer), } - errFailedVin := failedVinDecode.Insert(ctx, dc.dbs().Writer, boil.Infer()) + // Upsert, not Insert: vin is the primary key, so once a row has aged past + // failedDecodeTTL and the retry fails again, an Insert collides and the + // row keeps its original created_at. That would leave the VIN + // permanently past the window -- re-running the full vendor fan-out on + // every single request -- which is the opposite of what the gate is for. + // Writing created_at forward restarts the window. + failedVinDecode.CreatedAt = time.Now() + errFailedVin := failedVinDecode.Upsert(ctx, dc.dbs().Writer, true, + []string{models.FailedVinDecodeColumns.Vin}, + boil.Whitelist( + models.FailedVinDecodeColumns.VendorsTried, + models.FailedVinDecodeColumns.VincarioData, + models.FailedVinDecodeColumns.DrivlyData, + models.FailedVinDecodeColumns.AutoisoData, + models.FailedVinDecodeColumns.DatgroupData, + models.FailedVinDecodeColumns.Vin17Data, + models.FailedVinDecodeColumns.CountryCode, + models.FailedVinDecodeColumns.ManufacturerName, + models.FailedVinDecodeColumns.CreatedAt, + ), + boil.Infer()) if errFailedVin != nil { localLog.Err(errFailedVin).Msgf("failed to save failed vin decode to database") } @@ -207,17 +258,39 @@ func (dc DecodeVINQueryHandler) Handle(ctx context.Context, query *DecodeVINQuer resp.Year = vinInfo.Year resp.Model = vinInfo.Model - modelSlug := stringutils.SlugString(vinInfo.Model) - tid := common.DeviceDefinitionSlug(stringutils.SlugString(vinInfo.Make), modelSlug, int16(vinInfo.Year)) + tid, errID := definitionIDForDecode(vinInfo.Make, vinInfo.Model, int16(vinInfo.Year)) + if errID != nil { + // Nothing below this can succeed: the catalog cannot hold a template + // at this id, so the read 404s and the create 422s -- identically, on + // every retry, for every VIN of this model-year. Stop here, with the + // same answer the low-confidence gate gives, so the client falls back + // to the manual make/model/year picker instead of being told the + // service is broken. + metrics.InternalError.With(prometheus.Labels{"method": VinErrors}).Inc() + localLog.Warn().Err(errID).Str("decode_source", string(vinInfo.Source)). + Msg("decoded model yields an id definitions-worker can never accept; returning not found so the client opens the manual picker") + return nil, errID + } resp.DefinitionId = tid - tblDef, _, errTbl := dc.deviceDefinitionOnChainService.GetDefinitionByID(ctx, tid) + tblDef, _, errTbl := dc.deviceDefinitionCatalogService.GetTemplateByID(ctx, tid) + if errTbl != nil && !errors.Is(errTbl, gateways.ErrTemplateNotFound) { + // A catalog outage (5xx, timeout, decode failure) is not the same as + // the definition not existing. Falling through here would read + // tblDef as nil and run Create() below -- writing a duplicate + // definition for a vehicle that may already exist, on the VIN-decode + // hot path, at decode volume, during the worst possible moment for + // it. Abort the decode instead of continuing with a nil template. + metrics.InternalError.With(prometheus.Labels{"method": VinErrors}).Inc() + return nil, errors.Wrapf(errTbl, "failed to get definition from catalog for vinObj: %s, id: %s", vinObj.String(), tid) + } if errTbl != nil { - dc.logger.Warn().Err(errTbl).Msgf("failed to get definition from tableland for vinObj: %s, id: %s", vinObj.String(), tid) + // Genuinely not found (ErrTemplateNotFound): fall through and create it below. + dc.logger.Warn().Err(errTbl).Msgf("failed to get definition from catalog for vinObj: %s, id: %s", vinObj.String(), tid) } else if tblDef == nil { - dc.logger.Warn().Msgf("failed to get definition from tableland for vinObj: %s, id: %s", vinObj.String(), tid) + dc.logger.Warn().Msgf("failed to get definition from catalog for vinObj: %s, id: %s", vinObj.String(), tid) } else { - dc.logger.Info().Str(logfields.VIN, vinObj.String()).Msgf("found definition from tableland %s: %+v", tid, tblDef) + dc.logger.Info().Str(logfields.VIN, vinObj.String()).Msgf("found definition from catalog %s: %+v", tid, tblDef) } // add images if we don't have any for this definition_id @@ -236,7 +309,13 @@ func (dc DecodeVINQueryHandler) Handle(ctx context.Context, query *DecodeVINQuer } } - // figure out powertrain + // figure out powertrain for the style write further down. This is the + // old heuristic derivation, kept alive because processDeviceStyle stamps + // its result onto device_styles -- the table the extraction pipeline + // reads to build templates in the first place. Changing what gets + // written there is a separate decision; pt is passed to + // processDeviceStyle explicitly below so this stays true regardless of + // what resp.Powertrain ends up holding for the response. pt := dc.powerTrainTypeService.ResolvePowerTrainFromVinInfo(vinInfo.StyleName, vinInfo.FuelType) if pt == "" { // try a different way @@ -246,16 +325,31 @@ func (dc DecodeVINQueryHandler) Handle(ctx context.Context, query *DecodeVINQuer resp.Powertrain = pt } - // if dd not found in tableland, we want to create it - if tblDef != nil { - resp.DefinitionId = tblDef.ID - } else { + // Not in the catalog yet. A low-confidence decoder is not trusted to name a + // new template: the Japanese chassis decoders have returned body-style codes + // such as "4D" as the model, which became garbage definitions like + // toyota_4d_2017. Answer not found instead, so the client falls back to the + // manual make/model/year picker. + if tblDef == nil && isLowConfidenceSource(vinInfo.Source) { + metrics.InternalError.With(prometheus.Labels{"method": VinErrors}).Inc() + localLog.Warn().Str("decode_source", string(vinInfo.Source)).Msg("low-confidence decode and catalog miss; returning not found so the client opens the manual picker") + return nil, &exceptions.NotFoundError{Err: fmt.Errorf("device definition %s is not in the catalog and decode source %s is low-confidence; manual selection required", tid, vinInfo.Source)} + } + + // Every other source creates it. Create is create-only: if another writer + // stored the template after the read above, the decode continues with their + // template instead of overwriting it. + if tblDef == nil { // if any images were added above, they will be in the database latestImages, _ := models.Images(models.ImageWhere.DefinitionID.EQ(resp.DefinitionId)).All(ctx, dc.dbs().Reader) // todo load up some metadata from what was decoded. Powertrain too md := resolveMetadataFromInfo(resp.Powertrain, vinInfo) - trx, err := dc.deviceDefinitionOnChainService.Create(ctx, resp.Manufacturer, coremodels.DeviceDefinitionTablelandModel{ + // The id comes back in DefinitionId; NewTrxHash stays empty because + // definitions are no longer written on-chain and there is no + // transaction. Putting the slug here would hand a "0x..." consumer a + // value that is not a hash. + tblDef, err = createOrAdoptTemplate(ctx, dc.deviceDefinitionCatalogService, resp.Manufacturer, coremodels.DeviceDefinitionTablelandModel{ ID: tid, KSUID: ksuid.New().String(), Model: resp.Model, @@ -266,9 +360,62 @@ func (dc DecodeVINQueryHandler) Handle(ctx context.Context, query *DecodeVINQuer }) if err != nil { metrics.InternalError.With(prometheus.Labels{"method": VinErrors}).Inc() - return nil, errors.Wrap(err, "error creating new device definition on-chain from decoded vinObj") + return nil, errors.Wrap(err, "error creating new device definition from decoded vinObj") + } + } + + if tblDef != nil { + resp.DefinitionId = tblDef.ID + + // The model is the template's, not the provider's. resp.Model still + // holds vinInfo.Model here, which is whatever casing and spelling the + // decoder handed back ("LAND CRUISER PRADO", "CROWN"), while every + // cached decode of the same VIN answers tblDef.Model ("Land Cruiser + // Prado"). Leaving that in place means the first decode of a VIN and + // all of its repeats disagree about the model -- the same divergence + // hydrateResponseFromVinNumber was fixed for on the other side. It + // matters most on the adopt path, where the template already existed + // under a different spelling than this decoder produced. + resp.Model = tblDef.Model + + // Narrow the template to the trim this VIN decoded to. ManufacturerCode + // only ever arrives via drivly (VINDecodingInfoData.ManufacturerCode, + // populated in vin_decoding_service.go's buildFromDrivly from + // DrivlyVINResponse.ManufacturerCode); every other provider leaves it + // empty, so a manufacturerCode-keyed selector simply can't match for + // those decodes -- not an error, just a signal that isn't there. + resolved := services.MatchTrim(tblDef, services.MatchSignals{ + ManufacturerCode: vinInfo.ManufacturerCode, + StyleName: vinInfo.StyleName, + VIN: vinObj.String(), + }) + resp.Trim = resolved.Trim + resp.TemplateVersion = int32(resolved.TemplateVersion) + resp.MatchQuality = string(resolved.Quality) + resp.MatchCandidates = resolved.Candidates + // MatchBy and HardwareTemplateId are resolved by MatchTrim and were + // previously dropped here. match.by is how a consumer -- and our own + // dashboards -- can tell whether trim matching is firing on + // manufacturerCode or on styleName, and hardwareTemplateId is the + // template-default-with-trim-override resolution the contract + // requires be settled here "so callers never reimplement the + // fallback". Computing both and emitting neither left the only + // evidence of that work inside the matcher's own unit tests. + resp.MatchBy = resolved.MatchedBy + resp.HardwareTemplateId = resolved.HardwareTemplateID + + observeTrimMatch(resolved, resp.Source) + + // The response's powertrain comes from the resolved template/trim + // attributes now, not from the pt heuristic above -- that heuristic + // is what produced the ICE/hybrid-attributes mismatch this migration + // exists to fix. If the template carries no powertrain_type at all + // (template or matched trim), the response reports none rather than + // falling back to a guess. + resp.Powertrain = "" + if v, ok := resolved.Attributes[common.PowerTrainType].(string); ok { + resp.Powertrain = v } - resp.NewTrxHash = *trx } // match style - only process style if name is longer than 1 @@ -276,7 +423,10 @@ func (dc DecodeVINQueryHandler) Handle(ctx context.Context, query *DecodeVINQuer localLog.Warn().Msgf("decoded style name too short: %s must have a minimum of 2 characters.", vinInfo.StyleName) } else { var styleErr error - resp.DeviceStyleId, styleErr = dc.processDeviceStyle(ctx, vinInfo, tid, resp.Powertrain) + // pt, not resp.Powertrain: processDeviceStyle writes to device_styles, + // the extraction pipeline's input, and that write path is unchanged + // by this migration -- see the comment on pt's declaration above. + resp.DeviceStyleId, styleErr = dc.processDeviceStyle(ctx, vinInfo, tid, pt) if styleErr != nil { dc.logger.Error().Err(styleErr).Msgf("error processing device style for vinObj: %s. continuing", vinObj.String()) } @@ -290,6 +440,13 @@ func (dc DecodeVINQueryHandler) Handle(ctx context.Context, query *DecodeVINQuer localLog.Info().Str("device_definition_id", resp.DefinitionId). Str("style_id", resp.DeviceStyleId). + // How the trim resolved, on the line that already records a + // successful decode: without these, "how often does a decode fail to + // narrow, and on which provider" is unanswerable from logs. + Str("match_quality", resp.MatchQuality). + Str("trim", resp.Trim). + Strs("match_by", resp.MatchBy). + Str("manufacturer_code", vinInfo.ManufacturerCode). Str("wmi", wmi). Str("vds", vinObj.VDS()). Str("vis", vinObj.VIS()). @@ -312,31 +469,131 @@ func resolveMetadataFromInfo(powertrain string, _ *coremodels.VINDecodingInfoDat return &md } -// hydrateResponseFromVinNumber pass in a vin_number database object and converts to vin decode response -func (dc DecodeVINQueryHandler) hydrateResponseFromVinNumber(vn *models.VinNumber) *p_grpc.DecodeVinResponse { - if vn == nil { - return nil +// readCachedVinNumber reads the vin_numbers row for a VIN, or nil when this +// VIN has not been decoded before. +// +// The transaction holds nothing but this one read, and it is closed before the +// function returns -- on every path, including a failed query and a failed +// begin. Handle used to open it and keep it open across +// hydrateResponseFromVinNumber, which was pure in-memory when that was +// written. It now issues a catalog GET through a client with a 30 second +// timeout and a device_styles query against the reader, and returns early on a +// cache hit, so the path the code itself calls "the one most decodes take" +// held a writer connection and a SERIALIZABLE snapshot across a full CDN round +// trip -- and took a reader connection while holding it. A two second catalog +// stall pinned every writer connection for two seconds per decode; a thirty +// second stall exhausted the pool while unrelated writes queued behind it. +// +// The isolation level is unchanged: what this row is read at is a separate +// decision from how long the read is held. +func (dc DecodeVINQueryHandler) readCachedVinNumber(ctx context.Context, vinStr string) (*models.VinNumber, error) { + tx, err := dc.dbs().Writer.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable}) + if err != nil { + return nil, errors.Wrap(err, "error when beginning transaction") } - // call on-chain svc to get the DD and pull out the powertrain - powertrain := "" // this is what we're trying to resolve in part - trx := "" - tblDef, manufID, err := dc.deviceDefinitionOnChainService.GetDefinitionByID(context.Background(), vn.DefinitionID) - if err == nil && tblDef != nil { - if tblDef.Metadata != nil { - for _, attribute := range tblDef.Metadata.DeviceAttributes { - if attribute.Name == common.PowerTrainType { - powertrain = attribute.Value - break - } - } + // Nothing is written here, so Rollback is how this transaction ends, and + // deferring it closes the error paths too rather than only the happy one. + defer tx.Rollback() //nolint:errcheck + vn, err := models.VinNumbers(models.VinNumberWhere.Vin.EQ(vinStr)).One(ctx, tx) + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } + if err != nil { + return nil, errors.Wrap(err, "error when querying for existing VIN number") + } + return vn, nil +} + +// definitionIDForDecode builds the template id for a decoded make/model/year, +// and refuses one definitions-worker can never hold. +// +// common.DeviceDefinitionSlug repairs an id by dropping characters outside the +// worker's class, and does not re-check what it produced. A model written in a +// script with no character in that class -- ハイエース, Нива, reachable through +// vinInfoFromKnown's KnownModel, whose source is not low-confidence -- comes +// back as toyota__2020, whose empty middle segment ID_RE refuses. Writing that +// id would 422 the create and fail every retry of every VIN of that +// model-year, so the failure belongs here, before the id is used for anything. +// +// The error is *exceptions.NotFoundError, the same type the low-confidence +// gate returns: the remedy is the same one, a manual make/model/year pick, and +// both the HTTP and gRPC layers already translate it (404, codes.NotFound) +// rather than reporting the decoder as broken. It wraps +// common.ErrUnmintableDefinitionID so a caller can tell this apart from a +// vehicle that merely has no template yet. +func definitionIDForDecode(makeName, modelName string, year int16) (string, error) { + id, err := common.DeviceDefinitionSlug(stringutils.SlugString(makeName), stringutils.SlugString(modelName), year) + if err != nil { + return "", &exceptions.NotFoundError{ + Err: fmt.Errorf("no device definition id can be built for %d %s %s: %w", year, makeName, modelName, err), } - if powertrain == "" { - makeName, _ := dc.deviceDefinitionOnChainService.GetManufacturerNameByID(context.Background(), manufID) - powertrain, _ = dc.powerTrainTypeService.ResolvePowerTrainType(stringutils.SlugString(makeName), stringutils.SlugString(tblDef.Model), null.JSON{}, null.JSON{}) + } + return id, nil +} + +// createOrAdoptTemplate creates the template for the first decode of a +// make/model/year and always returns the stored template, whoever wrote it. +// +// Both outcomes have to hand one back. A decode that returned nothing on the +// path where its own create landed skipped trim matching entirely: the first +// decode of a definition answered trim "", template_version 0 and +// match_quality "", while the next decode of the same VIN read the stored Base +// trim and answered "Base" with quality "exact". Two calls a second apart +// disagreeing about one VIN is the defect hydrateResponseFromVinNumber's doc +// comment forbids, and the trim-match counter under-reported every new +// definition on top of it. Create answers with the document the worker stored, +// so this costs no extra request. +// +// Create is create-only. When another writer -- a Console curator saving trims, +// or a concurrent first decode -- stored the template between the decode's +// catalog read and this write, Create returns ErrTemplateExists instead of +// replacing their version with a single Base trim. That is success by someone +// else: their template is read back with a cache-busting read, since the CDN +// may still be serving the 404 the decode just saw, and returned so the decode +// narrows it like any template it found. +func createOrAdoptTemplate(ctx context.Context, catalog gateways.DeviceDefinitionCatalogService, manufacturer string, dd coremodels.DeviceDefinitionTablelandModel) (*coremodels.Template, error) { + created, err := catalog.Create(ctx, manufacturer, dd) + switch { + case err == nil && created != nil: + return created, nil + case err == nil: + // The write landed but its response was not readable as this + // template. Rare, and not a reason to answer with no match data: + // read the document back instead. + stored, _, errRead := catalog.GetTemplateByIDFresh(ctx, dd.ID) + if errRead != nil { + return nil, errors.Wrapf(errRead, "template %s was created but could not be read back", dd.ID) } - } else { - // this is not good, somehow it got decoded in past without it being created on tableland - dc.logger.Warn().Msgf("vin decoded for unexistent device definition: %s, vin: %s", vn.DefinitionID, vn.Vin) + return stored, nil + case !errors.Is(err, gateways.ErrTemplateExists): + return nil, err + } + stored, _, err := catalog.GetTemplateByIDFresh(ctx, dd.ID) + if err != nil { + return nil, errors.Wrapf(err, "template %s was created by another writer but could not be read back", dd.ID) + } + return stored, nil +} + +// hydrateResponseFromVinNumber pass in a vin_number database object and converts to vin decode response. +// +// This is the cached path, and it is the one most decodes take: every VIN that +// has been decoded once is answered from vin_numbers thereafter. It therefore +// has to give the SAME answer a fresh decode of the same VIN would -- same +// trim, same match quality, same powertrain. Leaving the match fields unset +// here would emit an undocumented fourth match_quality ("") on the majority of +// production traffic, and sourcing powertrain from template-level attributes +// alone would silently miss it on exactly the multi-trim templates this +// migration exists for (a template only carries powertrain_type at the top +// level when every trim agrees on it), falling through to a make/model +// heuristic -- the blended answer we are replacing. +// +// It returns an error only when the catalog could not be read at all. A +// template that is genuinely absent is answered, as before, with the fields +// the matcher never got to compute left empty. +func (dc DecodeVINQueryHandler) hydrateResponseFromVinNumber(ctx context.Context, vn *models.VinNumber) (*p_grpc.DecodeVinResponse, error) { + if vn == nil { + return nil, nil } resp := &p_grpc.DecodeVinResponse{ @@ -345,14 +602,110 @@ func (dc DecodeVINQueryHandler) hydrateResponseFromVinNumber(vn *models.VinNumbe DeviceStyleId: vn.StyleID.String, Source: vn.DecodeProvider.String, DefinitionId: vn.DefinitionID, - Powertrain: powertrain, - NewTrxHash: trx, } - return resp + tblDef, _, err := dc.deviceDefinitionCatalogService.GetTemplateByID(ctx, vn.DefinitionID) + if err != nil && !errors.Is(err, gateways.ErrTemplateNotFound) { + // A catalog outage (5xx, timeout, decode failure) is not the same as + // the template not existing, and this is the path most decodes take. + // Answering OK with empty trim, match quality, candidates, powertrain + // and hardware template id would make an outage indistinguishable + // from a genuinely template-less definition -- and would emit the + // undocumented fourth match_quality ("") on the majority of + // production traffic. The live path checks the same sentinel the same + // way; fail the decode instead. + return nil, errors.Wrapf(err, "failed to read template %s from catalog for cached decode of vin %s", vn.DefinitionID, vn.Vin) + } + if err != nil || tblDef == nil { + // Genuinely not found (ErrTemplateNotFound): this is not good, somehow + // it got decoded in past without a template existing for it. + // MatchQuality stays empty rather than "model-only": the matcher did + // not run at all, and claiming a quality it never computed would be + // the kind of authoritative-looking wrong answer this migration exists + // to stop. + dc.logger.Warn().Err(err).Msgf("vin decoded for unexistent device definition: %s, vin: %s", vn.DefinitionID, vn.Vin) + return resp, nil + } + + // The model is the template's, not the vin_numbers row's: vin_numbers + // stores the manufacturer name and the definition id but never the model, + // and a response without it answered "" for every decode after the first + // while a fresh decode of the same VIN answered the model. + resp.Model = tblDef.Model + + resolved := services.MatchTrim(tblDef, dc.matchSignalsFromVinNumber(ctx, vn)) + resp.Trim = resolved.Trim + resp.TemplateVersion = int32(resolved.TemplateVersion) + resp.MatchQuality = string(resolved.Quality) + resp.MatchCandidates = resolved.Candidates + resp.MatchBy = resolved.MatchedBy + resp.HardwareTemplateId = resolved.HardwareTemplateID + // No heuristic fallback, deliberately: the live path in Handle reports no + // powertrain when the resolved attributes carry none, and these two paths + // answering the same VIN differently is the defect this function is + // fixing, not a behaviour worth keeping on one side of it. + if v, ok := resolved.Attributes[common.PowerTrainType].(string); ok { + resp.Powertrain = v + } + + observeTrimMatch(resolved, resp.Source) + + return resp, nil +} + +// matchSignalsFromVinNumber rebuilds the signals a fresh decode of this VIN +// would have produced, out of what saveVinDecodeNumber persisted. Every source +// here is the same value the live path fed the matcher: drivly_data is the +// marshalled DrivlyVINResponse vinInfo.ManufacturerCode was read from, and the +// style row's name is the vinInfo.StyleName processDeviceStyle stored. A +// signal that was never persisted stays empty, which the matcher treats as +// "not available" rather than as a non-match. +func (dc DecodeVINQueryHandler) matchSignalsFromVinNumber(ctx context.Context, vn *models.VinNumber) services.MatchSignals { + sig := services.MatchSignals{VIN: vn.Vin} + + if vn.DrivlyData.Valid { + sig.ManufacturerCode = gjson.GetBytes(vn.DrivlyData.JSON, "manufacturerCode").String() + } + + if vn.StyleID.Valid && vn.StyleID.String != "" { + style, err := models.DeviceStyles(models.DeviceStyleWhere.ID.EQ(vn.StyleID.String)).One(ctx, dc.dbs().Reader) + if err != nil { + // Best effort: a missing style row costs us one selector, which + // shows up as a lower match quality rather than as a wrong trim. + dc.logger.Debug().Err(err).Msgf("could not load style %s for cached decode of vin %s", vn.StyleID.String, vn.Vin) + } else { + sig.StyleName = style.Name + } + } + + return sig +} + +// observeTrimMatch records how a decode resolved, so the rate of exact vs +// ambiguous vs model-only is answerable from production rather than from +// inspection. The plan's riskiest assumption is that manufacturerCode reaches +// a decode as a usable signal at all -- it only ever arrives via drivly -- and +// this counter, broken down by decode source, is what makes that measurable +// instead of merely asserted. +func observeTrimMatch(resolved services.Resolved, source string) { + if source == "" { + source = "unknown" + } + metrics.TrimMatchQuality.With(prometheus.Labels{ + "quality": string(resolved.Quality), + "source": source, + }).Inc() } // processDeviceStyle saves new styles if needed to db and returns the style database ID +// +// Every read here is checked for a failure that is not no-rows. sqlboiler's +// One() answers such a failure with a nil row and a wrapped error, so a reader +// that is merely unavailable for a moment -- a pool blip, a reset connection, +// the caller's context deadline expiring right after the catalog round trip +// above -- used to fall through both no-rows branches and nil-dereference the +// style on the way out, panicking the decode hot path. Handle already treats +// an error from here as "continue without a style id"; it just never got one. func (dc DecodeVINQueryHandler) processDeviceStyle(ctx context.Context, vinInfo *coremodels.VINDecodingInfoData, definitionID, powertrain string) (string, error) { externalStyleID := stringutils.SlugString(vinInfo.StyleName) @@ -362,6 +715,9 @@ func (dc DecodeVINQueryHandler) processDeviceStyle(ctx context.Context, vinInfo models.DeviceStyleWhere.Source.EQ(string(vinInfo.Source)), models.DeviceStyleWhere.ExternalStyleID.EQ(externalStyleID), ).One(ctx, dc.dbs().Reader) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return "", errors.Wrapf(err, "error querying device_styles for definition %s by external style id %s", definitionID, externalStyleID) + } if errors.Is(err, sql.ErrNoRows) { // Step 2: If not found, try searching by name @@ -369,6 +725,9 @@ func (dc DecodeVINQueryHandler) processDeviceStyle(ctx context.Context, vinInfo models.DeviceStyleWhere.DefinitionID.EQ(definitionID), models.DeviceStyleWhere.Name.EQ(vinInfo.StyleName), ).One(ctx, dc.dbs().Reader) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return "", errors.Wrapf(err, "error querying device_styles for definition %s by name %s", definitionID, vinInfo.StyleName) + } } if errors.Is(err, sql.ErrNoRows) { @@ -454,31 +813,16 @@ func (dc DecodeVINQueryHandler) saveVinDecodeNumber(ctx context.Context, vinObj } // vinInfoFromKnown builds a vininfo object based on one passed in with Make from vin WMI, and passed in model and year set -func (dc DecodeVINQueryHandler) vinInfoFromKnown(vin vin.VIN, knownModel string, knownYear int32) (*coremodels.VINDecodingInfoData, error) { +func (dc DecodeVINQueryHandler) vinInfoFromKnown(ctx context.Context, vin vin.VIN, knownModel string, knownYear int32) (*coremodels.VINDecodingInfoData, error) { vinInfo := &coremodels.VINDecodingInfoData{} vinInfo.VIN = vin.String() - wmis, err := models.Wmis(models.WmiWhere.Wmi.EQ(vin.Wmi())).All(context.Background(), dc.dbs().Reader) + wmis, err := models.Wmis(models.WmiWhere.Wmi.EQ(vin.Wmi())).All(ctx, dc.dbs().Reader) if err != nil { - return nil, errors.Wrap(err, "vinInfoFromKnown: unknown WMI "+vin.Wmi()) + return nil, errors.Wrap(err, "vinInfoFromKnown: failed to read wmis for "+vin.Wmi()) } - if len(wmis) > 1 { - // see if we can find an existing device definition for this WMI - makeNamesForError := "" - for _, wmi := range wmis { - makeNamesForError += wmi.ManufacturerName + ", " - definitionID := common.DeviceDefinitionSlug(stringutils.SlugString(wmi.ManufacturerName), stringutils.SlugString(knownModel), int16(knownYear)) - deviceDefinitionTablelandModel, _, err := dc.deviceDefinitionOnChainService.GetDefinitionByID(context.Background(), definitionID) - if err == nil && deviceDefinitionTablelandModel != nil { - vinInfo.Make = wmi.ManufacturerName - break - } - } - // if make is blank means no matching DD's found. We don't have a good way to determine the right Make / OEM - if vinInfo.Make == "" { - return nil, fmt.Errorf("vinInfoFromKnown: unable to determine the right OEM between %sfor WMI %s", makeNamesForError, vin.Wmi()) - } - } else { - vinInfo.Make = wmis[0].ManufacturerName + vinInfo.Make, err = dc.makeFromWMIRows(ctx, vin.Wmi(), wmis, knownModel, knownYear) + if err != nil { + return nil, err } vinInfo.Year = knownYear vinInfo.Model = knownModel @@ -491,6 +835,42 @@ func (dc DecodeVINQueryHandler) vinInfoFromKnown(vin vin.VIN, knownModel string, return vinInfo, nil } +// makeFromWMIRows names the manufacturer for a VIN whose wmis rows have +// already been read. A WMI can be shared by several marques of the same parent +// OEM, in which case the one that already has a template for this model-year +// is the right answer. +func (dc DecodeVINQueryHandler) makeFromWMIRows(ctx context.Context, wmiCode string, wmis models.WmiSlice, knownModel string, knownYear int32) (string, error) { + if len(wmis) == 0 { + // .All() reports an unknown WMI as an empty slice with a nil error -- + // unlike .One(), which returns sql.ErrNoRows -- so this has to be + // checked explicitly. Indexing element zero here panicked the decode + // handler for exactly the VINs this fallback exists to serve. + return "", &exceptions.NotFoundError{Err: fmt.Errorf("vinInfoFromKnown: unknown WMI %s", wmiCode)} + } + if len(wmis) > 1 { + // see if we can find an existing device definition for this WMI + makeNamesForError := "" + for _, wmi := range wmis { + makeNamesForError += wmi.ManufacturerName + ", " + definitionID, errID := common.DeviceDefinitionSlug(stringutils.SlugString(wmi.ManufacturerName), stringutils.SlugString(knownModel), int16(knownYear)) + if errID != nil { + // No template can be stored at an id the worker refuses, so + // this marque cannot be the one with a definition for the + // model-year. Skipping it costs a catalog request that would + // 404 anyway; the loop still reports every marque it weighed. + continue + } + tmpl, _, err := dc.deviceDefinitionCatalogService.GetTemplateByID(ctx, definitionID) + if err == nil && tmpl != nil { + return wmi.ManufacturerName, nil + } + } + // no matching DD's found. We don't have a good way to determine the right Make / OEM + return "", fmt.Errorf("vinInfoFromKnown: unable to determine the right OEM between %sfor WMI %s", makeNamesForError, wmiCode) + } + return wmis[0].ManufacturerName, nil +} + func (dc DecodeVINQueryHandler) associateImagesToDeviceDefinition(ctx context.Context, definitionID, mk, model string, year int, prodID int, prodFormat int) error { img, err := dc.fuelAPIService.FetchDeviceImages(mk, model, year, prodID, prodFormat) @@ -522,3 +902,17 @@ func (dc DecodeVINQueryHandler) associateImagesToDeviceDefinition(ctx context.Co return nil } + +// isLowConfidenceSource returns true for decode providers whose output has historically +// produced bad device definitions (e.g., Japanese chassis decoders returning body-style +// codes as model names). For these sources a decode refuses to create a template on a +// catalog miss and surfaces a NotFoundError so the client can fall back to manual +// make/model/year selection. High-confidence Western providers (Drivly, Vincario, DATGroup, +// Tesla) keep creating the template. +func isLowConfidenceSource(src coremodels.DecodeProviderEnum) bool { + switch src { + case coremodels.Japan17VIN, coremodels.CarVXVIN, coremodels.AutoIsoProvider, coremodels.ElevaKaufmannProvider: + return true + } + return false +} diff --git a/internal/core/queries/decode_vin_create_test.go b/internal/core/queries/decode_vin_create_test.go new file mode 100644 index 00000000..b73613a3 --- /dev/null +++ b/internal/core/queries/decode_vin_create_test.go @@ -0,0 +1,464 @@ +package queries + +import ( + "context" + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "net/url" + "strings" + "sync" + "testing" + + "github.com/DIMO-Network/device-definitions-api/internal/config" + "github.com/DIMO-Network/device-definitions-api/internal/core/common" + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" + "github.com/DIMO-Network/device-definitions-api/internal/core/services" + "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/exceptions" + "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +// The decode's create is only observable at the worker, so these run the real +// catalog gateway against a fake one. DecodeVINQueryHandler's suite needs +// Postgres; createOrAdoptTemplate does not. + +// A curator's template: two trims, at version 2. +const curatedTemplateJSON = `{ + "id": "toyota_camry_2026", + "deviceType": "vehicle", + "manufacturer": {"slug": "toyota", "name": "Toyota", "tokenId": 131}, + "model": "Camry", + "year": 2026, + "attributes": {"number_of_doors": 4}, + "trims": [ + {"name": "LE", "selectors": {"styleName": ["LE"]}, "attributes": {"powertrain_type": "ICE"}}, + {"name": "Hybrid LE", "selectors": {"styleName": ["Hybrid LE"]}, "attributes": {"powertrain_type": "HEV"}} + ], + "version": 2 +}` + +var firstDecode = coremodels.DeviceDefinitionTablelandModel{ + ID: "toyota_camry_2026", + Model: "Camry", + Year: 2026, + DeviceType: "vehicle", +} + +// fakeWorker keeps the definitions-worker's write contract: GET /t/ serves +// the stored template or 404, a PUT with If-None-Match: * answers 412 when one +// is stored, and a PUT without it overwrites. +type fakeWorker struct { + stored string + rejectPut int + puts []string // the If-None-Match header each PUT carried + putPaths []string // the path each PUT went to + templateGets int + getPaths []string // the path each template GET went to + getQueries []string // the query string each template GET carried + edgeHits int // template GETs the edge answered without the origin + cdnRequests int + version int +} + +// nextVersion is the version the worker stamps on the document it stores. +func (fw *fakeWorker) nextVersion() int { + fw.version++ + return fw.version +} + +// workerHandler is definitions-worker's contract: GET /t/ serves the +// stored template or 404, a PUT with If-None-Match: * answers 412 when one is +// stored, and a PUT without it overwrites. Routing is on the path alone +// (src/index.ts matches url.pathname), so a query string reaches nothing here +// -- which is what makes a cache-busting parameter safe. +func workerHandler(fw *fakeWorker) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + switch { + case r.Method == http.MethodPost: + // identity-api's GraphQL endpoint. + _, _ = w.Write([]byte(`{"data":{"manufacturer":{"tokenId":131,"name":"Toyota"}}}`)) + case strings.HasPrefix(r.URL.Path, "/schema/"): + _, _ = w.Write([]byte(`{"id":"vehicle","attributes":[]}`)) + case r.Method == http.MethodPut: + fw.puts = append(fw.puts, r.Header.Get("If-None-Match")) + fw.putPaths = append(fw.putPaths, r.URL.Path) + if fw.rejectPut != 0 { + w.WriteHeader(fw.rejectPut) + _, _ = w.Write([]byte(`{"errors":["rejected"]}`)) + return + } + if r.Header.Get("If-None-Match") == "*" && fw.stored != "" { + w.WriteHeader(http.StatusPreconditionFailed) + _, _ = w.Write([]byte(`{"error":"template already exists","expected":null,"actual":2}`)) + return + } + // The worker answers a PUT with the document it stored, version + // stamped. That body is what the decode matches trims against. + body, _ := io.ReadAll(r.Body) + stored, _ := sjson.SetBytes(body, "version", fw.nextVersion()) + fw.stored = string(stored) + _, _ = w.Write(stored) + case r.Method == http.MethodGet && strings.HasPrefix(r.URL.Path, "/t/"): + fw.templateGets++ + fw.getPaths = append(fw.getPaths, r.URL.Path) + fw.getQueries = append(fw.getQueries, r.URL.RawQuery) + if fw.stored == "" { + w.WriteHeader(http.StatusNotFound) + return + } + _, _ = w.Write([]byte(fw.stored)) + default: + w.WriteHeader(http.StatusNotFound) + } + } +} + +// edgeCache is Cloudflare in front of the worker. Template documents are +// served `public, max-age=86400`, and the cache key is the whole URL -- path +// AND query -- so a GET whose exact URL has been answered before is served +// from cache for up to a day, and only a URL the edge has not seen reaches the +// origin at all. +func edgeCache(fw *fakeWorker, origin http.Handler) http.HandlerFunc { + type entry struct { + status int + body string + } + cached := map[string]entry{} + var mu sync.Mutex + return func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet || !strings.HasPrefix(r.URL.Path, "/t/") { + origin.ServeHTTP(w, r) + return + } + key := r.URL.RequestURI() + mu.Lock() + hit, ok := cached[key] + if !ok { + mu.Unlock() + rec := httptest.NewRecorder() + origin.ServeHTTP(rec, r) + hit = entry{status: rec.Code, body: rec.Body.String()} + mu.Lock() + cached[key] = hit + } else { + fw.edgeHits++ + } + mu.Unlock() + w.WriteHeader(hit.status) + _, _ = w.Write([]byte(hit.body)) + } +} + +// newFakeWorker points the catalog and worker settings at two different +// servers, so a request that reached the worker is unambiguous in a test. The +// charts do NOT produce this shape -- see newOneHostFakeWorker, which does. +func newFakeWorker(t *testing.T, fw *fakeWorker) gateways.DeviceDefinitionCatalogService { + t.Helper() + // The CDN still serves the 404 the decode's read saw. + cdn := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + fw.cdnRequests++ + w.WriteHeader(http.StatusNotFound) + })) + t.Cleanup(cdn.Close) + worker := httptest.NewServer(workerHandler(fw)) + t.Cleanup(worker.Close) + return catalogService(t, cdn.URL, worker.URL) +} + +// newOneHostFakeWorker is the configuration the charts actually deploy: +// DEFINITIONS_CATALOG_URL and DEFINITIONS_WORKER_URL are the same hostname in +// both dev and prod (values.yaml, values-prod.yaml), with Cloudflare's cache +// in front of it. There is no second host to read "through the worker" +// instead, so the only thing that can separate a fresh read from a cached one +// is the cache key. +func newOneHostFakeWorker(t *testing.T, fw *fakeWorker) gateways.DeviceDefinitionCatalogService { + t.Helper() + host := httptest.NewServer(edgeCache(fw, workerHandler(fw))) + t.Cleanup(host.Close) + return catalogService(t, host.URL, host.URL) +} + +func catalogService(t *testing.T, catalogURL, workerURL string) gateways.DeviceDefinitionCatalogService { + t.Helper() + identity, err := url.Parse(workerURL) + require.NoError(t, err) + logger := zerolog.Nop() + return gateways.NewDeviceDefinitionCatalogService(&config.Settings{ + DefinitionsCatalogURL: catalogURL, + DefinitionsWorkerURL: workerURL, + DefinitionsWorkerToken: "test-token", + IdentityAPIURL: *identity, + }, &logger) +} + +// A curator saved toyota_camry_2026 with its trims after a first decode of the +// same model-year read 404 and before it created the template. The create used +// to overwrite them with a single Base trim and report success. +func TestCreateOrAdoptTemplateContinuesWithTheTemplateAnotherWriterStored(t *testing.T) { + fw := &fakeWorker{stored: curatedTemplateJSON} + catalog := newFakeWorker(t, fw) + + tmpl, err := createOrAdoptTemplate(context.Background(), catalog, "Toyota", firstDecode) + require.NoError(t, err, "another writer creating the template is success, not a failed decode") + require.NotNil(t, tmpl, "the decode must continue with the stored template") + + assert.Equal(t, []string{"*"}, fw.puts, "one create-only PUT, and no second write") + assert.JSONEq(t, curatedTemplateJSON, fw.stored, "the curated template must not be overwritten") + assert.Equal(t, 1, fw.templateGets, "the stored template is read back with a cache-busting read") + assert.Zero(t, fw.cdnRequests, "the edge may still be serving the 404") + + assert.Equal(t, 2, tmpl.Version) + require.Len(t, tmpl.Trims, 2, "the curated trims, not a single Base trim") + assert.Equal(t, "Hybrid LE", tmpl.Trims[1].Name) +} + +// When this decode's create is the one that lands, it must still answer with +// the template it wrote. Returning nothing skipped the whole match block, so +// the very first decode of a definition answered trim "", template_version 0 +// and match_quality "" -- and the next decode of the same VIN, reading the +// stored Base trim, answered trim "Base" with quality "exact". Two calls a +// second apart disagreeing about one VIN is exactly what the cached path's +// doc comment says must not happen, and the trim-match counter under-reported +// every new definition. +// +// The worker's PUT already answers with the stored document, so there is +// nothing extra to fetch: no read-back, one write. +func TestCreateOrAdoptTemplateReturnsTheTemplateItWrote(t *testing.T) { + fw := &fakeWorker{} + catalog := newFakeWorker(t, fw) + + tmpl, err := createOrAdoptTemplate(context.Background(), catalog, "Toyota", firstDecode) + require.NoError(t, err) + require.NotNil(t, tmpl, "the decode has to narrow the template it just created") + assert.Equal(t, []string{"*"}, fw.puts) + assert.NotEmpty(t, fw.stored) + assert.Zero(t, fw.templateGets, "the PUT's own response is the stored template") + + assert.Equal(t, "toyota_camry_2026", tmpl.ID) + assert.Equal(t, "Camry", tmpl.Model) + assert.Equal(t, 1, tmpl.Version, "the version the worker stamped, not zero") + require.Len(t, tmpl.Trims, 1) + assert.Equal(t, "Base", tmpl.Trims[0].Name) +} + +// The invariant the return value exists for: the first decode of a VIN and +// every decode after it answer the same thing. The created template, run +// through the matcher Handle runs, must resolve exactly as the stored template +// resolves for the cached path -- Base, exact, version 1 -- rather than the +// empty match block a nil template produced. +func TestTheCreatedTemplateResolvesTheWayTheNextDecodeWill(t *testing.T) { + fw := &fakeWorker{} + catalog := newFakeWorker(t, fw) + + created, err := createOrAdoptTemplate(context.Background(), catalog, "Toyota", firstDecode) + require.NoError(t, err) + require.NotNil(t, created) + + // What the next decode of the same VIN reads back out of the catalog. + var stored coremodels.Template + require.NoError(t, json.Unmarshal([]byte(fw.stored), &stored)) + + sig := services.MatchSignals{VIN: "4T1C11AK8NU123456", StyleName: "LE"} + fresh := services.MatchTrim(created, sig) + cached := services.MatchTrim(&stored, sig) + + assert.Equal(t, cached, fresh, "the decode that created the definition must answer what the next one answers") + assert.Equal(t, "Base", fresh.Trim) + assert.Equal(t, services.MatchExact, fresh.Quality) + assert.Equal(t, 1, fresh.TemplateVersion) +} + +// Only a 412 means there is someone else's template to use. Any other refusal +// fails the decode. +func TestCreateOrAdoptTemplateFailsWhenTheWorkerRejectsTheTemplate(t *testing.T) { + fw := &fakeWorker{rejectPut: http.StatusUnprocessableEntity} + catalog := newFakeWorker(t, fw) + + tmpl, err := createOrAdoptTemplate(context.Background(), catalog, "Toyota", firstDecode) + require.Error(t, err) + assert.NotErrorIs(t, err, gateways.ErrTemplateExists) + assert.Nil(t, tmpl) + assert.Zero(t, fw.templateGets) +} + +// The id is repaired and the body is not. definitions-worker checks that the +// body's model and the model segment of the id name the same thing, and it +// runs BOTH sides through the same character-class repair before comparing -- +// so `up!` in the body matches segment `up`. dd-api's half of that contract is +// to keep sending the model as decoded: repairing the model to match the id +// would store "up" as the name of a car called "up!", and "Tribeca NY NJ" as +// the name of the Tribeca (NY/NJ). This pins the pair for both shapes the +// repair is known to produce, so neither side can move alone. +func TestCreateSendsTheDecodedModelAlongsideTheRepairedID(t *testing.T) { + tests := []struct { + make string + model string + year int16 + wantID string + }{ + {make: "Volkswagen", model: "up!", year: 2020, wantID: "volkswagen_up_2020"}, + {make: "Subaru", model: "Tribeca (NY/NJ)", year: 2020, wantID: "subaru_tribeca-ny-nj_2020"}, + } + for _, tt := range tests { + t.Run(tt.wantID, func(t *testing.T) { + fw := &fakeWorker{} + catalog := newFakeWorker(t, fw) + + // Exactly what Handle does with a decoded make/model/year. + id, err := definitionIDForDecode(tt.make, tt.model, tt.year) + require.NoError(t, err) + require.Equal(t, tt.wantID, id, "the id the repair is there to produce") + + _, err = createOrAdoptTemplate(context.Background(), catalog, tt.make, coremodels.DeviceDefinitionTablelandModel{ + ID: id, + Model: tt.model, + Year: int(tt.year), + DeviceType: "vehicle", + }) + require.NoError(t, err) + + require.Len(t, fw.putPaths, 1) + assert.Equal(t, "/t/"+tt.wantID, fw.putPaths[0], "the write goes to the repaired id") + assert.Equal(t, tt.wantID, gjson.Get(fw.stored, "id").String(), "the body's id is the repaired id") + assert.Equal(t, tt.model, gjson.Get(fw.stored, "model").String(), + "the body carries the model as decoded, never the id's repaired segment") + }) + } +} + +// The repair strips every character outside the worker's class, and never +// looks at what it produced. A model with no character in that class at all -- +// a Japanese or Cyrillic name, which reaches a decode through vinInfoFromKnown +// whose source is not low-confidence -- leaves the id's middle segment empty, +// and ID_RE requires at least one character there. Creating it 422s, and so +// does every retry of every VIN of that model-year, forever. Refuse to build +// the id instead, the way the low-confidence gate refuses to name a template. +func TestDefinitionIDForDecodeRefusesAnIDNoTemplateCanExistAt(t *testing.T) { + tests := []struct { + make string + model string + year int16 + }{ + {make: "Toyota", model: "ハイエース", year: 2020}, + {make: "Lada", model: "Нива", year: 2021}, + } + for _, tt := range tests { + t.Run(tt.make+" "+tt.model, func(t *testing.T) { + id, err := definitionIDForDecode(tt.make, tt.model, tt.year) + require.Error(t, err, "an id with an empty segment must never reach a PUT") + assert.Empty(t, id) + + var notFound *exceptions.NotFoundError + require.ErrorAs(t, err, ¬Found, + "the decode surfaces this the way the low-confidence gate does: not found, so the client opens the manual picker") + assert.ErrorIs(t, notFound.Err, common.ErrUnmintableDefinitionID) + }) + } +} + +// The gate must not fire for anything the worker accepts, repaired or not. +func TestDefinitionIDForDecodeBuildsEveryIDTheWorkerAccepts(t *testing.T) { + tests := []struct { + make string + model string + year int16 + wantID string + }{ + {make: "Toyota", model: "Camry", year: 2026, wantID: "toyota_camry_2026"}, + {make: "Volkswagen", model: "ID. Buzz", year: 2024, wantID: "volkswagen_id--buzz_2024"}, + {make: "Dodge", model: "Town & Country", year: 2012, wantID: "dodge_town-&-country_2012"}, + {make: "Kia", model: "Soul !EV!", year: 2020, wantID: "kia_soul-ev_2020"}, + } + for _, tt := range tests { + t.Run(tt.wantID, func(t *testing.T) { + id, err := definitionIDForDecode(tt.make, tt.model, tt.year) + require.NoError(t, err) + assert.Equal(t, tt.wantID, id) + }) + } +} + +// The deployed configuration, end to end. DEFINITIONS_CATALOG_URL and +// DEFINITIONS_WORKER_URL are one hostname, so "read through the worker instead +// of the CDN" bypassed nothing: the read-back built a byte-identical request +// to the read the decode had already made, and Cloudflare answered it from +// cache. Against responses served `public, max-age=86400`, that means the +// read-back was served the very 404 it exists to see past, and the decode +// failed with "created by another writer but could not be read back" for a +// template that plainly exists. +func TestTheFreshReadIsNotServedTheCached404OnOneHost(t *testing.T) { + fw := &fakeWorker{} + catalog := newOneHostFakeWorker(t, fw) + ctx := context.Background() + + // The decode's catalog read: no template yet. The edge now holds that 404 + // for a day. + _, _, err := catalog.GetTemplateByID(ctx, firstDecode.ID) + require.ErrorIs(t, err, gateways.ErrTemplateNotFound) + + // A curator saves the template through the worker a moment later. + fw.stored = curatedTemplateJSON + fw.version = 2 + + // The cached read still answers 404. That is the edge doing its job, and + // it is the reason the read-back cannot be an ordinary read. + _, _, err = catalog.GetTemplateByID(ctx, firstDecode.ID) + require.ErrorIs(t, err, gateways.ErrTemplateNotFound) + require.Positive(t, fw.edgeHits, "the premise: the second identical read never reached the origin") + + tmpl, err := createOrAdoptTemplate(ctx, catalog, "Toyota", firstDecode) + require.NoError(t, err, "the read-back must not be served the 404 the decode already saw") + require.NotNil(t, tmpl) + assert.Equal(t, 2, tmpl.Version) + require.Len(t, tmpl.Trims, 2, "the curator's trims, read past the cache") + assert.Equal(t, "Hybrid LE", tmpl.Trims[1].Name) +} + +// What separates the two reads is the cache key, and nothing else. The path is +// identical because definitions-worker routes on url.pathname alone, so the +// query it never reads costs nothing there and is the whole difference at the +// edge. The cached read must stay cacheable -- it is the hot path -- so only +// the fresh read carries the parameter, and it must differ every time or the +// second fresh read of a day is served the first one's answer. +func TestOnlyTheFreshReadCarriesACacheBuster(t *testing.T) { + fw := &fakeWorker{stored: curatedTemplateJSON} + catalog := newFakeWorker(t, fw) + ctx := context.Background() + + _, _, err := catalog.GetTemplateByIDFresh(ctx, firstDecode.ID) + require.NoError(t, err) + _, _, err = catalog.GetTemplateByIDFresh(ctx, firstDecode.ID) + require.NoError(t, err) + + require.Len(t, fw.getQueries, 2) + assert.NotEmpty(t, fw.getQueries[0], "a fresh read the edge has already seen is not a fresh read") + assert.NotEqual(t, fw.getQueries[0], fw.getQueries[1], "two fresh reads must not share a cache key") + for _, p := range fw.getPaths { + assert.Equal(t, "/t/"+firstDecode.ID+".json", p, "the worker routes on the path; the query must not move it") + } + + // The cached read is the hot path and must keep the CDN's cache key. + fw.getQueries = nil + _, _, err = catalog.GetTemplateByID(ctx, firstDecode.ID) + require.ErrorIs(t, err, gateways.ErrTemplateNotFound, "the two-server fake's CDN always 404s") + assert.Zero(t, fw.cdnRequests-1, "the cached read goes to the CDN") + assert.Empty(t, fw.getQueries, "the cached read never reaches the worker") +} + +// A catalog miss from one of these sources answers not found instead of +// creating a template (#312). Pinning the set keeps a new provider from being +// trusted, or an untrusted one from being dropped, without a decision. +func TestIsLowConfidenceSourceGatesOnlyTheUntrustedDecoders(t *testing.T) { + for _, src := range []coremodels.DecodeProviderEnum{coremodels.Japan17VIN, coremodels.CarVXVIN, coremodels.AutoIsoProvider, coremodels.ElevaKaufmannProvider} { + assert.True(t, isLowConfidenceSource(src), "%s", src) + } + for _, src := range []coremodels.DecodeProviderEnum{"drivly", "vincario", "datgroup", "tesla", ""} { + assert.False(t, isLowConfidenceSource(src), "%q", src) + } +} diff --git a/internal/core/queries/decode_vin_failed_test.go b/internal/core/queries/decode_vin_failed_test.go new file mode 100644 index 00000000..07b0c429 --- /dev/null +++ b/internal/core/queries/decode_vin_failed_test.go @@ -0,0 +1,96 @@ +package queries + +import ( + "context" + "database/sql" + "errors" + "testing" + + sqlmock "github.com/DATA-DOG/go-sqlmock" + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" + mock_services "github.com/DIMO-Network/device-definitions-api/internal/core/services/mocks" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +// A decode that fails has to record itself in failed_vin_decodes: that row is +// what stops the next request for the same VIN from paying for the whole +// vendor fan-out again, and it is the only record that the VIN was ever tried. +// +// GetVIN returns (nil, nil, err) on several paths -- the 0SC test-VIN branch +// now reads a template from the catalog and returns its error verbatim, and +// the invalid-VIN guard returns before any vendor is tried -- so the vendor +// extra the failure branch reads can be nil. It used to be read +// unconditionally, so the failure branch panicked, wrote no row, and the same +// VIN failed the same way on every retry forever. +// +// No Postgres: sqlmock answers the reads and records the insert. + +const failedTestVIN = "4T1C11AK8NU123456" + +func failedDecodeHandler(t *testing.T) (DecodeVINQueryHandler, sqlmock.Sqlmock, *mock_services.MockVINDecodingService) { + t.Helper() + dbs, mock := mockDBS(t) + ctrl := gomock.NewController(t) + t.Cleanup(ctrl.Finish) + vinDecoding := mock_services.NewMockVINDecodingService(ctrl) + logger := zerolog.Nop() + return DecodeVINQueryHandler{dbs: dbs, logger: &logger, vinDecodingService: vinDecoding}, mock, vinDecoding +} + +// expectDecodeUpToProviders queues every read Handle makes before it calls the +// decoding service: the cached vin_numbers read (in its own transaction), the +// failed_vin_decodes check, the device_types read and the wmis read. +func expectDecodeUpToProviders(mock sqlmock.Sqlmock) { + mock.ExpectBegin() + mock.ExpectQuery(`SELECT .* FROM .*vin_numbers.* WHERE`). + WillReturnError(sql.ErrNoRows) + mock.ExpectRollback() + mock.ExpectQuery(`SELECT COUNT\(\*\) FROM .*failed_vin_decodes.*`). + WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(0)) + mock.ExpectQuery(`SELECT .* FROM .*device_types.* WHERE`). + WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow("vehicle", "Vehicle")) + mock.ExpectQuery(`SELECT .* FROM .*wmis.* WHERE`). + WillReturnError(sql.ErrNoRows) +} + +// The regression: every vendor failed and the decoding service reported no +// vendor extra at all. +func TestHandleRecordsAFailedDecodeWhenTheVendorExtraIsNil(t *testing.T) { + dc, mock, vinDecoding := failedDecodeHandler(t) + expectDecodeUpToProviders(mock) + vinDecoding.EXPECT().GetVIN(gomock.Any(), failedTestVIN, coremodels.AllProviders, "USA"). + Return(nil, nil, errors.New("invalid vin")) + + mock.ExpectQuery(`INSERT INTO .*failed_vin_decodes.*`). + WillReturnRows(sqlmock.NewRows([]string{"vin"}).AddRow(failedTestVIN)) + + resp, err := dc.Handle(context.Background(), &DecodeVINQuery{VIN: failedTestVIN, Country: "USA"}) + + require.Error(t, err, "a decode with no vendor extra must report the decode failure, not panic") + assert.Nil(t, resp) + assert.Contains(t, err.Error(), "invalid vin") + // The failure has to be recorded, or the next request repeats the whole + // vendor fan-out and fails identically. + assert.NoError(t, mock.ExpectationsWereMet(), "the failed_vin_decodes row must still be written") +} + +// The ordinary failure: the vendors were tried and said no, so the extra +// carries what each of them answered. That detail must survive into the row. +func TestHandleRecordsTheVendorsTriedOnAFailedDecode(t *testing.T) { + dc, mock, vinDecoding := failedDecodeHandler(t) + expectDecodeUpToProviders(mock) + vinDecoding.EXPECT().GetVIN(gomock.Any(), failedTestVIN, coremodels.AllProviders, "USA"). + Return(nil, &coremodels.VINDecodingVendorExtra{VendorsTried: []string{"drivly", "vincario"}}, errors.New("no vendor could decode")) + + mock.ExpectQuery(`INSERT INTO .*failed_vin_decodes.*`). + WillReturnRows(sqlmock.NewRows([]string{"vin"}).AddRow(failedTestVIN)) + + _, err := dc.Handle(context.Background(), &DecodeVINQuery{VIN: failedTestVIN, Country: "USA"}) + + require.Error(t, err) + assert.Contains(t, err.Error(), "no vendor could decode") + assert.NoError(t, mock.ExpectationsWereMet(), "the failed_vin_decodes row must still be written") +} diff --git a/internal/core/queries/decode_vin_hydrate_test.go b/internal/core/queries/decode_vin_hydrate_test.go new file mode 100644 index 00000000..b7366e6a --- /dev/null +++ b/internal/core/queries/decode_vin_hydrate_test.go @@ -0,0 +1,124 @@ +package queries + +import ( + "context" + "fmt" + "testing" + + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" + "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/db/models" + "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" + mock_gateways "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways/mocks" + "github.com/aarondl/null/v8" + "github.com/pkg/errors" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +// hydrateResponseFromVinNumber is the cached decode path, the one most decodes +// take. Its doc comment promises it answers what a fresh decode of the same VIN +// would, so these run it against a mocked catalog: no Postgres, because a +// vin_numbers row with no style id never touches the database. + +const hydrateVIN = "4T1C11AK8NU123456" + +// cachedVinNumber is a vin_numbers row as saveVinDecodeNumber writes one, with +// no style id so matchSignalsFromVinNumber makes no database call. +func cachedVinNumber() *models.VinNumber { + return &models.VinNumber{ + Vin: hydrateVIN, + ManufacturerName: "Toyota", + Year: 2026, + DefinitionID: "toyota_camry_2026", + DecodeProvider: null.StringFrom("drivly"), + } +} + +func hydrateTemplate() *coremodels.Template { + return &coremodels.Template{ + ID: "toyota_camry_2026", + DeviceType: "vehicle", + Manufacturer: coremodels.TemplateManufacturer{Slug: "toyota", Name: "Toyota", TokenID: 131}, + Model: "Camry", + Year: 2026, + Attributes: map[string]any{"number_of_doors": 4}, + Trims: []coremodels.Trim{ + {Name: "LE", Selectors: coremodels.TrimSelectors{StyleName: []string{"LE"}}, Attributes: map[string]any{"powertrain_type": "ICE"}}, + {Name: "Hybrid LE", Selectors: coremodels.TrimSelectors{StyleName: []string{"Hybrid LE"}}, Attributes: map[string]any{"powertrain_type": "HEV"}}, + }, + Version: 2, + } +} + +func hydrateHandler(t *testing.T) (DecodeVINQueryHandler, *mock_gateways.MockDeviceDefinitionCatalogService) { + t.Helper() + ctrl := gomock.NewController(t) + t.Cleanup(ctrl.Finish) + catalog := mock_gateways.NewMockDeviceDefinitionCatalogService(ctrl) + logger := zerolog.Nop() + return DecodeVINQueryHandler{ + logger: &logger, + deviceDefinitionCatalogService: catalog, + }, catalog +} + +// The same VIN answered from vin_numbers must carry the model a fresh decode +// answered, not an empty string that depends only on cache state. +func TestHydrateResponseFromVinNumberAnswersTheModel(t *testing.T) { + dc, catalog := hydrateHandler(t) + catalog.EXPECT().GetTemplateByID(gomock.Any(), "toyota_camry_2026").Return(hydrateTemplate(), nil, nil) + + resp, err := dc.hydrateResponseFromVinNumber(context.Background(), cachedVinNumber()) + + require.NoError(t, err) + require.NotNil(t, resp) + assert.Equal(t, "Camry", resp.Model, "the cached path must answer the model the fresh path does") + // The rest of the fresh path's fields, so a future edit cannot drop one + // the way Model was dropped. + assert.Equal(t, "Toyota", resp.Manufacturer) + assert.Equal(t, int32(2026), resp.Year) + assert.Equal(t, "drivly", resp.Source) + assert.Equal(t, "toyota_camry_2026", resp.DefinitionId) + assert.Equal(t, int32(2), resp.TemplateVersion) + assert.Equal(t, "model-only", resp.MatchQuality) +} + +// A catalog outage -- a 502, a TLS blip, a truncated body -- is not proof that +// the template does not exist. Answering 200 with empty trim, match quality, +// candidates, powertrain and hardware template id makes an outage +// indistinguishable from a genuinely template-less definition, and emits the +// undocumented fourth match_quality ("") this function's doc comment forbids. +func TestHydrateResponseFromVinNumberFailsOnCatalogOutage(t *testing.T) { + dc, catalog := hydrateHandler(t) + outage := errors.Wrap(fmt.Errorf("unexpected status 502 from catalog"), "failed to read template") + catalog.EXPECT().GetTemplateByID(gomock.Any(), "toyota_camry_2026").Return(nil, nil, outage) + + resp, err := dc.hydrateResponseFromVinNumber(context.Background(), cachedVinNumber()) + + require.Error(t, err, "a catalog outage must surface as an error, not as a successful decode with empty fields") + assert.Nil(t, resp) + assert.NotErrorIs(t, err, gateways.ErrTemplateNotFound) +} + +// A genuine 404 keeps today's behaviour: the VIN was decoded in the past +// without a template existing for it, and the response says so by leaving the +// match fields empty rather than by failing the decode. +func TestHydrateResponseFromVinNumberStillAnswersWhenTheTemplateIsGenuinelyGone(t *testing.T) { + dc, catalog := hydrateHandler(t) + notFound := errors.Wrapf(gateways.ErrTemplateNotFound, "template %s", "toyota_camry_2026") + catalog.EXPECT().GetTemplateByID(gomock.Any(), "toyota_camry_2026").Return(nil, nil, notFound) + + resp, err := dc.hydrateResponseFromVinNumber(context.Background(), cachedVinNumber()) + + require.NoError(t, err) + require.NotNil(t, resp) + assert.Equal(t, "Toyota", resp.Manufacturer) + assert.Equal(t, "toyota_camry_2026", resp.DefinitionId) + assert.Empty(t, resp.Trim) + assert.Empty(t, resp.MatchQuality) + assert.Empty(t, resp.Powertrain) + assert.Empty(t, resp.HardwareTemplateId) + assert.Empty(t, resp.MatchCandidates) +} diff --git a/internal/core/queries/decode_vin_known_test.go b/internal/core/queries/decode_vin_known_test.go new file mode 100644 index 00000000..0e5881c8 --- /dev/null +++ b/internal/core/queries/decode_vin_known_test.go @@ -0,0 +1,127 @@ +package queries + +import ( + "context" + "database/sql" + "database/sql/driver" + "fmt" + "math/big" + "testing" + + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" + "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/db/models" + "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/exceptions" + mock_gateways "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways/mocks" + "github.com/DIMO-Network/shared/pkg/db" + vinutils "github.com/DIMO-Network/shared/pkg/vin" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +// vinInfoFromKnown is the smartcar / software-connection fallback: the +// providers all failed, and the decode is rebuilt from the WMI plus a model +// and year the caller supplied. These need no Postgres -- makeFromWMIRows +// takes the rows, and the context test never gets as far as a connection. + +const knownVIN = "1FTFW1E502FA00001" + +// An unknown WMI is the case this fallback exists for. sqlboiler's .All() +// reports it as an empty slice with a nil error -- unlike .One(), which +// returns sql.ErrNoRows -- so indexing element zero panicked the decode +// handler. +func TestMakeFromWMIRowsReportsAnUnknownWMIAsNotFound(t *testing.T) { + dc, _ := hydrateHandler(t) + + mk, err := dc.makeFromWMIRows(context.Background(), "1FT", nil, "F-150", 2020) + + require.Error(t, err) + assert.Empty(t, mk) + var notFound *exceptions.NotFoundError + assert.ErrorAs(t, err, ¬Found, "an unknown WMI must be a typed not found, not a panic") +} + +// One row is the common case and still answers that marque. +func TestMakeFromWMIRowsAnswersTheOnlyManufacturer(t *testing.T) { + dc, _ := hydrateHandler(t) + + mk, err := dc.makeFromWMIRows(context.Background(), "1FT", models.WmiSlice{{Wmi: "1FT", ManufacturerName: "Ford"}}, "F-150", 2020) + + require.NoError(t, err) + assert.Equal(t, "Ford", mk) +} + +// A WMI shared by several marques of one parent OEM resolves to the marque +// that already has a template for this model-year, and the catalog is asked +// with the caller's context. +func TestMakeFromWMIRowsPicksTheMarqueWithATemplateUsingTheCallersContext(t *testing.T) { + dc, catalog := hydrateHandler(t) + type ctxKey struct{} + ctx := context.WithValue(context.Background(), ctxKey{}, "callers-context") + + catalog.EXPECT().GetTemplateByID(gomock.Any(), "chrysler_town-and-country_2012"). + DoAndReturn(func(got context.Context, _ string) (*coremodels.Template, *big.Int, error) { + assert.Equal(t, "callers-context", got.Value(ctxKey{}), "the catalog must be called with the caller's context") + return nil, nil, fmt.Errorf("not in the catalog") + }) + catalog.EXPECT().GetTemplateByID(gomock.Any(), "dodge_town-and-country_2012"). + DoAndReturn(func(got context.Context, _ string) (*coremodels.Template, *big.Int, error) { + assert.Equal(t, "callers-context", got.Value(ctxKey{}), "the catalog must be called with the caller's context") + return hydrateTemplate(), nil, nil + }) + + mk, err := dc.makeFromWMIRows(ctx, "2C4", models.WmiSlice{ + {Wmi: "2C4", ManufacturerName: "Chrysler"}, + {Wmi: "2C4", ManufacturerName: "Dodge"}, + }, "Town and Country", 2012) + + require.NoError(t, err) + assert.Equal(t, "Dodge", mk) +} + +// ctxRecordingConnector is a database/sql connector that records the context +// the query was issued with and then refuses to connect, so a query's context +// is observable without a database. +type ctxRecordingConnector struct{ got chan context.Context } + +func (c *ctxRecordingConnector) Connect(ctx context.Context) (driver.Conn, error) { + select { + case c.got <- ctx: + default: + } + return nil, fmt.Errorf("no database in this test") +} + +func (*ctxRecordingConnector) Driver() driver.Driver { return nil } + +// A cancelled decode must stop holding a database connection: the wmis query +// ran on context.Background(), so it outlived the request that asked for it. +func TestVinInfoFromKnownQueriesWithTheCallersContext(t *testing.T) { + conn := &ctxRecordingConnector{got: make(chan context.Context, 1)} + sqlDB := sql.OpenDB(conn) + t.Cleanup(func() { _ = sqlDB.Close() }) + + ctrl := gomock.NewController(t) + t.Cleanup(ctrl.Finish) + logger := zerolog.Nop() + dc := DecodeVINQueryHandler{ + logger: &logger, + deviceDefinitionCatalogService: mock_gateways.NewMockDeviceDefinitionCatalogService(ctrl), + dbs: func() *db.ReaderWriter { + return &db.ReaderWriter{Reader: &db.DB{DB: sqlDB}, Writer: &db.DB{DB: sqlDB}} + }, + } + + type ctxKey struct{} + ctx := context.WithValue(context.Background(), ctxKey{}, "callers-context") + _, err := dc.vinInfoFromKnown(ctx, vinutils.VIN(knownVIN), "F-150", 2020) + require.Error(t, err, "the fake connector refuses, so the query must fail") + + select { + case got := <-conn.got: + assert.Equal(t, "callers-context", got.Value(ctxKey{}), "the wmis query must run on the caller's context, not context.Background()") + default: + t.Fatal("no database connection was attempted") + } +} diff --git a/internal/core/queries/decode_vin_style_test.go b/internal/core/queries/decode_vin_style_test.go new file mode 100644 index 00000000..e02fba92 --- /dev/null +++ b/internal/core/queries/decode_vin_style_test.go @@ -0,0 +1,122 @@ +package queries + +import ( + "context" + "database/sql" + "errors" + "testing" + + sqlmock "github.com/DATA-DOG/go-sqlmock" + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// processDeviceStyle runs on every decode whose style name is at least two +// characters, which is nearly all of them. sqlboiler's One() returns a nil row +// together with a wrapped error for every failure that is not sql.ErrNoRows -- +// a reader-pool blip, a reset connection, a context deadline (the caller's +// context carries one, and a catalog round trip runs just before this) -- so +// branching only on no-rows and then reading style.ID nil-dereferences and +// panics the decode. Handle is already written to tolerate an error from this +// function; it just never got one. +// +// No Postgres: sqlmock answers the device_styles reads. + +const styleTestDefinitionID = "toyota_camry_2026" + +func styleHandler(t *testing.T) (DecodeVINQueryHandler, sqlmock.Sqlmock) { + t.Helper() + return txHandler(t) +} + +func styleVINInfo() *coremodels.VINDecodingInfoData { + return &coremodels.VINDecodingInfoData{ + VIN: "4T1C11AK8NU123456", + Make: "Toyota", + Model: "Camry", + Year: 2026, + StyleName: "LE", + Source: coremodels.DrivlyProvider, + } +} + +// The first lookup is by (definition_id, source, external_style_id). A failure +// that is not no-rows leaves the row nil, and neither no-rows branch fires. +func TestProcessDeviceStyleReportsAFailedExternalIDLookup(t *testing.T) { + dc, mock := styleHandler(t) + mock.ExpectQuery(`SELECT .* FROM .*device_styles.* WHERE`). + WillReturnError(context.DeadlineExceeded) + + id, err := dc.processDeviceStyle(context.Background(), styleVINInfo(), styleTestDefinitionID, "ICE") + + require.Error(t, err, "a failed device_styles read must be reported, not dereferenced") + assert.ErrorIs(t, err, context.DeadlineExceeded) + assert.Empty(t, id) + assert.NoError(t, mock.ExpectationsWereMet()) +} + +// The second lookup is by name, reached only when the first found no row. It +// fails the same way, and used to reach the same nil dereference. +func TestProcessDeviceStyleReportsAFailedNameLookup(t *testing.T) { + dc, mock := styleHandler(t) + mock.ExpectQuery(`SELECT .* FROM .*device_styles.* WHERE`). + WillReturnError(sql.ErrNoRows) + mock.ExpectQuery(`SELECT .* FROM .*device_styles.* WHERE`). + WillReturnError(sql.ErrConnDone) + + id, err := dc.processDeviceStyle(context.Background(), styleVINInfo(), styleTestDefinitionID, "ICE") + + require.Error(t, err, "a failed device_styles read must be reported, not dereferenced") + assert.ErrorIs(t, err, sql.ErrConnDone) + assert.Empty(t, id) + assert.NoError(t, mock.ExpectationsWereMet()) +} + +// The ordinary hit: the style already exists under the external style id. +func TestProcessDeviceStyleReturnsAnExistingStyle(t *testing.T) { + dc, mock := styleHandler(t) + mock.ExpectQuery(`SELECT .* FROM .*device_styles.* WHERE`). + WillReturnRows(sqlmock.NewRows([]string{"id", "definition_id", "name", "external_style_id", "source"}). + AddRow("26M1cyBpEVbz8Ejw5A7qKcKAaWP", styleTestDefinitionID, "LE", "le", "drivly")) + + id, err := dc.processDeviceStyle(context.Background(), styleVINInfo(), styleTestDefinitionID, "ICE") + + require.NoError(t, err) + assert.Equal(t, "26M1cyBpEVbz8Ejw5A7qKcKAaWP", id) + assert.NoError(t, mock.ExpectationsWereMet()) +} + +// Found on the second lookup, by name: the first read reported no row. +func TestProcessDeviceStyleReturnsAStyleFoundByName(t *testing.T) { + dc, mock := styleHandler(t) + mock.ExpectQuery(`SELECT .* FROM .*device_styles.* WHERE`). + WillReturnError(sql.ErrNoRows) + mock.ExpectQuery(`SELECT .* FROM .*device_styles.* WHERE`). + WillReturnRows(sqlmock.NewRows([]string{"id", "definition_id", "name", "external_style_id", "source"}). + AddRow("26M1cyBpEVbz8Ejw5A7qKcKAaWQ", styleTestDefinitionID, "LE", "le-other", "vincario")) + + id, err := dc.processDeviceStyle(context.Background(), styleVINInfo(), styleTestDefinitionID, "ICE") + + require.NoError(t, err) + assert.Equal(t, "26M1cyBpEVbz8Ejw5A7qKcKAaWQ", id) + assert.NoError(t, mock.ExpectationsWereMet()) +} + +// A failed insert is already reported; keep it that way, and keep the error +// distinguishable from a failed read. +func TestProcessDeviceStyleReportsAFailedInsert(t *testing.T) { + dc, mock := styleHandler(t) + mock.ExpectQuery(`SELECT .* FROM .*device_styles.* WHERE`). + WillReturnError(sql.ErrNoRows) + mock.ExpectQuery(`SELECT .* FROM .*device_styles.* WHERE`). + WillReturnError(sql.ErrNoRows) + mock.ExpectQuery(`INSERT INTO .*device_styles.*`). + WillReturnError(errors.New("duplicate key value violates unique constraint")) + + id, err := dc.processDeviceStyle(context.Background(), styleVINInfo(), styleTestDefinitionID, "ICE") + + require.Error(t, err) + assert.Contains(t, err.Error(), "error creating style") + assert.Empty(t, id) +} diff --git a/internal/core/queries/decode_vin_test.go b/internal/core/queries/decode_vin_test.go index 2ca6b83c..f90468e0 100644 --- a/internal/core/queries/decode_vin_test.go +++ b/internal/core/queries/decode_vin_test.go @@ -11,7 +11,7 @@ import ( mock_repository "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/db/repositories/mocks" "github.com/aarondl/sqlboiler/v4/types" - "github.com/segmentio/ksuid" + "github.com/pkg/errors" coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" stringutils "github.com/DIMO-Network/shared/pkg/strings" @@ -46,7 +46,7 @@ type DecodeVINQueryHandlerSuite struct { mockVINService *mock_services.MockVINDecodingService mockFuelAPIService *mock_gateways.MockFuelAPIService mockPowerTrainTypeService *mock_services.MockPowerTrainTypeService - mockDeviceDefinitionOnChainService *mock_gateways.MockDeviceDefinitionOnChainService + mockDeviceDefinitionCatalogService *mock_gateways.MockDeviceDefinitionCatalogService queryHandler DecodeVINQueryHandler mockVINRepo *mock_repository.MockVINRepository @@ -66,14 +66,14 @@ func (s *DecodeVINQueryHandlerSuite) SetupTest() { s.mockVINService = mock_services.NewMockVINDecodingService(s.ctrl) s.mockPowerTrainTypeService = mock_services.NewMockPowerTrainTypeService(s.ctrl) - s.mockDeviceDefinitionOnChainService = mock_gateways.NewMockDeviceDefinitionOnChainService(s.ctrl) + s.mockDeviceDefinitionCatalogService = mock_gateways.NewMockDeviceDefinitionCatalogService(s.ctrl) s.mockFuelAPIService = mock_gateways.NewMockFuelAPIService(s.ctrl) s.mockVINRepo = mock_repository.NewMockVINRepository(s.ctrl) s.mockIdentity = mock_gateways.NewMockIdentityAPI(s.ctrl) s.pdb, s.container = dbtesthelper.StartContainerDatabase(s.ctx, dbName, s.T(), migrationsDirRelPath) - s.queryHandler = NewDecodeVINQueryHandler(s.pdb.DBS, s.mockVINService, s.mockVINRepo, dbtesthelper.Logger(), s.mockFuelAPIService, s.mockPowerTrainTypeService, s.mockDeviceDefinitionOnChainService, s.mockIdentity) + s.queryHandler = NewDecodeVINQueryHandler(s.pdb.DBS, s.mockVINService, s.mockVINRepo, dbtesthelper.Logger(), s.mockFuelAPIService, s.mockPowerTrainTypeService, s.mockDeviceDefinitionCatalogService, s.mockIdentity) } func (s *DecodeVINQueryHandlerSuite) TearDownTest() { @@ -165,8 +165,8 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_WithExistingDD_UpdatesAt vinExtra := &coremodels.VINDecodingVendorExtra{} s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, vinExtra, nil) s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return("ICE") - s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return( - buildTestTblDD(definitionID, dd.Model, int(dd.Year)), nil, nil) + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + buildTestTemplate(definitionID, dd.Model, int(dd.Year)), nil, nil) wmiDb := &models.Wmi{ Wmi: vin[:3], ManufacturerName: dm.Name, @@ -275,14 +275,16 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_CreatesDD_WithMismatchWM vinDecodingInfoData.MetaData = null.JSONFrom(metaData) styleLevelPT := "PHEV" - s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return( - nil, nil, nil) // should return nil b/c doesn't exist + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + nil, nil, errors.Wrapf(gateways.ErrTemplateNotFound, "template %s", definitionID)) // genuine 404: creation path should still run vinExtra := &coremodels.VINDecodingVendorExtra{} s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, vinExtra, nil) s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return(styleLevelPT) - trxHashHex := "0xa90868fe9364dbf41695b3b87e630f6455cfd63a4711f56b64f631b828c02b35" - s.mockDeviceDefinitionOnChainService.EXPECT().Create(ctx, dmLincoln.Name, gomock.Any()).Return(&trxHashHex, nil) + // Create answers with the document the worker stored, and the decode + // narrows it exactly as it narrows a template it found. + s.mockDeviceDefinitionCatalogService.EXPECT().Create(ctx, dmLincoln.Name, gomock.Any()). + Return(buildCreatedTemplate(definitionID, vinInfoResp.Model, 2022, styleLevelPT), nil) image := gateways.FuelImage{ SourceURL: "https://image", @@ -344,15 +346,13 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_JapanChassisNumber_exist err := vinNumb.Insert(s.ctx, s.pdb.DBS().Writer, boil.Infer()) s.Require().NoError(err) // mock setup for powertrain lookup, which is in the vin decode response - s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), dd.ID).Return( - &coremodels.DeviceDefinitionTablelandModel{ + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), dd.ID).Return( + &coremodels.Template{ ID: dd.ID, Model: dd.Model, Year: dd.Year, DeviceType: common.DefaultDeviceType, - Metadata: &coremodels.DeviceDefinitionMetadata{DeviceAttributes: []coremodels.DeviceTypeAttribute{ - {Name: "powertrain_type", Value: "ICE"}, - }}, + Attributes: map[string]any{"powertrain_type": "ICE"}, }, big.NewInt(1), nil) qryResult, err := s.queryHandler.Handle(s.ctx, &DecodeVINQuery{VIN: vin, Country: country}) @@ -428,13 +428,13 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_CreatesDD() { vinDecodingInfoData.MetaData = null.JSONFrom(metaData) styleLevelPT := "PHEV" - s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return( - nil, nil, nil) // should return nil b/c doesn't exist + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + nil, nil, errors.Wrapf(gateways.ErrTemplateNotFound, "template %s", definitionID)) // genuine 404: creation path should still run s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil, nil) s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return(styleLevelPT) - trxHashHex := "0xa90868fe9364dbf41695b3b87e630f6455cfd63a4711f56b64f631b828c02b35" - s.mockDeviceDefinitionOnChainService.EXPECT().Create(ctx, gomock.Any(), gomock.Any()).Return(&trxHashHex, nil) + s.mockDeviceDefinitionCatalogService.EXPECT().Create(ctx, gomock.Any(), gomock.Any()). + Return(buildCreatedTemplate(definitionID, vinInfoResp.Model, 2021, styleLevelPT), nil) image := gateways.FuelImage{ SourceURL: "https://image", @@ -477,18 +477,414 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_CreatesDD() { s.Assert().NotEmpty(ddImages) } -func buildTestTblDD(definitionID, model string, year int) *coremodels.DeviceDefinitionTablelandModel { - return &coremodels.DeviceDefinitionTablelandModel{ +// buildCreatedTemplate is the document definitions-worker stores, and answers +// the PUT with, for a template Create wrote: one Base trim, the decoded +// powertrain as a template attribute, and version 1. A decode that creates a +// definition must narrow this exactly as the next decode of the same VIN +// narrows the same document read back out of the catalog. +func buildCreatedTemplate(definitionID, model string, year int, powertrain string) *coremodels.Template { + attrs := map[string]any{} + if powertrain != "" { + attrs["powertrain_type"] = powertrain + } + return &coremodels.Template{ + ID: definitionID, + Model: model, + Year: year, + DeviceType: "vehicle", + Manufacturer: coremodels.TemplateManufacturer{Slug: strings.Split(definitionID, "_")[0], TokenID: 1}, + Attributes: attrs, + Trims: []coremodels.Trim{{Name: "Base", Attributes: map[string]any{}}}, + Version: 1, + } +} + +func buildTestTemplate(definitionID, model string, year int) *coremodels.Template { + return &coremodels.Template{ ID: definitionID, - KSUID: ksuid.New().String(), Model: model, Year: year, DeviceType: "vehicle", ImageURI: "", - Metadata: &coremodels.DeviceDefinitionMetadata{DeviceAttributes: []coremodels.DeviceTypeAttribute{ - {Name: "powertrain_type", Value: "ICE"}, - }}, + Attributes: map[string]any{"powertrain_type": "ICE"}, + } +} + +// buildTestTemplateWithTrims returns a template with two trims disambiguated +// on styleName -- LE (ICE) and Hybrid LE (HEV) -- mirroring the real +// toyota_camry_2020 bug this migration exists to fix: a template whose +// top-level attributes say ICE while a specific trim actually carries HEV. +// Trims are disambiguated on styleName here (rather than manufacturerCode, +// see buildTestCamryTemplate below) to prove that axis still works too -- +// vincario/autoiso/dat-decoded VINs never carry a manufacturer code, so +// styleName selectors remain the only reachable signal for that population. +func buildTestTemplateWithTrims(definitionID, model string, year, version int) *coremodels.Template { + return &coremodels.Template{ + ID: definitionID, + Model: model, + Year: year, + DeviceType: "vehicle", + Version: version, + Attributes: map[string]any{"powertrain_type": "ICE"}, + Trims: []coremodels.Trim{ + { + Name: "LE", + Selectors: coremodels.TrimSelectors{StyleName: []string{"LE"}}, + Attributes: map[string]any{"powertrain_type": "ICE"}, + }, + { + Name: "Hybrid LE", + Selectors: coremodels.TrimSelectors{StyleName: []string{"Hybrid LE"}}, + Attributes: map[string]any{"powertrain_type": "HEV"}, + }, + }, + } +} + +// buildTestCamryTemplate mirrors trim_match_test.go's camry() fixture and, +// more importantly, mirrors what the extraction pipeline actually emits +// (emit.mjs:166 emits only manufacturerCode selectors, never styleName). +// LE/Hybrid LE are disambiguated purely on manufacturerCode -- the axis +// that requires VINDecodingInfoData.ManufacturerCode (populated in +// buildFromDrivly) to reach decode_vin's MatchSignals at all. +func buildTestCamryTemplate(definitionID, model string, year, version int) *coremodels.Template { + return &coremodels.Template{ + ID: definitionID, + Model: model, + Year: year, + DeviceType: "vehicle", + Version: version, + Attributes: map[string]any{"powertrain_type": "ICE"}, + Trims: []coremodels.Trim{ + { + Name: "LE", + Selectors: coremodels.TrimSelectors{ManufacturerCode: []string{"2532"}}, + Attributes: map[string]any{"powertrain_type": "ICE"}, + }, + { + Name: "Hybrid LE", + Selectors: coremodels.TrimSelectors{ManufacturerCode: []string{"2559"}}, + Attributes: map[string]any{"powertrain_type": "HEV"}, + }, + }, + } +} + +// A catalog 404 (ErrTemplateNotFound) is the one case where GetTemplateByID +// failing should still fall through to Create(): the definition genuinely +// does not exist yet, exactly as it does today. +func (s *DecodeVINQueryHandlerSuite) TestHandle_CatalogNotFound_StillCreatesDefinition() { + ctx := context.Background() + const vin = "1FMCU0G61MUA52727" // ford escape 2021 + const wmi = "1FM" + + dm := dbtesthelper.SetupCreateMake("Ford") + _ = dbtesthelper.SetupCreateAutoPiIntegration(s.T(), s.pdb) + _ = dbtesthelper.SetupCreateWMI(s.T(), wmi, dm.Name, s.pdb) + + vinDecodingInfoData := &coremodels.VINDecodingInfoData{ + StyleName: "XLE", + Source: "drivly", + Year: 2021, + Make: dm.Name, + Model: "Escape", + } + definitionID := "ford_escape_2021" + + s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil, nil) + s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return("ICE") + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + nil, nil, errors.Wrapf(gateways.ErrTemplateNotFound, "template %s", definitionID)) + + s.mockDeviceDefinitionCatalogService.EXPECT().Create(gomock.Any(), gomock.Any(), gomock.Any()).Times(1). + Return(buildCreatedTemplate(definitionID, "Escape", 2021, "ICE"), nil) + + image := gateways.FuelImage{SourceURL: "https://image"} + fuelDeviceImagesMock := gateways.FuelDeviceImages{FuelAPIID: "1", Height: 1, Width: 1, Images: []gateways.FuelImage{image}} + s.mockFuelAPIService.EXPECT().FetchDeviceImages(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(2).Return(fuelDeviceImagesMock, nil) + + qryResult, err := s.queryHandler.Handle(s.ctx, &DecodeVINQuery{VIN: vin, Country: country}) + s.NoError(err) + s.NotNil(qryResult, "expected qryResult not nil") + s.Assert().Equal(definitionID, qryResult.DefinitionId) +} + +// A catalog 500 (or any other non-ErrTemplateNotFound failure) must abort +// the decode rather than being read as "the definition doesn't exist." +// Reading it that way is exactly what would create a duplicate definition +// for a vehicle that may already exist -- on the VIN-decode hot path, at +// decode volume, during a catalog outage. The Times(0) on Create is the +// whole point of this test: against the pre-fix code, GetTemplateByID +// returning any error (not just ErrTemplateNotFound) fell through with a +// nil template and Create() ran anyway, violating this expectation. +func (s *DecodeVINQueryHandlerSuite) TestHandle_CatalogOutage_AbortsWithoutCreatingDuplicate() { + ctx := context.Background() + const vin = "1FMCU0G61MUA52727" // ford escape 2021 + const wmi = "1FM" + + dm := dbtesthelper.SetupCreateMake("Ford") + _ = dbtesthelper.SetupCreateAutoPiIntegration(s.T(), s.pdb) + _ = dbtesthelper.SetupCreateWMI(s.T(), wmi, dm.Name, s.pdb) + + vinDecodingInfoData := &coremodels.VINDecodingInfoData{ + StyleName: "XLE", + Source: "drivly", + Year: 2021, + Make: dm.Name, + Model: "Escape", + } + definitionID := "ford_escape_2021" + + s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil, nil) + // A plain, non-sentinel error simulates a catalog 500 / timeout / decode + // failure -- deliberately not wrapping gateways.ErrTemplateNotFound. + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + nil, nil, fmt.Errorf("catalog returned 500 for template %s", definitionID)) + s.mockDeviceDefinitionCatalogService.EXPECT().Create(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + // Permissive stubs for everything a correctly-aborting Handle() never + // reaches. They exist so that, against the pre-fix code (which falls + // through past the catalog error instead of aborting), the flow can run + // all the way to Create() and the failure this test reports is squarely + // "Create was called when it should not have been" -- not an incidental + // panic on some other unmocked call along the way. + s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(gomock.Any(), gomock.Any()).AnyTimes().Return("ICE") + image := gateways.FuelImage{SourceURL: "https://image"} + fuelDeviceImagesMock := gateways.FuelDeviceImages{FuelAPIID: "1", Height: 1, Width: 1, Images: []gateways.FuelImage{image}} + s.mockFuelAPIService.EXPECT().FetchDeviceImages(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(fuelDeviceImagesMock, nil) + + qryResult, err := s.queryHandler.Handle(s.ctx, &DecodeVINQuery{VIN: vin, Country: country}) + s.Error(err, "a catalog outage must abort the decode") + s.Nil(qryResult) + + count, countErr := models.VinNumbers().Count(s.ctx, s.pdb.DBS().Reader) + require.NoError(s.T(), countErr) + assert.Equal(s.T(), int64(0), count, "an aborted decode must not persist a vin_number as if it succeeded") +} + +// A styleName that matches exactly one trim's selectors narrows the +// template to that trim: the response reports the trim, an "exact" match +// quality, the template's version, and a powertrain taken from the matched +// trim's attributes -- not the template's blended default. +func (s *DecodeVINQueryHandlerSuite) TestHandle_ExactTrimMatch_PopulatesMatchFieldsFromResolvedTrim() { + ctx := context.Background() + const vin = "1FMCU0G61MUA52727" // ford escape 2021 + const wmi = "1FM" + + dm := dbtesthelper.SetupCreateMake("Ford") + _ = dbtesthelper.SetupCreateAutoPiIntegration(s.T(), s.pdb) + _ = dbtesthelper.SetupCreateWMI(s.T(), wmi, dm.Name, s.pdb) + + vinDecodingInfoData := &coremodels.VINDecodingInfoData{ + StyleName: "Hybrid LE", + Source: "drivly", + Year: 2021, + Make: dm.Name, + Model: "Escape", } + definitionID := "ford_escape_2021" + + s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil, nil) + // The style-write path (processDeviceStyle) is untouched by this change: + // it still derives from ResolvePowerTrainFromVinInfo, deliberately + // returning a different value ("ICE") than the matched trim's ("HEV") so + // the assertions below can tell the two paths apart. + s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return("ICE") + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + buildTestTemplateWithTrims(definitionID, "Escape", 2021, 3), nil, nil) + + image := gateways.FuelImage{SourceURL: "https://image"} + fuelDeviceImagesMock := gateways.FuelDeviceImages{FuelAPIID: "1", Height: 1, Width: 1, Images: []gateways.FuelImage{image}} + s.mockFuelAPIService.EXPECT().FetchDeviceImages(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(2).Return(fuelDeviceImagesMock, nil) + + qryResult, err := s.queryHandler.Handle(s.ctx, &DecodeVINQuery{VIN: vin, Country: country}) + s.NoError(err) + s.NotNil(qryResult, "expected qryResult not nil") + + s.Assert().Equal("Hybrid LE", qryResult.Trim) + s.Assert().Equal("exact", qryResult.MatchQuality) + s.Assert().Equal(int32(3), qryResult.TemplateVersion) + s.Assert().Equal("HEV", qryResult.Powertrain, "response powertrain must come from the resolved trim, not the ResolvePowerTrainFromVinInfo heuristic") + s.Assert().Empty(qryResult.MatchCandidates) + + // processDeviceStyle's write is untouched: device_styles still gets the + // old heuristic's value ("ICE"), never the resolved trim's ("HEV"). + ds, err := models.DeviceStyles().One(s.ctx, s.pdb.DBS().Reader) + s.Require().NoError(err) + s.Assert().Equal("ICE", gjson.GetBytes(ds.Metadata.JSON, common.PowerTrainType).Str) +} + +// A styleName that matches none of the template's trims is model-only: no +// trim is chosen, and the response's powertrain (if any) comes only from +// the template's own attributes -- never from a trim that didn't match. +func (s *DecodeVINQueryHandlerSuite) TestHandle_NoTrimMatch_IsModelOnlyWithNoTrimPowertrain() { + ctx := context.Background() + const vin = "1FMCU0G61MUA52727" // ford escape 2021 + const wmi = "1FM" + + dm := dbtesthelper.SetupCreateMake("Ford") + _ = dbtesthelper.SetupCreateAutoPiIntegration(s.T(), s.pdb) + _ = dbtesthelper.SetupCreateWMI(s.T(), wmi, dm.Name, s.pdb) + + vinDecodingInfoData := &coremodels.VINDecodingInfoData{ + StyleName: "Unknown Trim", + Source: "drivly", + Year: 2021, + Make: dm.Name, + Model: "Escape", + } + definitionID := "ford_escape_2021" + + s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil, nil) + s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return("ICE") + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + buildTestTemplateWithTrims(definitionID, "Escape", 2021, 3), nil, nil) + + image := gateways.FuelImage{SourceURL: "https://image"} + fuelDeviceImagesMock := gateways.FuelDeviceImages{FuelAPIID: "1", Height: 1, Width: 1, Images: []gateways.FuelImage{image}} + s.mockFuelAPIService.EXPECT().FetchDeviceImages(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(2).Return(fuelDeviceImagesMock, nil) + + qryResult, err := s.queryHandler.Handle(s.ctx, &DecodeVINQuery{VIN: vin, Country: country}) + s.NoError(err) + s.NotNil(qryResult, "expected qryResult not nil") + + s.Assert().Empty(qryResult.Trim) + s.Assert().Equal("model-only", qryResult.MatchQuality) + s.Assert().Equal(int32(3), qryResult.TemplateVersion) + s.Assert().Empty(qryResult.MatchCandidates) + // The template's own attribute survives (it is not "from a trim"); it + // must not be either trim's own value. + s.Assert().Equal("ICE", qryResult.Powertrain) +} + +// A styleName that matches more than one trim's selectors is ambiguous: no +// trim is chosen, the still-contending trims are reported as candidates, +// and only the attributes every candidate agrees on survive -- here LE and +// Hybrid LE disagree on powertrain_type, so the response falls back to the +// template's own value, never one candidate's arbitrarily. +func (s *DecodeVINQueryHandlerSuite) TestHandle_AmbiguousTrimMatch_PopulatesCandidates() { + ctx := context.Background() + const vin = "1FMCU0G61MUA52727" // ford escape 2021 + const wmi = "1FM" + + dm := dbtesthelper.SetupCreateMake("Ford") + _ = dbtesthelper.SetupCreateAutoPiIntegration(s.T(), s.pdb) + _ = dbtesthelper.SetupCreateWMI(s.T(), wmi, dm.Name, s.pdb) + + vinDecodingInfoData := &coremodels.VINDecodingInfoData{ + StyleName: "SE", + Source: "drivly", + Year: 2021, + Make: dm.Name, + Model: "Escape", + } + definitionID := "ford_escape_2021" + tmpl := buildTestTemplateWithTrims(definitionID, "Escape", 2021, 3) + tmpl.Trims[0].Selectors.StyleName = []string{"SE"} + tmpl.Trims[1].Selectors.StyleName = []string{"SE"} + + s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil, nil) + s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return("ICE") + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return(tmpl, nil, nil) + + image := gateways.FuelImage{SourceURL: "https://image"} + fuelDeviceImagesMock := gateways.FuelDeviceImages{FuelAPIID: "1", Height: 1, Width: 1, Images: []gateways.FuelImage{image}} + s.mockFuelAPIService.EXPECT().FetchDeviceImages(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(2).Return(fuelDeviceImagesMock, nil) + + qryResult, err := s.queryHandler.Handle(s.ctx, &DecodeVINQuery{VIN: vin, Country: country}) + s.NoError(err) + s.NotNil(qryResult, "expected qryResult not nil") + + s.Assert().Empty(qryResult.Trim) + s.Assert().Equal("ambiguous", qryResult.MatchQuality) + s.Assert().ElementsMatch([]string{"LE", "Hybrid LE"}, qryResult.MatchCandidates) + s.Assert().Equal(int32(3), qryResult.TemplateVersion) + s.Assert().Equal("ICE", qryResult.Powertrain, "disagreeing candidates must not leak one trim's value into the response") +} + +// The scenario the manufacturer-code finding said was structurally +// unreachable: a drivly decode whose upstream response carries a +// manufacturerCode now forwards it into MatchSignals, and narrows a +// manufacturerCode-keyed template -- the only selector kind the extraction +// pipeline actually emits (emit.mjs:166) -- to a single trim. +func (s *DecodeVINQueryHandlerSuite) TestHandle_DrivlyManufacturerCode_ExactTrimMatch() { + ctx := context.Background() + const vin = "1FMCU0G61MUA52727" // ford escape 2021 + const wmi = "1FM" + + dm := dbtesthelper.SetupCreateMake("Ford") + _ = dbtesthelper.SetupCreateAutoPiIntegration(s.T(), s.pdb) + _ = dbtesthelper.SetupCreateWMI(s.T(), wmi, dm.Name, s.pdb) + + vinDecodingInfoData := &coremodels.VINDecodingInfoData{ + StyleName: "Hybrid LE", + Source: coremodels.DrivlyProvider, + Year: 2021, + Make: dm.Name, + Model: "Escape", + ManufacturerCode: "2559", + } + definitionID := "ford_escape_2021" + + s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil, nil) + s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return("ICE") + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + buildTestCamryTemplate(definitionID, "Escape", 2021, 3), nil, nil) + + image := gateways.FuelImage{SourceURL: "https://image"} + fuelDeviceImagesMock := gateways.FuelDeviceImages{FuelAPIID: "1", Height: 1, Width: 1, Images: []gateways.FuelImage{image}} + s.mockFuelAPIService.EXPECT().FetchDeviceImages(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(2).Return(fuelDeviceImagesMock, nil) + + qryResult, err := s.queryHandler.Handle(s.ctx, &DecodeVINQuery{VIN: vin, Country: country}) + s.NoError(err) + s.NotNil(qryResult, "expected qryResult not nil") + + s.Assert().Equal("Hybrid LE", qryResult.Trim) + s.Assert().Equal("exact", qryResult.MatchQuality) + s.Assert().Equal(int32(3), qryResult.TemplateVersion) + s.Assert().Equal("HEV", qryResult.Powertrain) + s.Assert().Empty(qryResult.MatchCandidates) +} + +// A decode from a provider that supplies no manufacturer code (every +// provider except drivly, and drivly itself whenever its response omits +// one) must not error just because the template's selectors are +// manufacturerCode-only: matching simply can't succeed on that axis, and +// the response reports model-only like any other no-match, not a failure. +func (s *DecodeVINQueryHandlerSuite) TestHandle_NoManufacturerCode_IsModelOnlyNotError() { + ctx := context.Background() + const vin = "1FMCU0G61MUA52727" // ford escape 2021 + const wmi = "1FM" + + dm := dbtesthelper.SetupCreateMake("Ford") + _ = dbtesthelper.SetupCreateAutoPiIntegration(s.T(), s.pdb) + _ = dbtesthelper.SetupCreateWMI(s.T(), wmi, dm.Name, s.pdb) + + vinDecodingInfoData := &coremodels.VINDecodingInfoData{ + StyleName: "XLE", + Source: coremodels.VincarioProvider, // never carries a manufacturer code + Year: 2021, + Make: dm.Name, + Model: "Escape", + // ManufacturerCode intentionally left at its zero value. + } + definitionID := "ford_escape_2021" + + s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil, nil) + s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return("ICE") + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + buildTestCamryTemplate(definitionID, "Escape", 2021, 3), nil, nil) + + image := gateways.FuelImage{SourceURL: "https://image"} + fuelDeviceImagesMock := gateways.FuelDeviceImages{FuelAPIID: "1", Height: 1, Width: 1, Images: []gateways.FuelImage{image}} + s.mockFuelAPIService.EXPECT().FetchDeviceImages(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(2).Return(fuelDeviceImagesMock, nil) + + qryResult, err := s.queryHandler.Handle(s.ctx, &DecodeVINQuery{VIN: vin, Country: country}) + s.NoError(err, "no manufacturer code must not error the decode") + s.NotNil(qryResult, "expected qryResult not nil") + + s.Assert().Empty(qryResult.Trim) + s.Assert().Equal("model-only", qryResult.MatchQuality) + s.Assert().Empty(qryResult.MatchCandidates) } func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_WithExistingDD_AndStyleAndMetadata() { @@ -545,8 +941,8 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_WithExistingDD_AndStyleA s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil, nil) s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return("HEV") - s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return( - buildTestTblDD(definitionID, dd.Model, int(dd.Year)), nil, nil) + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + buildTestTemplate(definitionID, dd.Model, int(dd.Year)), nil, nil) // db setup ds := dbtesthelper.SetupCreateStyle(s.T(), definitionID, buildStyleName(vinInfoResp), "drivly", vinInfoResp.SubModel, s.pdb) @@ -638,8 +1034,8 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_WithExistingWMI() { s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil, nil) s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return("HEV") - s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return( - buildTestTblDD(definitionID, dd.Model, int(dd.Year)), nil, nil) + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + buildTestTemplate(definitionID, dd.Model, int(dd.Year)), nil, nil) image := gateways.FuelImage{ SourceURL: "https://image", @@ -690,8 +1086,8 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_TeslaDecode() { s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.TeslaProvider, "USA").Times(1).Return(vinDecodingInfoData, nil, nil) s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo(vinDecodingInfoData.StyleName, vinDecodingInfoData.FuelType).Return("BEV") - s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return( - buildTestTblDD(definitionID, dd.Model, dd.Year), nil, nil) + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + buildTestTemplate(definitionID, dd.Model, dd.Year), nil, nil) image := gateways.FuelImage{ SourceURL: "https://image", @@ -747,15 +1143,13 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_WithExistingVINNumber() err = vinNumb.Insert(s.ctx, s.pdb.DBS().Writer, boil.Infer()) s.Require().NoError(err) // mock needed for powertrain lookup - s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), dd.ID).Return( - &coremodels.DeviceDefinitionTablelandModel{ + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), dd.ID).Return( + &coremodels.Template{ ID: dd.ID, Model: dd.Model, Year: dd.Year, DeviceType: common.DefaultDeviceType, - Metadata: &coremodels.DeviceDefinitionMetadata{DeviceAttributes: []coremodels.DeviceTypeAttribute{ - {Name: "powertrain_type", Value: "ICE"}, - }}, + Attributes: map[string]any{"powertrain_type": "ICE"}, }, big.NewInt(1), nil) qryResult, err := s.queryHandler.Handle(s.ctx, &DecodeVINQuery{VIN: vin, Country: country}) @@ -786,8 +1180,8 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_InvalidVINYear_AutoIso() definitionID := "ford_escape_2017" s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil, nil) s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo("", "").Return("ICE") // normally this would return "" - s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return( - buildTestTblDD(definitionID, "Escape", 2021), nil, nil) + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + buildTestTemplate(definitionID, "Escape", 2021), nil, nil) wmiDb := &models.Wmi{ Wmi: vin[:3], ManufacturerName: dm.Name, @@ -827,8 +1221,8 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_InvalidStyleName_AutoIso definitionID := "ford_escape_2017" s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(vinDecodingInfoData, nil, nil) s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo("1", "").Return("ICE") - s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return( - buildTestTblDD(definitionID, "Escape", 2017), nil, nil) + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + buildTestTemplate(definitionID, "Escape", 2017), nil, nil) wmiDb := &models.Wmi{ Wmi: vin[:3], ManufacturerName: dm.Name, @@ -885,8 +1279,8 @@ func (s *DecodeVINQueryHandlerSuite) TestHandle_Success_DecodeKnownFallback() { s.mockVINService.EXPECT().GetVIN(ctx, vin, coremodels.AllProviders, "USA").Times(1).Return(nil, nil, fmt.Errorf("unable to decode")) s.mockPowerTrainTypeService.EXPECT().ResolvePowerTrainFromVinInfo("", "").Return("ICE") - s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), definitionID).Return( - buildTestTblDD(definitionID, "Bronco", 20222), nil, nil) + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + buildTestTemplate(definitionID, "Bronco", 20222), nil, nil) image := gateways.FuelImage{ SourceURL: "https://image", @@ -980,18 +1374,16 @@ func (s *DecodeVINQueryHandlerSuite) TestDecodeVINQueryHandler_vinInfoFromKnown_ // mock call to get definition by id definitionID := "ford_escape_2020" - s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), gomock.AnyOf("lincoln_escape_2020", definitionID)).AnyTimes().Return(&coremodels.DeviceDefinitionTablelandModel{ + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), gomock.AnyOf("lincoln_escape_2020", definitionID)).AnyTimes().Return(&coremodels.Template{ ID: definitionID, - KSUID: ksuid.New().String(), Model: "Escape", Year: 2020, DeviceType: common.DefaultDeviceType, ImageURI: "", - Metadata: nil, }, nil, nil) - //s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), "lincoln_escape_2020").AnyTimes().Return(nil, nil, fmt.Errorf("not found")) + //s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), "lincoln_escape_2020").AnyTimes().Return(nil, nil, fmt.Errorf("not found")) - got, err := s.queryHandler.vinInfoFromKnown(v, "Escape", 2020) + got, err := s.queryHandler.vinInfoFromKnown(s.ctx, v, "Escape", 2020) require.NoError(s.T(), err) assert.Equal(s.T(), "1FMCU0G61MUA52727", got.VIN) assert.Equal(s.T(), "Ford", got.Make) @@ -1011,7 +1403,7 @@ func (s *DecodeVINQueryHandlerSuite) TestDecodeVINQueryHandler_vinInfoFromKnown_ err := wmi1.Insert(s.ctx, s.pdb.DBS().Writer, boil.Infer()) require.NoError(s.T(), err) - got, err := s.queryHandler.vinInfoFromKnown(v, "Escape", 2020) + got, err := s.queryHandler.vinInfoFromKnown(s.ctx, v, "Escape", 2020) require.NoError(s.T(), err) assert.Equal(s.T(), "1FMCU0G61MUA52727", got.VIN) assert.Equal(s.T(), "Ford", got.Make) @@ -1037,9 +1429,215 @@ func (s *DecodeVINQueryHandlerSuite) TestDecodeVINQueryHandler_vinInfoFromKnown_ require.NoError(s.T(), err) // mock call to get definition by id definitionID := "ford_escape_2020" - s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), gomock.AnyOf("lincoln_escape_2020", definitionID)).Times(2).Return(nil, nil, fmt.Errorf("not found")) + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), gomock.AnyOf("lincoln_escape_2020", definitionID)).Times(2).Return(nil, nil, fmt.Errorf("not found")) - got, err := s.queryHandler.vinInfoFromKnown(v, "Escape", 2020) + got, err := s.queryHandler.vinInfoFromKnown(s.ctx, v, "Escape", 2020) require.Error(s.T(), err, "vinInfoFromKnown: unable to determine the right OEM between Ford, Lincoln for WMI %s 1FM") require.Nil(s.T(), got) } + +// buildTrimOnlyPowertrainTemplate is the shape the extraction actually emits +// for a model-year sold in more than one powertrain: powertrain_type lives on +// the trims, NOT at the template level, because the trims disagree about it. +// A template-level lookup finds nothing here, which is the whole reason the +// cached decode path has to run the matcher rather than read Attributes. +func buildTrimOnlyPowertrainTemplate(definitionID, model string, year, version int) *coremodels.Template { + return &coremodels.Template{ + ID: definitionID, + Model: model, + Year: year, + DeviceType: "vehicle", + Version: version, + HardwareTemplateID: "130", + Attributes: map[string]any{"number_of_doors": float64(4)}, + Trims: []coremodels.Trim{ + { + Name: "LE", + Selectors: coremodels.TrimSelectors{ManufacturerCode: []string{"2532"}}, + Attributes: map[string]any{"powertrain_type": "ICE", "fuel_tank_capacity_gal": 16.0}, + }, + { + Name: "Hybrid LE", + Selectors: coremodels.TrimSelectors{ManufacturerCode: []string{"2559"}}, + HardwareTemplateID: "115", + Attributes: map[string]any{"powertrain_type": "HEV", "fuel_tank_capacity_gal": 13.2}, + }, + }, + } +} + +// The cached path -- the one every VIN takes from its second decode onward -- +// must answer with the same trim, quality and powertrain a fresh decode would. +// Before this was wired up it returned an empty match_quality and read +// powertrain from template-level attributes only, which on a multi-trim +// template finds nothing and falls through to a make/model heuristic: the +// blended answer this migration exists to replace, served to the majority of +// traffic while the freshly-decoded path returned the right one. +func (s *DecodeVINQueryHandlerSuite) TestHandle_ExistingVINNumber_ResolvesTrimLikeAFreshDecode() { + const vin = "1FMCU0G61MUA52727" // ford escape 2021 + const definitionID = "ford_escape_2021" + + dm := dbtesthelper.SetupCreateMake("Ford") + _ = dbtesthelper.SetupCreateWMI(s.T(), "1FM", dm.Name, s.pdb) + + v := vinutil.VIN(vin) + vinNumb := models.VinNumber{ + Vin: vin, + Wmi: null.StringFrom(v.Wmi()), + VDS: null.StringFrom(v.VDS()), + CheckDigit: null.StringFrom(v.CheckDigit()), + SerialNumber: v.SerialNumber(), + Vis: null.StringFrom(v.VIS()), + ManufacturerName: dm.Name, + DefinitionID: definitionID, + Year: 2021, + DecodeProvider: null.StringFrom("drivly"), + // The marshalled DrivlyVINResponse saveVinDecodeNumber persisted; it + // is the same payload vinInfo.ManufacturerCode was read from on the + // fresh decode, so the cached path can recover the signal from it. + DrivlyData: null.JSONFrom([]byte(`{"vin":"1FMCU0G61MUA52727","manufacturerCode":"2559","trim":"Hybrid LE"}`)), + } + s.Require().NoError(vinNumb.Insert(s.ctx, s.pdb.DBS().Writer, boil.Infer())) + + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + buildTrimOnlyPowertrainTemplate(definitionID, "Escape", 2021, 3), big.NewInt(1), nil) + + qryResult, err := s.queryHandler.Handle(s.ctx, &DecodeVINQuery{VIN: vin, Country: country}) + s.NoError(err) + s.Require().NotNil(qryResult) + + s.Assert().Equal("Hybrid LE", qryResult.Trim) + s.Assert().Equal("exact", qryResult.MatchQuality) + s.Assert().Equal(int32(3), qryResult.TemplateVersion) + s.Assert().Equal([]string{"manufacturerCode"}, qryResult.MatchBy) + // From the matched trim, not from the template and not from a heuristic. + s.Assert().Equal("HEV", qryResult.Powertrain) + // The trim's hardware override wins over the template's default. + s.Assert().Equal("115", qryResult.HardwareTemplateId) + s.Assert().Empty(qryResult.MatchCandidates) +} + +// The cached path's styleName signal comes from the persisted device_styles +// row, which is where processDeviceStyle wrote the decoded style name. A +// styleName-keyed template must therefore resolve on a cached decode exactly +// as it does on a fresh one. +func (s *DecodeVINQueryHandlerSuite) TestHandle_ExistingVINNumber_MatchesOnPersistedStyleName() { + const vin = "1FMCU0G61MUA52727" + const definitionID = "ford_escape_2021" + + dm := dbtesthelper.SetupCreateMake("Ford") + _ = dbtesthelper.SetupCreateWMI(s.T(), "1FM", dm.Name, s.pdb) + style := dbtesthelper.SetupCreateStyle(s.T(), definitionID, "Hybrid LE", "drivly", "Hybrid LE", s.pdb) + + tmpl := buildTrimOnlyPowertrainTemplate(definitionID, "Escape", 2021, 4) + // A styleName-keyed template, the shape the extraction is expected to + // emit once it stops keying trims on manufacturerCode alone. + tmpl.Trims[0].Selectors = coremodels.TrimSelectors{StyleName: []string{"LE"}} + tmpl.Trims[1].Selectors = coremodels.TrimSelectors{StyleName: []string{"Hybrid LE"}} + + v := vinutil.VIN(vin) + vinNumb := models.VinNumber{ + Vin: vin, + Wmi: null.StringFrom(v.Wmi()), + VDS: null.StringFrom(v.VDS()), + CheckDigit: null.StringFrom(v.CheckDigit()), + SerialNumber: v.SerialNumber(), + Vis: null.StringFrom(v.VIS()), + ManufacturerName: dm.Name, + DefinitionID: definitionID, + Year: 2021, + DecodeProvider: null.StringFrom("drivly"), + StyleID: null.StringFrom(style.ID), + } + s.Require().NoError(vinNumb.Insert(s.ctx, s.pdb.DBS().Writer, boil.Infer())) + + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return(tmpl, big.NewInt(1), nil) + + qryResult, err := s.queryHandler.Handle(s.ctx, &DecodeVINQuery{VIN: vin, Country: country}) + s.NoError(err) + s.Require().NotNil(qryResult) + + s.Assert().Equal("Hybrid LE", qryResult.Trim) + s.Assert().Equal("exact", qryResult.MatchQuality) + s.Assert().Equal([]string{"styleName"}, qryResult.MatchBy) + s.Assert().Equal("HEV", qryResult.Powertrain) +} + +// When no signal narrows the template, the cached path says model-only and +// reports no powertrain -- the same answer, and the same silence, the fresh +// path gives. It must not reach for a make/model heuristic just because it +// happens to have a manufacturer id in hand. +func (s *DecodeVINQueryHandlerSuite) TestHandle_ExistingVINNumber_NoSignalIsModelOnlyWithNoPowertrain() { + const vin = "1FMCU0G61MUA52727" + const definitionID = "ford_escape_2021" + + dm := dbtesthelper.SetupCreateMake("Ford") + _ = dbtesthelper.SetupCreateWMI(s.T(), "1FM", dm.Name, s.pdb) + + v := vinutil.VIN(vin) + vinNumb := models.VinNumber{ + Vin: vin, + Wmi: null.StringFrom(v.Wmi()), + VDS: null.StringFrom(v.VDS()), + CheckDigit: null.StringFrom(v.CheckDigit()), + SerialNumber: v.SerialNumber(), + Vis: null.StringFrom(v.VIS()), + ManufacturerName: dm.Name, + DefinitionID: definitionID, + Year: 2021, + // vincario supplies no manufacturer code and stored no drivly payload. + DecodeProvider: null.StringFrom("vincario"), + } + s.Require().NoError(vinNumb.Insert(s.ctx, s.pdb.DBS().Writer, boil.Infer())) + + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + buildTrimOnlyPowertrainTemplate(definitionID, "Escape", 2021, 3), big.NewInt(1), nil) + + qryResult, err := s.queryHandler.Handle(s.ctx, &DecodeVINQuery{VIN: vin, Country: country}) + s.NoError(err) + s.Require().NotNil(qryResult) + + s.Assert().Equal("model-only", qryResult.MatchQuality) + s.Assert().Empty(qryResult.Trim) + s.Assert().Empty(qryResult.Powertrain, "no trim matched, so no trim's powertrain may leak into the response") + // The template's default, never a candidate trim's override. + s.Assert().Equal("130", qryResult.HardwareTemplateId) +} + +// match_quality has three values, all of which assert that the matcher ran. +// When it could not run at all -- no template to match against -- the field +// stays empty rather than claiming "model-only", which would assert that a +// real template was read and nothing in it matched. +func (s *DecodeVINQueryHandlerSuite) TestHandle_ExistingVINNumber_NoTemplateLeavesMatchQualityEmpty() { + const vin = "1FMCU0G61MUA52727" + const definitionID = "ford_escape_2021" + + dm := dbtesthelper.SetupCreateMake("Ford") + _ = dbtesthelper.SetupCreateWMI(s.T(), "1FM", dm.Name, s.pdb) + + v := vinutil.VIN(vin) + vinNumb := models.VinNumber{ + Vin: vin, + Wmi: null.StringFrom(v.Wmi()), + VDS: null.StringFrom(v.VDS()), + CheckDigit: null.StringFrom(v.CheckDigit()), + SerialNumber: v.SerialNumber(), + Vis: null.StringFrom(v.VIS()), + ManufacturerName: dm.Name, + DefinitionID: definitionID, + Year: 2021, + DecodeProvider: null.StringFrom("drivly"), + } + s.Require().NoError(vinNumb.Insert(s.ctx, s.pdb.DBS().Writer, boil.Infer())) + + s.mockDeviceDefinitionCatalogService.EXPECT().GetTemplateByID(gomock.Any(), definitionID).Return( + nil, nil, gateways.ErrTemplateNotFound) + + qryResult, err := s.queryHandler.Handle(s.ctx, &DecodeVINQuery{VIN: vin, Country: country}) + s.NoError(err) + s.Require().NotNil(qryResult) + + s.Assert().Empty(qryResult.MatchQuality) + s.Assert().Empty(qryResult.Trim) + s.Assert().Equal(definitionID, qryResult.DefinitionId) +} diff --git a/internal/core/queries/decode_vin_tx_test.go b/internal/core/queries/decode_vin_tx_test.go new file mode 100644 index 00000000..074ff7de --- /dev/null +++ b/internal/core/queries/decode_vin_tx_test.go @@ -0,0 +1,123 @@ +package queries + +import ( + "context" + "database/sql" + "errors" + "testing" + + sqlmock "github.com/DATA-DOG/go-sqlmock" + "github.com/DIMO-Network/shared/pkg/db" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// Handle reads the cached vin_numbers row inside a SERIALIZABLE transaction on +// the writer, and used to keep that transaction open across +// hydrateResponseFromVinNumber. That function was pure in-memory when the +// transaction was placed around it; it now issues a catalog GET through a +// client with a 30 second timeout and a device_styles query against the +// reader, and returns early on a cache hit -- the path the code itself calls +// "the one most decodes take". So the commonest decode held a writer +// connection and a serializable snapshot across a full CDN round trip, and +// took a reader connection while holding it: a two second catalog stall pins +// every writer connection for two seconds per decode, and a thirty second +// stall exhausts the pool outright while unrelated writes queue behind it. +// +// The fix is to read the row, end the transaction, then hydrate. These pin the +// first half of that: readCachedVinNumber has ended its transaction by the +// time it returns, on every path -- a row, no row, a failed query, a failed +// begin. Nothing slow can then run inside it, because there is no inside. +// +// No Postgres: sqlmock answers the read and records that the rollback happened +// before the call returned. + +func mockDBS(t *testing.T) (func() *db.ReaderWriter, sqlmock.Sqlmock) { + t.Helper() + sqlDB, mock, err := sqlmock.New() + require.NoError(t, err) + t.Cleanup(func() { _ = sqlDB.Close() }) + rw := &db.ReaderWriter{Reader: &db.DB{DB: sqlDB}, Writer: &db.DB{DB: sqlDB}} + return func() *db.ReaderWriter { return rw }, mock +} + +func txHandler(t *testing.T) (DecodeVINQueryHandler, sqlmock.Sqlmock) { + t.Helper() + dbs, mock := mockDBS(t) + logger := zerolog.Nop() + return DecodeVINQueryHandler{dbs: dbs, logger: &logger}, mock +} + +const txTestVIN = "4T1C11AK8NU123456" + +func TestReadCachedVinNumberEndsItsTransactionBeforeItReturns(t *testing.T) { + dc, mock := txHandler(t) + mock.ExpectBegin() + mock.ExpectQuery(`SELECT .* FROM .*vin_numbers.* WHERE`). + WithArgs(txTestVIN). + WillReturnRows(sqlmock.NewRows([]string{"vin", "definition_id", "year", "manufacturer_name"}). + AddRow(txTestVIN, "toyota_camry_2026", 2026, "Toyota")) + mock.ExpectRollback() + + vn, err := dc.readCachedVinNumber(context.Background(), txTestVIN) + + require.NoError(t, err) + require.NotNil(t, vn) + assert.Equal(t, "toyota_camry_2026", vn.DefinitionID) + // The whole point: by the time the caller has the row, the writer + // connection and the serializable snapshot are already released, so the + // catalog round trip that follows holds neither. + assert.NoError(t, mock.ExpectationsWereMet(), "the transaction must be closed before hydration starts") +} + +// A VIN that has never been decoded is the path that goes on to do the whole +// decode -- several HTTP calls to vendors -- so leaving the transaction open +// here would be the worst case of all. +func TestReadCachedVinNumberEndsItsTransactionWhenThereIsNoRow(t *testing.T) { + dc, mock := txHandler(t) + mock.ExpectBegin() + mock.ExpectQuery(`SELECT .* FROM .*vin_numbers.* WHERE`). + WithArgs(txTestVIN). + WillReturnError(sql.ErrNoRows) + mock.ExpectRollback() + + vn, err := dc.readCachedVinNumber(context.Background(), txTestVIN) + + require.NoError(t, err, "no cached row is not an error, it is the uncached decode") + assert.Nil(t, vn) + assert.NoError(t, mock.ExpectationsWereMet()) +} + +// Not just the happy path: a failed read must not leak the transaction either. +func TestReadCachedVinNumberEndsItsTransactionWhenTheQueryFails(t *testing.T) { + dc, mock := txHandler(t) + boom := errors.New("connection reset by peer") + mock.ExpectBegin() + mock.ExpectQuery(`SELECT .* FROM .*vin_numbers.* WHERE`). + WithArgs(txTestVIN). + WillReturnError(boom) + mock.ExpectRollback() + + vn, err := dc.readCachedVinNumber(context.Background(), txTestVIN) + + require.Error(t, err) + assert.Nil(t, vn) + assert.ErrorIs(t, err, boom) + assert.NoError(t, mock.ExpectationsWereMet()) +} + +// A transaction that never began has nothing to close, and must not be +// reported as a decode failure of some other kind. +func TestReadCachedVinNumberReportsAFailedBegin(t *testing.T) { + dc, mock := txHandler(t) + boom := errors.New("too many connections") + mock.ExpectBegin().WillReturnError(boom) + + vn, err := dc.readCachedVinNumber(context.Background(), txTestVIN) + + require.Error(t, err) + assert.Nil(t, vn) + assert.ErrorIs(t, err, boom) + assert.NoError(t, mock.ExpectationsWereMet()) +} diff --git a/internal/core/queries/get_compatibility_r1.go b/internal/core/queries/get_compatibility_r1.go index 7f2b5c56..87457bfd 100644 --- a/internal/core/queries/get_compatibility_r1.go +++ b/internal/core/queries/get_compatibility_r1.go @@ -99,8 +99,16 @@ func getCompatibilityR1SheetData(ctx context.Context, settings *config.Settings) yr, _ := strconv.Atoi(fmt.Sprintf("%v", row[2])) compat := fmt.Sprintf("%v", row[3]) + definitionID, err := common.DeviceDefinitionSlug(stringutils.SlugString(mk), stringutils.SlugString(model), int16(yr)) + if err != nil { + // A row whose make/model yields an id no template can exist + // at describes a definition the catalog can never hold, so + // serving it would only send the caller to look one up that + // 404s forever. Skip the row and keep the rest of the sheet. + continue + } rows = append(rows, CompatibilitySheetRow{ - DefinitionID: common.DeviceDefinitionSlug(stringutils.SlugString(mk), stringutils.SlugString(model), int16(yr)), + DefinitionID: definitionID, Make: mk, Model: model, Year: yr, diff --git a/internal/core/queries/get_dd_by_autocomplete.go b/internal/core/queries/get_dd_by_autocomplete.go index 5df400a1..7c79997f 100644 --- a/internal/core/queries/get_dd_by_autocomplete.go +++ b/internal/core/queries/get_dd_by_autocomplete.go @@ -5,7 +5,6 @@ import ( "github.com/DIMO-Network/device-definitions-api/internal/core/mediator" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/search" - "github.com/mitchellh/mapstructure" ) type GetAllDeviceDefinitionByAutocompleteQuery struct { @@ -43,18 +42,30 @@ func (ch GetAllDeviceDefinitionByAutocompleteQueryHandler) Handle(ctx context.Co return nil, err } - deviceDefinitions := make([]GetAllDeviceDefinitionAutocompleteItem, 0, len(*result.Hits)) - for _, hit := range *result.Hits { - var doc map[string]interface{} - if err := mapstructure.Decode(hit.Document, &doc); err != nil { + // firstHitPerGroup, not *result.Hits: Autocomplete groups on definition_id, + // and Typesense returns a grouped search in grouped_hits with hits unset -- + // so the old dereference of result.Hits was both a nil panic and, ungrouped, + // ten trims of the same definition. + hits := firstHitPerGroup(result) + deviceDefinitions := make([]GetAllDeviceDefinitionAutocompleteItem, 0, len(hits)) + for _, hit := range hits { + if hit.Document == nil { continue } + doc := *hit.Document - item := GetAllDeviceDefinitionAutocompleteItem{ - ID: doc["id"].(string), - Name: doc["name"].(string), + // docString and definitionName rather than bare type assertions: the + // documents are untyped maps, a missing key panics on assertion, and the + // per-trim document's own name carries the trim ("2020 Toyota Camry LE") + // while this endpoint lists definitions. + id := docString(doc, "definition_id") + if id == "" { + continue } - deviceDefinitions = append(deviceDefinitions, item) + deviceDefinitions = append(deviceDefinitions, GetAllDeviceDefinitionAutocompleteItem{ + ID: id, + Name: definitionName(doc), + }) } response := &GetAllDeviceDefinitionByAutocompleteQueryResult{ diff --git a/internal/core/queries/get_dd_by_autocomplete_test.go b/internal/core/queries/get_dd_by_autocomplete_test.go new file mode 100644 index 00000000..37c7278e --- /dev/null +++ b/internal/core/queries/get_dd_by_autocomplete_test.go @@ -0,0 +1,91 @@ +package queries + +import ( + "context" + "testing" + + mock_search "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/search/mocks" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +// Autocomplete groups on definition_id, so Typesense answers in grouped_hits +// with hits unset. The handler used to dereference result.Hits unconditionally, +// which panics on exactly this shape, and before grouping it listed one entry +// per trim -- ten identical "Toyota Camry" suggestions for one Camry. +func TestGetAllDeviceDefinitionByAutocompleteQuery_GroupedHits(t *testing.T) { + ctrl := gomock.NewController(t) + svc := mock_search.NewMockTypesenseAPIService(ctrl) + svc.EXPECT().Autocomplete(gomock.Any(), "camry"). + Return(searchResultFromJSON(t, workerGroupedSearchJSON), nil) + + handler := NewGetAllDeviceDefinitionByAutocompleteQueryHandler(svc) + out, err := handler.Handle(context.Background(), &GetAllDeviceDefinitionByAutocompleteQuery{Query: "camry"}) + require.NoError(t, err) + result, ok := out.(*GetAllDeviceDefinitionByAutocompleteQueryResult) + require.True(t, ok) + + // Two definitions, not the three trim documents behind them. + require.Len(t, result.Items, 2) + + // The id is the definition slug, not the per-trim document id + // ("toyota_camry_2020#LE"), and the label is the definition's name, not the + // leading trim's ("2020 Toyota Camry LE"). + assert.Equal(t, "toyota_camry_2020", result.Items[0].ID) + assert.Equal(t, "2020 Toyota Camry", result.Items[0].Name) + assert.Equal(t, "ford_f-150_2021", result.Items[1].ID) + assert.Equal(t, "2021 Ford F-150", result.Items[1].Name) +} + +// Ungrouped hits remain the fallback, and a document missing fields must decode +// to zero values rather than panic on a type assertion. +func TestGetAllDeviceDefinitionByAutocompleteQuery_UngroupedAndMissingFields(t *testing.T) { + ctrl := gomock.NewController(t) + svc := mock_search.NewMockTypesenseAPIService(ctrl) + svc.EXPECT().Autocomplete(gomock.Any(), "up"). + Return(searchResultFromJSON(t, `{ + "found": 2, + "hits": [ + {"document": {"id": "volkswagen_up_2019#Base", "definition_id": "volkswagen_up_2019", + "name": "2019 Volkswagen up", "make": "Volkswagen", "model": "up"}}, + {"document": {"id": "orphan#Base", "name": "no definition id here"}} + ] +}`), nil) + + handler := NewGetAllDeviceDefinitionByAutocompleteQueryHandler(svc) + var out interface{} + var err error + require.NotPanics(t, func() { + out, err = handler.Handle(context.Background(), &GetAllDeviceDefinitionByAutocompleteQuery{Query: "up"}) + }) + require.NoError(t, err) + result := out.(*GetAllDeviceDefinitionByAutocompleteQueryResult) + + // The document with no definition_id is dropped: an autocomplete entry whose + // id cannot be looked up is not a usable suggestion. + require.Len(t, result.Items, 1) + assert.Equal(t, "volkswagen_up_2019", result.Items[0].ID) + // year is absent, so definitionName falls back to the document's own name. + assert.Equal(t, "2019 Volkswagen up", result.Items[0].Name) +} + +// An empty result set must produce an empty list, not null, and must not panic +// on the absent hits/grouped_hits fields. +func TestGetAllDeviceDefinitionByAutocompleteQuery_NoHits(t *testing.T) { + ctrl := gomock.NewController(t) + svc := mock_search.NewMockTypesenseAPIService(ctrl) + svc.EXPECT().Autocomplete(gomock.Any(), "zzzz"). + Return(searchResultFromJSON(t, `{"found": 0}`), nil) + + handler := NewGetAllDeviceDefinitionByAutocompleteQueryHandler(svc) + var out interface{} + var err error + require.NotPanics(t, func() { + out, err = handler.Handle(context.Background(), &GetAllDeviceDefinitionByAutocompleteQuery{Query: "zzzz"}) + }) + require.NoError(t, err) + result := out.(*GetAllDeviceDefinitionByAutocompleteQueryResult) + assert.NotNil(t, result.Items) + assert.Empty(t, result.Items) +} diff --git a/internal/core/queries/get_dd_by_id.go b/internal/core/queries/get_dd_by_id.go index 11fe2004..fd5274da 100644 --- a/internal/core/queries/get_dd_by_id.go +++ b/internal/core/queries/get_dd_by_id.go @@ -2,6 +2,7 @@ package queries import ( "context" + "errors" "fmt" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" @@ -19,12 +20,12 @@ func (*GetDeviceDefinitionByIDQuery) Key() string { return "GetDeviceDefinitionB type GetDeviceDefinitionByIDQueryHandler struct { dbs func() *db.ReaderWriter - onChainSvc gateways.DeviceDefinitionOnChainService + catalogSvc gateways.DeviceDefinitionCatalogService } -func NewGetDeviceDefinitionByIDQueryHandler(onChainSvc gateways.DeviceDefinitionOnChainService, dbs func() *db.ReaderWriter) GetDeviceDefinitionByIDQueryHandler { +func NewGetDeviceDefinitionByIDQueryHandler(catalogSvc gateways.DeviceDefinitionCatalogService, dbs func() *db.ReaderWriter) GetDeviceDefinitionByIDQueryHandler { return GetDeviceDefinitionByIDQueryHandler{ - onChainSvc: onChainSvc, + catalogSvc: catalogSvc, dbs: dbs, } } @@ -33,10 +34,25 @@ func (ch GetDeviceDefinitionByIDQueryHandler) Handle(ctx context.Context, query qry := query.(*GetDeviceDefinitionByIDQuery) - dd, _, err := ch.onChainSvc.GetDefinitionByID(ctx, qry.DeviceDefinitionID) + dd, _, err := ch.catalogSvc.GetTemplateByID(ctx, qry.DeviceDefinitionID) if err != nil { - return nil, err + // GetTemplateByID reports a genuine "does not exist" as the wrapped + // ErrTemplateNotFound sentinel, and the HTTP layer maps a not-found by + // type assertion on *exceptions.NotFoundError, which a wrapped + // sentinel never satisfies. Returning it raw answered 500 for every + // unknown id, where the pre-migration on-chain path answered 404. + // Anything else is a catalog outage and stays an internal error: a + // caller reacting to a spurious 404 could create a duplicate + // definition for a vehicle that already exists. + if errors.Is(err, gateways.ErrTemplateNotFound) { + return nil, &exceptions.NotFoundError{ + Err: fmt.Errorf("could not find device definition id: %s: %w", qry.DeviceDefinitionID, err), + } + } + return nil, &exceptions.InternalError{ + Err: fmt.Errorf("failed to get device definition %s from catalog: %w", qry.DeviceDefinitionID, err), + } } if dd == nil { diff --git a/internal/core/queries/get_dd_by_id_test.go b/internal/core/queries/get_dd_by_id_test.go new file mode 100644 index 00000000..cd647d16 --- /dev/null +++ b/internal/core/queries/get_dd_by_id_test.go @@ -0,0 +1,99 @@ +package queries + +import ( + "context" + "testing" + + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" + "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/exceptions" + "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" + mock_gateways "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways/mocks" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +// GET /device-definitions/:id has no database of its own: it is the catalog +// read and the mapping of its error, which is the whole of what these check. +// The HTTP layer maps a not-found by type assertion (internal/api/common/ +// config.go), which a wrapped sentinel never satisfies, so the handler has to +// do the errors.Is check itself. + +const unknownDefinitionID = "ford_escapexx_2020" + +func catalogMockFor(t *testing.T) *mock_gateways.MockDeviceDefinitionCatalogService { + t.Helper() + ctrl := gomock.NewController(t) + t.Cleanup(ctrl.Finish) + return mock_gateways.NewMockDeviceDefinitionCatalogService(ctrl) +} + +func TestGetDeviceDefinitionByIDAnswersNotFoundForAnUnknownID(t *testing.T) { + catalog := catalogMockFor(t) + catalog.EXPECT().GetTemplateByID(gomock.Any(), unknownDefinitionID). + Return(nil, nil, errors.Wrapf(gateways.ErrTemplateNotFound, "template %q", unknownDefinitionID)) + + got, err := NewGetDeviceDefinitionByIDQueryHandler(catalog, nil). + Handle(context.Background(), &GetDeviceDefinitionByIDQuery{DeviceDefinitionID: unknownDefinitionID}) + + require.Error(t, err) + assert.Nil(t, got) + var notFound *exceptions.NotFoundError + assert.ErrorAs(t, err, ¬Found, "an unknown id is a 404, and the HTTP layer only maps this type") +} + +func TestGetDeviceDefinitionByIDDoesNotReportACatalogOutageAsNotFound(t *testing.T) { + catalog := catalogMockFor(t) + catalog.EXPECT().GetTemplateByID(gomock.Any(), unknownDefinitionID). + Return(nil, nil, errors.New("unexpected status 502 from catalog")) + + got, err := NewGetDeviceDefinitionByIDQueryHandler(catalog, nil). + Handle(context.Background(), &GetDeviceDefinitionByIDQuery{DeviceDefinitionID: unknownDefinitionID}) + + require.Error(t, err) + assert.Nil(t, got) + var notFound *exceptions.NotFoundError + assert.NotErrorAs(t, err, ¬Found, "a catalog outage must not be reported as a missing definition") +} + +func TestGetDeviceDefinitionByIDReturnsTheTemplate(t *testing.T) { + catalog := catalogMockFor(t) + catalog.EXPECT().GetTemplateByID(gomock.Any(), "toyota_camry_2026").Return(hydrateTemplate(), nil, nil) + + got, err := NewGetDeviceDefinitionByIDQueryHandler(catalog, nil). + Handle(context.Background(), &GetDeviceDefinitionByIDQuery{DeviceDefinitionID: "toyota_camry_2026"}) + + require.NoError(t, err) + tmpl, ok := got.(*coremodels.Template) + require.True(t, ok) + assert.Equal(t, "toyota_camry_2026", tmpl.ID) +} + +func TestGetDeviceDefinitionByIDV2AnswersNotFoundForAnUnknownID(t *testing.T) { + catalog := catalogMockFor(t) + catalog.EXPECT().GetTemplateByID(gomock.Any(), unknownDefinitionID). + Return(nil, nil, errors.Wrapf(gateways.ErrTemplateNotFound, "template %q", unknownDefinitionID)) + + got, err := NewGetDeviceDefinitionByIDQueryV2Handler(catalog, nil). + Handle(context.Background(), &GetDeviceDefinitionByIDQueryV2{DefinitionID: unknownDefinitionID}) + + require.Error(t, err) + assert.Nil(t, got) + var notFound *exceptions.NotFoundError + assert.ErrorAs(t, err, ¬Found, "an unknown id is a 404, and the HTTP layer only maps this type") +} + +func TestGetDeviceDefinitionByIDV2DoesNotReportACatalogOutageAsNotFound(t *testing.T) { + catalog := catalogMockFor(t) + catalog.EXPECT().GetTemplateByID(gomock.Any(), unknownDefinitionID). + Return(nil, nil, errors.New("unexpected status 502 from catalog")) + + got, err := NewGetDeviceDefinitionByIDQueryV2Handler(catalog, nil). + Handle(context.Background(), &GetDeviceDefinitionByIDQueryV2{DefinitionID: unknownDefinitionID}) + + require.Error(t, err) + assert.Nil(t, got) + var notFound *exceptions.NotFoundError + assert.NotErrorAs(t, err, ¬Found, "a catalog outage must not be reported as a missing definition") +} diff --git a/internal/core/queries/get_dd_by_id_v2.go b/internal/core/queries/get_dd_by_id_v2.go index fea5882b..dd88ec5d 100644 --- a/internal/core/queries/get_dd_by_id_v2.go +++ b/internal/core/queries/get_dd_by_id_v2.go @@ -2,6 +2,7 @@ package queries import ( "context" + "errors" "fmt" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" @@ -18,13 +19,13 @@ type GetDeviceDefinitionByIDQueryV2 struct { func (*GetDeviceDefinitionByIDQueryV2) Key() string { return "GetDeviceDefinitionByIdQueryV2" } type GetDeviceDefinitionByIDQueryV2Handler struct { - ddOnChainSvc gateways.DeviceDefinitionOnChainService + ddCatalogSvc gateways.DeviceDefinitionCatalogService dbs func() *db.ReaderWriter } -func NewGetDeviceDefinitionByIDQueryV2Handler(ddOnChainSvc gateways.DeviceDefinitionOnChainService, dbs func() *db.ReaderWriter) GetDeviceDefinitionByIDQueryV2Handler { +func NewGetDeviceDefinitionByIDQueryV2Handler(ddCatalogSvc gateways.DeviceDefinitionCatalogService, dbs func() *db.ReaderWriter) GetDeviceDefinitionByIDQueryV2Handler { return GetDeviceDefinitionByIDQueryV2Handler{ - ddOnChainSvc: ddOnChainSvc, + ddCatalogSvc: ddCatalogSvc, dbs: dbs, } } @@ -33,10 +34,25 @@ func (ch GetDeviceDefinitionByIDQueryV2Handler) Handle(ctx context.Context, quer qry := query.(*GetDeviceDefinitionByIDQueryV2) - dd, _, err := ch.ddOnChainSvc.GetDefinitionByID(ctx, qry.DefinitionID) + dd, _, err := ch.ddCatalogSvc.GetTemplateByID(ctx, qry.DefinitionID) if err != nil { - return nil, err + // GetTemplateByID reports a genuine "does not exist" as the wrapped + // ErrTemplateNotFound sentinel, and the HTTP layer maps a not-found by + // type assertion on *exceptions.NotFoundError, which a wrapped + // sentinel never satisfies. Returning it raw answered 500 for every + // unknown id, where the pre-migration on-chain path answered 404. + // Anything else is a catalog outage and stays an internal error: a + // caller reacting to a spurious 404 could create a duplicate + // definition for a vehicle that already exists. + if errors.Is(err, gateways.ErrTemplateNotFound) { + return nil, &exceptions.NotFoundError{ + Err: fmt.Errorf("could not find device definition id: %s: %w", qry.DefinitionID, err), + } + } + return nil, &exceptions.InternalError{ + Err: fmt.Errorf("failed to get device definition %s from catalog: %w", qry.DefinitionID, err), + } } if dd == nil { diff --git a/internal/core/queries/get_dd_by_make_model_year.go b/internal/core/queries/get_dd_by_make_model_year.go deleted file mode 100644 index 45431227..00000000 --- a/internal/core/queries/get_dd_by_make_model_year.go +++ /dev/null @@ -1,75 +0,0 @@ -package queries - -import ( - "context" - "fmt" - - "github.com/DIMO-Network/device-definitions-api/internal/core/common" - "github.com/DIMO-Network/device-definitions-api/internal/core/mediator" - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/db/models" - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/exceptions" - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" - "github.com/DIMO-Network/shared/pkg/db" - stringutils "github.com/DIMO-Network/shared/pkg/strings" - "github.com/aarondl/sqlboiler/v4/types" - "github.com/ericlagergren/decimal" -) - -type GetDeviceDefinitionByMakeModelYearQuery struct { - Make string `json:"make" validate:"required"` - Model string `json:"model" validate:"required"` - Year int `json:"year" validate:"required"` -} - -func (*GetDeviceDefinitionByMakeModelYearQuery) Key() string { - return "GetDeviceDefinitionByMakeModelYearQuery" -} - -type GetDeviceDefinitionByMakeModelYearQueryHandler struct { - dbs func() *db.ReaderWriter - onChainSvc gateways.DeviceDefinitionOnChainService - identity gateways.IdentityAPI -} - -func NewGetDeviceDefinitionByMakeModelYearQueryHandler(onChainSvc gateways.DeviceDefinitionOnChainService, dbs func() *db.ReaderWriter, identity gateways.IdentityAPI) GetDeviceDefinitionByMakeModelYearQueryHandler { - return GetDeviceDefinitionByMakeModelYearQueryHandler{ - onChainSvc: onChainSvc, - dbs: dbs, - identity: identity, - } -} - -func (ch GetDeviceDefinitionByMakeModelYearQueryHandler) Handle(ctx context.Context, query mediator.Message) (interface{}, error) { - - qry := query.(*GetDeviceDefinitionByMakeModelYearQuery) - makeSlug := stringutils.SlugString(qry.Make) - manufacturer, err := ch.onChainSvc.GetManufacturer(makeSlug) - if err != nil { - return nil, err - } - - manufacturerID := types.NewNullDecimal(decimal.New(int64(manufacturer.TokenID), 0)) - definitions, err := ch.onChainSvc.GetDeviceDefinitions(ctx, manufacturerID, "", qry.Model, qry.Year, 0, 100) - if err != nil { - return nil, err - } - - if len(definitions) == 0 { - return nil, &exceptions.NotFoundError{ - Err: fmt.Errorf("could not find device definition with MMY: %s %s %d", qry.Make, qry.Model, qry.Year), - } - } - dm, err := ch.identity.GetManufacturer(makeSlug) - if err != nil { - return nil, err - } - dss, _ := models.DeviceStyles(models.DeviceStyleWhere.DefinitionID.EQ(definitions[0].ID)).All(ctx, ch.dbs().Reader) - trx, _ := models.DefinitionTransactions(models.DefinitionTransactionWhere.DefinitionID.EQ(definitions[0].ID)).All(ctx, ch.dbs().Reader) - - queryResult, err := common.BuildFromDeviceDefinitionToQueryResult(&definitions[0], dm, dss, trx) - if err != nil { - return nil, err - } - - return queryResult, nil -} diff --git a/internal/core/queries/get_dd_by_search.go b/internal/core/queries/get_dd_by_search.go index a640e3d3..ebae1280 100644 --- a/internal/core/queries/get_dd_by_search.go +++ b/internal/core/queries/get_dd_by_search.go @@ -3,9 +3,10 @@ package queries import ( "context" + "github.com/DIMO-Network/device-definitions-api/internal/core/common" "github.com/DIMO-Network/device-definitions-api/internal/core/mediator" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/search" - "github.com/mitchellh/mapstructure" + "github.com/typesense/typesense-go/typesense/api" ) type GetAllDeviceDefinitionBySearchQuery struct { @@ -74,30 +75,44 @@ func (ch GetAllDeviceDefinitionBySearchQueryHandler) Handle(ctx context.Context, return nil, err } - deviceDefinitions := make([]GetAllDeviceDefinitionItem, 0, len(*result.Hits)) - for _, hit := range *result.Hits { - var doc map[string]interface{} - if err := mapstructure.Decode(hit.Document, &doc); err != nil { + hits := firstHitPerGroup(result) + deviceDefinitions := make([]GetAllDeviceDefinitionItem, 0, len(hits)) + for _, hit := range hits { + if hit.Document == nil { continue } + doc := *hit.Document + id := docString(doc, "definition_id") item := GetAllDeviceDefinitionItem{ - ID: doc["definition_id"].(string), // new slug id - DeviceDefinitionID: doc["device_definition_id"].(string), - Name: doc["name"].(string), - Make: doc["make"].(string), - //ManufacturerTokenID: int(doc["manufacturer_token_id"].(float64)), - Model: doc["model"].(string), - Year: int(doc["year"].(float64)), - ImageURL: doc["image_url"].(string), + ID: id, + // Legacy ksuids no longer exist and the index carries no + // device_definition_id. The field stays on the wire for + // compatibility and carries the slug id, the only id there is. + DeviceDefinitionID: id, + Name: definitionName(doc), + Make: docString(doc, "make"), + Model: docString(doc, "model"), + Year: docInt(doc, "year"), + ImageURL: docString(doc, "image_url"), } deviceDefinitions = append(deviceDefinitions, item) } + // Facet counts are per document and the index holds one document per + // trim, so each count is trims, not definitions: Typesense does not count + // groups. var makes []GetAllDeviceDefinitionFacetItem var models []GetAllDeviceDefinitionFacetItem var years []GetAllDeviceDefinitionFacetItem - for _, facet := range *result.FacetCounts { + var facetCounts []api.FacetCounts + if result.FacetCounts != nil { + facetCounts = *result.FacetCounts + } + for _, facet := range facetCounts { + if facet.Counts == nil || facet.FieldName == nil { + continue + } for _, count := range *facet.Counts { if *facet.FieldName == "make" { makes = append(makes, GetAllDeviceDefinitionFacetItem{ @@ -126,11 +141,15 @@ func (ch GetAllDeviceDefinitionBySearchQueryHandler) Handle(ctx context.Context, Years: years, } + found := 0 + if result.Found != nil { + found = *result.Found + } pagination := GetAllDeviceDefinitionPagination{ Page: qry.Page, PageSize: qry.PageSize, - TotalItems: *result.Found, - TotalPages: (*result.Found + qry.PageSize - 1) / qry.PageSize, + TotalItems: found, + TotalPages: (found + qry.PageSize - 1) / qry.PageSize, } response := &GetAllDeviceDefinitionBySearchQueryResult{ @@ -154,3 +173,57 @@ func (ch GetAllDeviceDefinitionBySearchQueryHandler) Handle(ctx context.Context, return response, nil } + +// firstHitPerGroup flattens a group_by=definition_id result to one hit per +// definition. The worker indexes one document per trim, so without grouping a +// query for "camry" returns toyota_camry_2020 once per trim; the endpoint's +// contract is one item per definition. Ungrouped hits are the fallback so a +// fake, or an index queried without group_by, still works. +func firstHitPerGroup(result *api.SearchResult) []api.SearchResultHit { + if result.GroupedHits != nil { + hits := make([]api.SearchResultHit, 0, len(*result.GroupedHits)) + for _, group := range *result.GroupedHits { + if len(group.Hits) > 0 { + hits = append(hits, group.Hits[0]) + } + } + return hits + } + if result.Hits != nil { + return *result.Hits + } + return nil +} + +// docString reads a string field from a Typesense document, "" when absent +// or not a string. Documents are untyped maps: a direct type assertion on a +// key the index does not carry panics, and fiber's recover turns that into a +// 500 on every hit. +func docString(doc map[string]interface{}, key string) string { + s, _ := doc[key].(string) + return s +} + +// docInt reads a numeric field, 0 when absent. JSON numbers decode as float64. +func docInt(doc map[string]interface{}, key string) int { + switch v := doc[key].(type) { + case float64: + return int(v) + case int: + return v + } + return 0 +} + +// definitionName is the definition-level display name. Each document in the +// index is a trim and its name carries the trim ("2020 Toyota Camry LE"), but +// this endpoint answers one item per definition and ranking decides which +// trim's document leads the group. It is built the way definitions were always +// named, falling back to the document's name when a part is missing. +func definitionName(doc map[string]interface{}) string { + year, mk, model := docInt(doc, "year"), docString(doc, "make"), docString(doc, "model") + if year == 0 || mk == "" || model == "" { + return docString(doc, "name") + } + return common.BuildDeviceDefinitionName(int16(year), mk, model) +} diff --git a/internal/core/queries/get_dd_by_search_test.go b/internal/core/queries/get_dd_by_search_test.go new file mode 100644 index 00000000..ab5c83d4 --- /dev/null +++ b/internal/core/queries/get_dd_by_search_test.go @@ -0,0 +1,144 @@ +package queries + +import ( + "context" + "encoding/json" + "testing" + + mock_search "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/search/mocks" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/typesense/typesense-go/typesense/api" + "go.uber.org/mock/gomock" +) + +// searchResultFromJSON builds the typesense-go result the way the client +// does: by decoding the wire shape. FacetCounts.Counts is an anonymous struct +// slice, so a literal is unwieldy and a real response is the more honest +// fixture anyway. +func searchResultFromJSON(t *testing.T, body string) *api.SearchResult { + t.Helper() + var result api.SearchResult + require.NoError(t, json.Unmarshal([]byte(body), &result)) + return &result +} + +// The definitions-worker indexes ONE DOCUMENT PER TRIM with the fields below. +// There is no device_definition_id (legacy ksuids are gone) and image_url may +// be empty, and each document's name carries its trim. A grouped search on +// definition_id returns each definition once, with its top trim document as the +// group's first hit. +const workerGroupedSearchJSON = `{ + "found": 2, + "found_docs": 3, + "out_of": 1000, + "page": 1, + "facet_counts": [ + {"field_name": "make", "counts": [{"count": 2, "value": "Toyota"}, {"count": 1, "value": "Ford"}]}, + {"field_name": "model", "counts": [{"count": 2, "value": "Camry"}, {"count": 1, "value": "F-150"}]}, + {"field_name": "year", "counts": [{"count": 2, "value": "2020"}, {"count": 1, "value": "2021"}]} + ], + "grouped_hits": [ + { + "group_key": ["toyota_camry_2020"], + "found": 2, + "hits": [ + {"document": {"id": "toyota_camry_2020#LE", "definition_id": "toyota_camry_2020", "trim": "LE", + "name": "2020 Toyota Camry LE", "make": "Toyota", "make_slug": "toyota", "make_token_id": 131, + "model": "Camry", "model_slug": "camry", "year": 2020, "image_url": "", "score": 10}}, + {"document": {"id": "toyota_camry_2020#Hybrid LE", "definition_id": "toyota_camry_2020", "trim": "Hybrid LE", + "name": "2020 Toyota Camry Hybrid LE", "make": "Toyota", "make_slug": "toyota", "make_token_id": 131, + "model": "Camry", "model_slug": "camry", "year": 2020, "image_url": "", "score": 9}} + ] + }, + { + "group_key": ["ford_f-150_2021"], + "found": 1, + "hits": [ + {"document": {"id": "ford_f-150_2021#XLT", "definition_id": "ford_f-150_2021", "trim": "XLT", + "name": "2021 Ford F-150 XLT", "make": "Ford", "make_slug": "ford", "make_token_id": 46, + "model": "F-150", "model_slug": "f-150", "year": 2021, "image_url": "https://img/f150.png", "score": 8}} + ] + } + ] +}` + +func TestGetAllDeviceDefinitionBySearchQuery_WorkerShapedGroupedHits(t *testing.T) { + ctrl := gomock.NewController(t) + svc := mock_search.NewMockTypesenseAPIService(ctrl) + svc.EXPECT().GetDeviceDefinitions(gomock.Any(), "camry", "", "", 0, 1, 20). + Return(searchResultFromJSON(t, workerGroupedSearchJSON), nil) + + handler := NewGetAllDeviceDefinitionBySearchQueryHandler(svc) + out, err := handler.Handle(context.Background(), &GetAllDeviceDefinitionBySearchQuery{Query: "camry", Page: 1, PageSize: 20}) + require.NoError(t, err) + result, ok := out.(*GetAllDeviceDefinitionBySearchQueryResult) + require.True(t, ok) + + // One item per definition, not per trim: the Camry group carries two + // trims and must come back once. + require.Len(t, result.DeviceDefinitions, 2) + + camry := result.DeviceDefinitions[0] + assert.Equal(t, "toyota_camry_2020", camry.ID) + // The legacy field stays on the wire for compatibility and carries the + // same slug id; there is no other identifier to put in it. + assert.Equal(t, camry.ID, camry.DeviceDefinitionID) + assert.Equal(t, "2020 Toyota Camry", camry.Name) + assert.Equal(t, "Toyota", camry.Make) + assert.Equal(t, "Camry", camry.Model) + assert.Equal(t, 2020, camry.Year) + assert.Equal(t, "", camry.ImageURL) + + f150 := result.DeviceDefinitions[1] + assert.Equal(t, "ford_f-150_2021", f150.ID) + assert.Equal(t, "ford_f-150_2021", f150.DeviceDefinitionID) + assert.Equal(t, 2021, f150.Year) + assert.Equal(t, "https://img/f150.png", f150.ImageURL) + + // Facet parsing is unchanged. + require.Len(t, result.Facets.Makes, 2) + assert.Equal(t, GetAllDeviceDefinitionFacetItem{Name: "Toyota", Count: 2}, result.Facets.Makes[0]) + require.Len(t, result.Facets.Models, 2) + assert.Equal(t, GetAllDeviceDefinitionFacetItem{Name: "Camry", Count: 2}, result.Facets.Models[0]) + require.Len(t, result.Facets.Years, 2) + assert.Equal(t, GetAllDeviceDefinitionFacetItem{Name: "2020", Count: 2}, result.Facets.Years[0]) + + assert.Equal(t, 2, result.Pagination.TotalItems) + assert.Equal(t, 1, result.Pagination.TotalPages) +} + +// A document with fields missing entirely -- no image_url, no year, and of +// course no device_definition_id -- must decode to zero values, never panic. +// Ungrouped hits are the fallback when the fake (or an older index) returns +// no grouped_hits. +func TestGetAllDeviceDefinitionBySearchQuery_MissingFieldsDoNotPanic(t *testing.T) { + ctrl := gomock.NewController(t) + svc := mock_search.NewMockTypesenseAPIService(ctrl) + svc.EXPECT().GetDeviceDefinitions(gomock.Any(), "up", "", "", 0, 1, 10). + Return(searchResultFromJSON(t, `{ + "found": 1, + "facet_counts": [], + "hits": [ + {"document": {"id": "volkswagen_up_2019#Base", "definition_id": "volkswagen_up_2019", + "name": "2019 Volkswagen up", "make": "Volkswagen", "model": "up"}} + ] +}`), nil) + + handler := NewGetAllDeviceDefinitionBySearchQueryHandler(svc) + var out interface{} + var err error + require.NotPanics(t, func() { + out, err = handler.Handle(context.Background(), &GetAllDeviceDefinitionBySearchQuery{Query: "up", Page: 1, PageSize: 10}) + }) + require.NoError(t, err) + result := out.(*GetAllDeviceDefinitionBySearchQueryResult) + + require.Len(t, result.DeviceDefinitions, 1) + item := result.DeviceDefinitions[0] + assert.Equal(t, "volkswagen_up_2019", item.ID) + assert.Equal(t, "volkswagen_up_2019", item.DeviceDefinitionID) + assert.Equal(t, 0, item.Year) + assert.Equal(t, "", item.ImageURL) + assert.Equal(t, []GetAllDeviceDefinitionFacetItem{}, result.Facets.Makes) +} diff --git a/internal/core/queries/get_dd_dynamic_filter.go b/internal/core/queries/get_dd_dynamic_filter.go deleted file mode 100644 index 213ccc9f..00000000 --- a/internal/core/queries/get_dd_dynamic_filter.go +++ /dev/null @@ -1,125 +0,0 @@ -//nolint:tagliatelle -package queries - -import ( - "context" - "encoding/json" - "strconv" - "strings" - "time" - - "github.com/DIMO-Network/device-definitions-api/internal/core/models" - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" - "github.com/aarondl/sqlboiler/v4/types" - "github.com/ericlagergren/decimal" - - "github.com/DIMO-Network/device-definitions-api/internal/core/mediator" - "github.com/DIMO-Network/shared/pkg/db" - "github.com/aarondl/null/v8" -) - -type GetDeviceDefinitionByDynamicFilterQuery struct { - DefinitionID string `json:"definition_id"` - Year int `json:"year"` - Model string `json:"model"` - VerifiedVinList []string `json:"verified_vin_list"` - PageIndex int `json:"page_index"` - PageSize int `json:"page_size"` - MakeSlug string -} - -type DeviceDefinitionQueryResponse struct { - ID string `json:"id"` - NameSlug string `json:"name_slug"` - Model string `json:"model"` - Year int `json:"year"` - ImageURL null.String `json:"image_url,omitempty"` - CreatedAt time.Time `json:"created_at,omitempty"` - UpdatedAt time.Time `json:"updated_at,omitempty"` - Metadata null.JSON `json:"metadata"` - Source null.String `json:"source"` - Verified bool `json:"verified"` - ExternalID null.String `json:"external_id"` - DeviceMakeID string `json:"device_make_id"` - Make string `json:"make"` - ExternalIDs null.JSON `json:"external_ids"` -} - -func (*GetDeviceDefinitionByDynamicFilterQuery) Key() string { - return "GetDeviceDefinitionByDynamicFilterQuery" -} - -type GetDeviceDefinitionByDynamicFilterQueryHandler struct { - DBS func() *db.ReaderWriter - onChainSvc gateways.DeviceDefinitionOnChainService -} - -func NewGetDeviceDefinitionByDynamicFilterQueryHandler(dbs func() *db.ReaderWriter, onChainSvc gateways.DeviceDefinitionOnChainService) GetDeviceDefinitionByDynamicFilterQueryHandler { - return GetDeviceDefinitionByDynamicFilterQueryHandler{ - DBS: dbs, - onChainSvc: onChainSvc, - } -} - -func (ch GetDeviceDefinitionByDynamicFilterQueryHandler) Handle(ctx context.Context, query mediator.Message) (interface{}, error) { - - qry := query.(*GetDeviceDefinitionByDynamicFilterQuery) - - if len(qry.DefinitionID) > 1 { - dd, _, err := ch.onChainSvc.GetDefinitionByID(ctx, qry.DefinitionID) - if err != nil { - return nil, err - } - dds := make([]DeviceDefinitionQueryResponse, 1) - dds[0] = ch.buildDeviceDefinitionQueryResponse(dd) - return dds, nil - } - - manufacturerID := types.NullDecimal{} - - if len(qry.MakeSlug) > 1 { - manufacturer, err := ch.onChainSvc.GetManufacturer(qry.MakeSlug) - if err != nil { - return nil, err - } - manufacturerID = types.NewNullDecimal(decimal.New(int64(manufacturer.TokenID), 0)) - } - - definitions, err := ch.onChainSvc.GetDeviceDefinitions(ctx, manufacturerID, "", qry.Model, qry.Year, int32(qry.PageIndex), int32(qry.PageSize)) - if err != nil { - return nil, err - } - - dd := make([]DeviceDefinitionQueryResponse, len(definitions)) - for i, item := range definitions { - dd[i] = ch.buildDeviceDefinitionQueryResponse(&item) - } - - return dd, err - -} - -func (ch GetDeviceDefinitionByDynamicFilterQueryHandler) buildDeviceDefinitionQueryResponse(dd *models.DeviceDefinitionTablelandModel) DeviceDefinitionQueryResponse { - if dd == nil { - return DeviceDefinitionQueryResponse{} - } - split := strings.Split(dd.ID, "_") - manufacturerSlug := split[0] - manufacturer, _ := ch.onChainSvc.GetManufacturer(manufacturerSlug) - mdStr := []byte("{}") - if dd.Metadata != nil { - mdStr, _ = json.Marshal(dd.Metadata) - } - - return DeviceDefinitionQueryResponse{ - ID: dd.ID, - NameSlug: dd.ID, - Model: dd.Model, - Year: dd.Year, - ImageURL: null.StringFrom(dd.ImageURI), - Verified: true, - DeviceMakeID: strconv.Itoa(manufacturer.TokenID), - Make: manufacturer.Name, - Metadata: null.JSONFrom(mdStr), - } -} diff --git a/internal/core/queries/get_ds_by_filter.go b/internal/core/queries/get_ds_by_filter.go index 16efb70a..54d59506 100644 --- a/internal/core/queries/get_ds_by_filter.go +++ b/internal/core/queries/get_ds_by_filter.go @@ -50,7 +50,7 @@ func (ch GetDeviceStyleByFilterQueryHandler) Handle(ctx context.Context, query m } } - response := []coremodels.GetDeviceStyleQueryResult{} + response := make([]coremodels.GetDeviceStyleQueryResult, 0, 1) if style == nil { return response, nil diff --git a/internal/core/queries/get_ds_by_id.go b/internal/core/queries/get_ds_by_id.go index 6b2cf98b..077c8e8f 100644 --- a/internal/core/queries/get_ds_by_id.go +++ b/internal/core/queries/get_ds_by_id.go @@ -14,6 +14,7 @@ import ( "github.com/DIMO-Network/device-definitions-api/internal/core/common" "github.com/DIMO-Network/device-definitions-api/internal/core/mediator" coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" + "github.com/DIMO-Network/device-definitions-api/internal/core/services" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/db/models" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/exceptions" "github.com/DIMO-Network/shared/pkg/db" @@ -28,11 +29,11 @@ func (*GetDeviceStyleByIDQuery) Key() string { return "GetDeviceStyleByIDQuery" type GetDeviceStyleByIDQueryHandler struct { DBS func() *db.ReaderWriter - onChainSvc gateways.DeviceDefinitionOnChainService + catalogSvc gateways.DeviceDefinitionCatalogService } -func NewGetDeviceStyleByIDQueryHandler(dbs func() *db.ReaderWriter, onchainSvc gateways.DeviceDefinitionOnChainService) GetDeviceStyleByIDQueryHandler { - return GetDeviceStyleByIDQueryHandler{DBS: dbs, onChainSvc: onchainSvc} +func NewGetDeviceStyleByIDQueryHandler(dbs func() *db.ReaderWriter, onchainSvc gateways.DeviceDefinitionCatalogService) GetDeviceStyleByIDQueryHandler { + return GetDeviceStyleByIDQueryHandler{DBS: dbs, catalogSvc: onchainSvc} } func (ch GetDeviceStyleByIDQueryHandler) Handle(ctx context.Context, query mediator.Message) (interface{}, error) { @@ -50,11 +51,18 @@ func (ch GetDeviceStyleByIDQueryHandler) Handle(ctx context.Context, query media Err: fmt.Errorf("failed to get device styles"), } } - dd, _, err := ch.onChainSvc.GetDefinitionByID(ctx, ds.DefinitionID) + dd, _, err := ch.catalogSvc.GetTemplateByID(ctx, ds.DefinitionID) if err != nil { - return nil, &exceptions.InternalError{ - Err: fmt.Errorf("failed to get device definition"), + // GetTemplateByID's error is a genuine "does not exist" only when it + // is ErrTemplateNotFound (checked by identity, never by message): a + // catalog outage -- a 5xx, a timeout, a decode failure -- must not be + // reclassified as not-found, or a caller reacting to the spurious 404 + // could create a duplicate definition for a vehicle that already + // exists, during the worst possible moment to do so. + if errors.Is(err, gateways.ErrTemplateNotFound) { + return nil, &exceptions.NotFoundError{Err: fmt.Errorf("device definition not found in catalog: %s: %w", ds.DefinitionID, err)} } + return nil, &exceptions.InternalError{Err: fmt.Errorf("failed to get device definition %s from catalog: %w", ds.DefinitionID, err)} } deviceStyleResult := coremodels.GetDeviceStyleQueryResult{ @@ -66,61 +74,127 @@ func (ch GetDeviceStyleByIDQueryHandler) Handle(ctx context.Context, query media SubModel: ds.SubModel, HardwareTemplateID: ds.HardwareTemplateID.String, DeviceDefinition: coremodels.GetDeviceDefinitionStyleQueryResult{ - DeviceAttributes: common.ConvertMetadataToDeviceAttributes(dd.Metadata), // copy any attributes from parent DD + // The style's name is the signal the trim matcher consumes, so + // the definition served here is the trim this style actually is, + // not the shared part of the template it belongs to. + DeviceAttributes: styleDeviceAttributes(dd, ds.Name, ds.Metadata.JSON), }, } - // first see if style metadata has powertrain, most cases will be blank - powerTrainType := gjson.GetBytes(ds.Metadata.JSON, common.PowerTrainType).String() - if len(powerTrainType) == 0 { - // Set powertrain based on naming logic - name := strings.ToLower(deviceStyleResult.Name) - if strings.Contains(name, "phev") { - powerTrainType = models.PowertrainPHEV - } else if strings.Contains(name, "hev") { - powerTrainType = models.PowertrainHEV - } else if strings.Contains(name, "plug-in") { - powerTrainType = models.PowertrainPHEV - } else if strings.Contains(name, "hybrid") { - powerTrainType = models.PowertrainHEV - } else if strings.Contains(name, "electric") { - powerTrainType = models.PowertrainBEV - } else if strings.Contains(name, "4xe") { - powerTrainType = models.PowertrainPHEV - } else if strings.Contains(name, "energi") { - powerTrainType = models.PowertrainPHEV - } - } - // override any existing powertrain inherited from device definition, only if we came up with something worthy from above logic - hasPowertrain := false - for i, item := range deviceStyleResult.DeviceDefinition.DeviceAttributes { + return deviceStyleResult, nil +} + +// styleDeviceAttributes serves the attributes of the trim this style is. +// +// A template carries at the top level only the attributes every trim agrees +// on -- by design, so that nothing which varies by trim is asserted for all of +// them. Copying those alone dropped every trim-varying attribute (mpg, msrp, +// seating, fuel tank) and left a caller unable to tell an attribute the +// template does not have from one living on a trim it was not given. For a +// model sold as combustion, hybrid and plug-in hybrid, nothing carried a +// powertrain at all: the name heuristic misses names like "Prime SE", and the +// response asserted internal combustion for a plug-in hybrid. +// +// The style's name is exactly services.MatchTrim's styleName signal, so the +// trim is resolved here. An exact match serves that trim's attributes over the +// template's; an ambiguous one serves only what every candidate agrees on; no +// match serves the template's own. In every case what comes back is what some +// trim actually has, never a merge across trims. +func styleDeviceAttributes(tmpl *coremodels.Template, styleName string, styleMetadata []byte) []coremodels.DeviceTypeAttributeEditor { + resolved := services.MatchTrim(tmpl, services.MatchSignals{StyleName: styleName}) + attrs := convertTemplateAttributesToDeviceAttributes(resolved.Attributes) + + powerTrainType := powertrainForStyle(resolved, styleName, styleMetadata) + for i, item := range attrs { if item.Name == common.PowerTrainType { - hasPowertrain = true - if len(powerTrainType) > 0 { - deviceStyleResult.DeviceDefinition.DeviceAttributes[i].Value = powerTrainType - } - break + attrs[i].Value = powerTrainType + return attrs } } + return append(attrs, coremodels.DeviceTypeAttributeEditor{ + Name: common.PowerTrainType, + Label: common.PowerTrainType, + Description: common.PowerTrainType, + Type: common.DefaultDeviceType, + Value: powerTrainType, + }) +} - // if no powertrain attribute found, set it, defaulting to parent DD if nothing resulted from above logic - if !hasPowertrain { - if len(powerTrainType) == 0 { - powerTrainType = models.PowertrainICE // default to ICE if nothing found - for _, attribute := range dd.Metadata.DeviceAttributes { - if attribute.Name == common.PowerTrainType { - powerTrainType = attribute.Value - break - } - } - } - deviceStyleResult.DeviceDefinition.DeviceAttributes = append(deviceStyleResult.DeviceDefinition.DeviceAttributes, coremodels.DeviceTypeAttributeEditor{ - Name: common.PowerTrainType, - Description: common.PowerTrainType, - Type: common.DefaultDeviceType, - Value: powerTrainType, - }) +// powertrainForStyle decides the one powertrain this style is reported with. +// +// In order: what the style row itself recorded at decode time, which is the +// only value observed for this style rather than inferred; then an exactly +// matched trim's, which is more specific than any reading of the name; then +// the name heuristic, which is how a style that narrowed to no single trim has +// always been answered; then whatever the resolution left -- the template's +// own value, or the one every ambiguous candidate agreed on. +// +// The ICE default applies only when all four say nothing: no powertrain on the +// style row, none on the matched trim, none shared by the template, and a name +// carrying no hint. That is a genuinely unknown powertrain, and ICE remains +// the answer there for compatibility with what this endpoint has always +// served. +func powertrainForStyle(resolved services.Resolved, styleName string, styleMetadata []byte) string { + if pt := gjson.GetBytes(styleMetadata, common.PowerTrainType).String(); pt != "" { + return pt + } + resolvedPT, _ := resolved.Attributes[common.PowerTrainType].(string) + if resolved.Quality == services.MatchExact && resolvedPT != "" { + return resolvedPT + } + if pt := powertrainFromStyleName(styleName); pt != "" { + return pt } + if resolvedPT != "" { + return resolvedPT + } + return models.PowertrainICE +} - return deviceStyleResult, nil +// powertrainFromStyleName reads a powertrain out of a style name, or "" when +// the name says nothing. It is a heuristic over marketing names and is used +// only where nothing in the catalog answers: a trim that matched, or a +// template whose trims all agree, is always believed over it. +func powertrainFromStyleName(styleName string) string { + name := strings.ToLower(styleName) + switch { + case strings.Contains(name, "phev"): + return models.PowertrainPHEV + case strings.Contains(name, "hev"): + return models.PowertrainHEV + case strings.Contains(name, "plug-in"): + return models.PowertrainPHEV + case strings.Contains(name, "hybrid"): + return models.PowertrainHEV + case strings.Contains(name, "electric"): + return models.PowertrainBEV + case strings.Contains(name, "4xe"): + return models.PowertrainPHEV + case strings.Contains(name, "energi"): + return models.PowertrainPHEV + } + return "" +} + +// convertTemplateAttributesToDeviceAttributes adapts a template's typed +// attribute map to the legacy DeviceTypeAttributeEditor shape this handler's +// response is built from. +// +// The renderer and the ordering are common's, the same two the definition path +// uses, so one definition's attributes read identically whichever endpoint +// served them. fmt.Sprint served a price of 1250000 as "1.25e+06" here while +// GetDeviceDefinitionByID served "1250000", and ranging over the map put the +// array in a different order on every request for the same style. +func convertTemplateAttributesToDeviceAttributes(attributes map[string]any) []coremodels.DeviceTypeAttributeEditor { + names := common.SortedAttributeNames(attributes) + dta := make([]coremodels.DeviceTypeAttributeEditor, 0, len(names)) + for _, name := range names { + dta = append(dta, coremodels.DeviceTypeAttributeEditor{ + Name: name, + Label: name, + Description: name, + Value: common.AttributeString(attributes[name]), + }) + } + return dta } diff --git a/internal/core/queries/get_ds_by_id_attrs_test.go b/internal/core/queries/get_ds_by_id_attrs_test.go new file mode 100644 index 00000000..dd6684aa --- /dev/null +++ b/internal/core/queries/get_ds_by_id_attrs_test.go @@ -0,0 +1,229 @@ +package queries + +import ( + "testing" + + "github.com/DIMO-Network/device-definitions-api/internal/core/common" + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" + "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/db/models" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// GET /device-styles/{id} serves the attributes of the definition the style +// belongs to. A template carries at the top level only what every trim agrees +// on, so copying those alone drops every trim-varying attribute and reports no +// powertrain for any model sold as combustion, hybrid and plug-in hybrid -- +// after which the name heuristic misses "Prime SE" and the code asserts ICE +// for a plug-in hybrid. The style's name is exactly the signal +// services.MatchTrim consumes, so the trim is resolved and its attributes +// served. +// +// These exercise the resolution itself, which is pure: no Postgres, no +// catalog. Only the handler's device_styles read needs CI. + +// rav4 is the shape the finding describes: one model sold with three +// powertrains, so powertrain_type lives on each trim and never at the top. +func rav4() *coremodels.Template { + return &coremodels.Template{ + ID: "toyota_rav4_2021", + DeviceType: "vehicle", + Manufacturer: coremodels.TemplateManufacturer{Slug: "toyota", Name: "Toyota", TokenID: 131}, + Model: "RAV4", + Year: 2021, + Attributes: map[string]any{ + "number_of_doors": float64(4), + "driven_wheels": "AWD", + }, + Trims: []coremodels.Trim{ + { + Name: "LE", + Selectors: coremodels.TrimSelectors{StyleName: []string{"LE"}}, + Attributes: map[string]any{common.PowerTrainType: "ICE", "mpg": float64(30), "base_msrp": float64(1250000)}, + }, + { + Name: "XSE Hybrid", + Selectors: coremodels.TrimSelectors{StyleName: []string{"XSE Hybrid"}}, + Attributes: map[string]any{common.PowerTrainType: "HEV", "mpg": float64(40)}, + }, + { + Name: "Prime SE", + Selectors: coremodels.TrimSelectors{StyleName: []string{"Prime SE"}}, + Attributes: map[string]any{common.PowerTrainType: "PHEV", "mpg": float64(94), "fuel_tank_capacity_gal": float64(14.5)}, + }, + }, + Version: 3, + } +} + +func attributeByName(t *testing.T, attrs []coremodels.DeviceTypeAttributeEditor, name string) string { + t.Helper() + for _, a := range attrs { + if a.Name == name { + return a.Value + } + } + return "" +} + +func hasAttribute(attrs []coremodels.DeviceTypeAttributeEditor, name string) bool { + for _, a := range attrs { + if a.Name == name { + return true + } + } + return false +} + +// The finding itself: a plug-in hybrid whose name no heuristic recognises. +func TestStyleAttributesResolveThePlugInHybridTrim(t *testing.T) { + attrs := styleDeviceAttributes(rav4(), "Prime SE", nil) + + assert.Equal(t, "PHEV", attributeByName(t, attrs, common.PowerTrainType), + "the matched trim says PHEV; asserting ICE here is the defect") + assert.Equal(t, "94", attributeByName(t, attrs, "mpg"), "a trim-varying attribute must be served") + assert.Equal(t, "14.5", attributeByName(t, attrs, "fuel_tank_capacity_gal")) + // The template's own attributes are still there. + assert.Equal(t, "4", attributeByName(t, attrs, "number_of_doors")) + assert.Equal(t, "AWD", attributeByName(t, attrs, "driven_wheels")) +} + +// The trim the heuristic would have got right must still come out right, and +// with its own attributes rather than another trim's. +func TestStyleAttributesResolveTheHybridTrim(t *testing.T) { + attrs := styleDeviceAttributes(rav4(), "XSE Hybrid", nil) + + assert.Equal(t, "HEV", attributeByName(t, attrs, common.PowerTrainType)) + assert.Equal(t, "40", attributeByName(t, attrs, "mpg")) + assert.False(t, hasAttribute(attrs, "fuel_tank_capacity_gal"), "attributes of a trim that did not match must not leak in") +} + +func TestStyleAttributesResolveTheCombustionTrim(t *testing.T) { + attrs := styleDeviceAttributes(rav4(), "LE", nil) + + assert.Equal(t, "ICE", attributeByName(t, attrs, common.PowerTrainType)) + assert.Equal(t, "30", attributeByName(t, attrs, "mpg")) +} + +// What the style itself recorded at decode time wins: it is the one value that +// was observed for this style rather than inferred from a name. +func TestStyleAttributesPreferThePowertrainOnTheStyleRow(t *testing.T) { + attrs := styleDeviceAttributes(rav4(), "Prime SE", []byte(`{"powertrain_type":"BEV"}`)) + + assert.Equal(t, "BEV", attributeByName(t, attrs, common.PowerTrainType)) +} + +// No trim matched, so nothing carries a powertrain -- but the name does. The +// heuristic still answers, as it always has. +func TestStyleAttributesFallBackToTheNameHeuristicWhenNoTrimMatches(t *testing.T) { + attrs := styleDeviceAttributes(rav4(), "Limited Plug-In", nil) + + assert.Equal(t, models.PowertrainPHEV, attributeByName(t, attrs, common.PowerTrainType)) + // No trim was chosen, so no trim's attributes are served. + assert.False(t, hasAttribute(attrs, "mpg"), "an unmatched style must not be given some trim's attributes") + assert.Equal(t, "4", attributeByName(t, attrs, "number_of_doors")) +} + +// A model where every trim agrees on the powertrain carries it at the top +// level. An unmatched style must take that, not the ICE default. +func TestStyleAttributesUseTheTemplatePowertrainWhenNoTrimMatches(t *testing.T) { + tmpl := &coremodels.Template{ + ID: "tesla_model-3_2022", + Model: "Model 3", + Year: 2022, + Attributes: map[string]any{common.PowerTrainType: "BEV"}, + Trims: []coremodels.Trim{ + {Name: "Long Range", Selectors: coremodels.TrimSelectors{StyleName: []string{"Long Range"}}}, + }, + } + + attrs := styleDeviceAttributes(tmpl, "Some Style We Do Not Know", nil) + + assert.Equal(t, "BEV", attributeByName(t, attrs, common.PowerTrainType), + "the template says BEV for every trim; defaulting to ICE would contradict it") +} + +// Two trims match, so no trim is chosen: only what every candidate agrees on +// is served, and the powertrain they agree on is not a guess. +func TestStyleAttributesServeOnlyWhatAmbiguousCandidatesAgreeOn(t *testing.T) { + tmpl := &coremodels.Template{ + ID: "toyota_camry_2026", + Model: "Camry", + Year: 2026, + Trims: []coremodels.Trim{ + {Name: "LE", Selectors: coremodels.TrimSelectors{StyleName: []string{"LE"}}, Attributes: map[string]any{common.PowerTrainType: "HEV", "mpg": float64(44)}}, + {Name: "LE FWD", Selectors: coremodels.TrimSelectors{StyleName: []string{"LE"}}, Attributes: map[string]any{common.PowerTrainType: "HEV", "mpg": float64(51)}}, + }, + } + + attrs := styleDeviceAttributes(tmpl, "LE", nil) + + assert.Equal(t, "HEV", attributeByName(t, attrs, common.PowerTrainType), "both candidates say HEV") + assert.False(t, hasAttribute(attrs, "mpg"), "the candidates disagree on mpg, so neither answer may be served") +} + +// The ICE default is the last resort and stays: nothing anywhere -- the style +// row, the matched trim, the template, the name -- says anything about the +// powertrain. +func TestStyleAttributesDefaultToICEOnlyWhenThePowertrainIsUnknown(t *testing.T) { + tmpl := &coremodels.Template{ + ID: "ford_escape_2020", + Model: "Escape", + Year: 2020, + Attributes: map[string]any{"number_of_doors": float64(4)}, + } + + attrs := styleDeviceAttributes(tmpl, "SE", nil) + + assert.Equal(t, models.PowertrainICE, attributeByName(t, attrs, common.PowerTrainType)) +} + +// A style whose name cannot narrow anything still gets an answer, and the +// resolution never panics on a template with no trims at all. +func TestStyleAttributesHandleATemplateWithNoTrims(t *testing.T) { + tmpl := &coremodels.Template{ + ID: "toyota_camry_2026", + Model: "Camry", + Year: 2026, + Attributes: map[string]any{common.PowerTrainType: "ICE", "number_of_doors": float64(4)}, + } + + attrs := styleDeviceAttributes(tmpl, "", nil) + + require.NotEmpty(t, attrs) + assert.Equal(t, "ICE", attributeByName(t, attrs, common.PowerTrainType)) +} + +// A template attribute decodes as a float64, so fmt.Sprint rendered a price of +// 1250000 as "1.25e+06" -- while GetDeviceDefinitionByID served "1250000" for +// the same definition, because the gateway already had a renderer written for +// this. Both now share it. +func TestStyleAttributesRenderNumbersWithoutScientificNotation(t *testing.T) { + attrs := styleDeviceAttributes(rav4(), "LE", nil) + + assert.Equal(t, "1250000", attributeByName(t, attrs, "base_msrp")) + assert.Equal(t, "4", attributeByName(t, attrs, "number_of_doors")) + assert.Equal(t, "30", attributeByName(t, attrs, "mpg")) + for _, a := range attrs { + assert.NotContains(t, a.Value, "e+", "%s must not be served in scientific notation", a.Name) + } +} + +// The attributes came out of a Go map, so the array was in a different order +// on every request for the same style. The sibling definition path sorts. +func TestStyleAttributesAreInAStableOrder(t *testing.T) { + want := namesOf(styleDeviceAttributes(rav4(), "Prime SE", nil)) + assert.Equal(t, []string{"driven_wheels", "fuel_tank_capacity_gal", "mpg", "number_of_doors", "powertrain_type"}, want) + for i := 0; i < 20; i++ { + assert.Equal(t, want, namesOf(styleDeviceAttributes(rav4(), "Prime SE", nil)), + "the attribute array must not shuffle between requests for one style") + } +} + +func namesOf(attrs []coremodels.DeviceTypeAttributeEditor) []string { + names := make([]string, 0, len(attrs)) + for _, a := range attrs { + names = append(names, a.Name) + } + return names +} diff --git a/internal/core/queries/get_ds_by_id_test.go b/internal/core/queries/get_ds_by_id_test.go new file mode 100644 index 00000000..aa3aec9e --- /dev/null +++ b/internal/core/queries/get_ds_by_id_test.go @@ -0,0 +1,97 @@ +package queries + +import ( + "context" + "fmt" + "testing" + + "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/exceptions" + "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" + mock_gateways "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways/mocks" + + dbtesthelper "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/dbtest" + "github.com/DIMO-Network/shared/pkg/db" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "github.com/testcontainers/testcontainers-go" + "go.uber.org/mock/gomock" +) + +// A catalog outage (a 500, a timeout, a decode failure) must not be +// reclassified as "this vehicle does not exist": that reclassification is +// what would let a caller respond by creating a duplicate definition mid- +// outage, the worst possible moment for it. +type GetDeviceStyleByIDQueryHandlerSuite struct { + suite.Suite + *require.Assertions + + ctrl *gomock.Controller + pdb db.Store + container testcontainers.Container + ctx context.Context + mockCatalogSvc *mock_gateways.MockDeviceDefinitionCatalogService + + queryHandler GetDeviceStyleByIDQueryHandler +} + +func TestGetDeviceStyleByIDQueryHandler(t *testing.T) { + suite.Run(t, new(GetDeviceStyleByIDQueryHandlerSuite)) +} + +func (s *GetDeviceStyleByIDQueryHandlerSuite) SetupTest() { + s.ctx = context.Background() + s.Assertions = require.New(s.T()) + s.ctrl = gomock.NewController(s.T()) + s.mockCatalogSvc = mock_gateways.NewMockDeviceDefinitionCatalogService(s.ctrl) + + s.pdb, s.container = dbtesthelper.StartContainerDatabase(s.ctx, dbName, s.T(), migrationsDirRelPath) + + s.queryHandler = NewGetDeviceStyleByIDQueryHandler(s.pdb.DBS, s.mockCatalogSvc) +} + +func (s *GetDeviceStyleByIDQueryHandlerSuite) TearDownTest() { + dbtesthelper.TruncateTables(s.pdb.DBS().Writer.DB, s.T()) + s.ctrl.Finish() +} + +func (s *GetDeviceStyleByIDQueryHandlerSuite) TearDownSuite() { + if err := s.container.Terminate(s.ctx); err != nil { + s.T().Fatal(err) + } +} + +// A genuine catalog 404 (ErrTemplateNotFound) is the one case that should +// surface as NotFoundError: the vehicle's parent template really is absent. +func (s *GetDeviceStyleByIDQueryHandlerSuite) TestHandle_CatalogTemplateNotFound_ReturnsNotFoundError() { + ds := dbtesthelper.SetupCreateStyle(s.T(), "toyota_camry_2020", "LE", "drivly", "", s.pdb) + + s.mockCatalogSvc.EXPECT().GetTemplateByID(gomock.Any(), ds.DefinitionID).Return( + nil, nil, errors.Wrapf(gateways.ErrTemplateNotFound, "template %s", ds.DefinitionID)) + + _, err := s.queryHandler.Handle(s.ctx, &GetDeviceStyleByIDQuery{DeviceStyleID: ds.ID}) + + require.Error(s.T(), err) + var notFound *exceptions.NotFoundError + assert.ErrorAs(s.T(), err, ¬Found) +} + +// A catalog outage -- a 500, a timeout, a decode failure -- is a distinct, +// non-sentinel error from GetTemplateByID. It must come back as an internal +// error, never a NotFoundError: conflating the two is what makes a catalog +// outage look like a missing vehicle. +func (s *GetDeviceStyleByIDQueryHandlerSuite) TestHandle_CatalogOutage_ReturnsInternalErrorNotNotFound() { + ds := dbtesthelper.SetupCreateStyle(s.T(), "toyota_camry_2020", "LE", "drivly", "", s.pdb) + + s.mockCatalogSvc.EXPECT().GetTemplateByID(gomock.Any(), ds.DefinitionID).Return( + nil, nil, fmt.Errorf("catalog returned 500 for template %s", ds.DefinitionID)) + + _, err := s.queryHandler.Handle(s.ctx, &GetDeviceStyleByIDQuery{DeviceStyleID: ds.ID}) + + require.Error(s.T(), err) + var notFound *exceptions.NotFoundError + assert.False(s.T(), errors.As(err, ¬Found), "a catalog outage must not surface as NotFoundError") + var internal *exceptions.InternalError + assert.ErrorAs(s.T(), err, &internal) +} diff --git a/internal/core/queries/upsert_vin_decode.go b/internal/core/queries/upsert_vin_decode.go index 3c8f7089..ec645475 100644 --- a/internal/core/queries/upsert_vin_decode.go +++ b/internal/core/queries/upsert_vin_decode.go @@ -3,8 +3,10 @@ package queries import ( "context" "fmt" + "math/big" "github.com/DIMO-Network/device-definitions-api/internal/core/mediator" + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/db/models" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/exceptions" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" @@ -20,7 +22,7 @@ import ( type UpsertDecodingQueryHandler struct { dbs func() *db.ReaderWriter logger *zerolog.Logger - deviceDefinitionOnChainService gateways.DeviceDefinitionOnChainService + deviceDefinitionCatalogService gateways.DeviceDefinitionCatalogService } type UpsertDecodingQuery struct { @@ -32,11 +34,11 @@ func (*UpsertDecodingQuery) Key() string { return "UpsertDecodingQuery" } func NewUpsertDecodingQueryHandler(dbs func() *db.ReaderWriter, logger *zerolog.Logger, - deviceDefinitionOnChainService gateways.DeviceDefinitionOnChainService) UpsertDecodingQueryHandler { + deviceDefinitionCatalogService gateways.DeviceDefinitionCatalogService) UpsertDecodingQueryHandler { return UpsertDecodingQueryHandler{ dbs: dbs, logger: logger, - deviceDefinitionOnChainService: deviceDefinitionOnChainService, + deviceDefinitionCatalogService: deviceDefinitionCatalogService, } } @@ -53,14 +55,21 @@ func (dc UpsertDecodingQueryHandler) Handle(ctx context.Context, query mediator. Str("handler", query.Key()). Logger() - // check if the definition id exists on chain - dd, manuf, err := dc.deviceDefinitionOnChainService.GetDefinitionByID(ctx, qry.DefinitionID) + // check if the definition id exists in the catalog. GetTemplateByID's + // error is only ever "does not exist" when it is ErrTemplateNotFound + // (checked by identity, never by message); anything else -- a catalog + // outage, a timeout, a decode failure -- is an internal error and must + // not be reported as a missing definition. + dd, manuf, err := dc.deviceDefinitionCatalogService.GetTemplateByID(ctx, qry.DefinitionID) if err != nil { - return nil, errors.Wrapf(err, "failed to find device definition by id %s when upserting vin decoding", qry.DefinitionID) + if errors.Is(err, gateways.ErrTemplateNotFound) { + return nil, &exceptions.NotFoundError{Err: fmt.Errorf("device definition not found in catalog: %s: %w", qry.DefinitionID, err)} + } + return nil, &exceptions.InternalError{Err: fmt.Errorf("failed to find device definition by id %s when upserting vin decoding: %w", qry.DefinitionID, err)} } - manufacturerName, err := dc.deviceDefinitionOnChainService.GetManufacturerNameByID(ctx, manuf) + manufacturerName, err := manufacturerNameForTemplate(ctx, dc.deviceDefinitionCatalogService, dd, manuf) if err != nil { - return nil, errors.Wrapf(err, "failed to find manufacturer name by id %s when upserting vin decoding", manuf) + return nil, err } //upsert the vin vinNumber := &models.VinNumber{ @@ -85,3 +94,25 @@ func (dc UpsertDecodingQueryHandler) Handle(ctx context.Context, query mediator. localLog.Info().Str(logfields.VIN, qry.VIN).Str(logfields.FunctionName, qry.Key()).Msg("manually upserted new vin number") return nil, nil } + +// manufacturerNameForTemplate names the manufacturer a template belongs to. +// +// A known token id keeps identity as the source of the name. A template's +// tokenId is optional, though, and GetTemplateByID reports an absent one as +// nil: looking that up as manufacturer 0 failed the upsert with an untyped +// error and never wrote the vin_numbers row. The template's own manufacturer +// name, which the schema requires, is used instead. A template with neither is +// reported as not found rather than written with an empty manufacturer. +func manufacturerNameForTemplate(ctx context.Context, catalog gateways.DeviceDefinitionCatalogService, tmpl *coremodels.Template, tokenID *big.Int) (string, error) { + if tokenID == nil { + if tmpl.Manufacturer.Name == "" { + return "", &exceptions.NotFoundError{Err: fmt.Errorf("device definition %s has no manufacturer token id or name", tmpl.ID)} + } + return tmpl.Manufacturer.Name, nil + } + name, err := catalog.GetManufacturerNameByID(ctx, tokenID) + if err != nil { + return "", errors.Wrapf(err, "failed to find manufacturer name by id %s when upserting vin decoding", tokenID) + } + return name, nil +} diff --git a/internal/core/queries/upsert_vin_decode_test.go b/internal/core/queries/upsert_vin_decode_test.go new file mode 100644 index 00000000..6e4223ba --- /dev/null +++ b/internal/core/queries/upsert_vin_decode_test.go @@ -0,0 +1,60 @@ +package queries + +import ( + "context" + "math/big" + "testing" + + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" + "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/exceptions" + mock_gateways "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways/mocks" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +// UpsertDecoding's write needs Postgres, so the manufacturer resolution it +// depends on is tested on its own. + +// A template's manufacturer.tokenId is optional, and GetTemplateByID reports an +// absent one as nil. Looking up manufacturer 0 in its place failed the upsert +// with an untyped error and never wrote the vin_numbers row. +func TestManufacturerNameForTemplateWithoutATokenIDUsesTheTemplate(t *testing.T) { + ctrl := gomock.NewController(t) + catalog := mock_gateways.NewMockDeviceDefinitionCatalogService(ctrl) + catalog.EXPECT().GetManufacturerNameByID(gomock.Any(), gomock.Any()).Times(0) + + tmpl := &coremodels.Template{ + ID: "toyota_camry_2026", + Manufacturer: coremodels.TemplateManufacturer{Slug: "toyota", Name: "Toyota"}, + } + name, err := manufacturerNameForTemplate(context.Background(), catalog, tmpl, nil) + require.NoError(t, err) + assert.Equal(t, "Toyota", name) +} + +func TestManufacturerNameForTemplateWithATokenIDAsksIdentity(t *testing.T) { + ctrl := gomock.NewController(t) + catalog := mock_gateways.NewMockDeviceDefinitionCatalogService(ctrl) + catalog.EXPECT().GetManufacturerNameByID(gomock.Any(), big.NewInt(131)).Return("Toyota", nil) + + tmpl := &coremodels.Template{ + ID: "toyota_camry_2020", + Manufacturer: coremodels.TemplateManufacturer{Slug: "toyota", Name: "TOYOTA", TokenID: 131}, + } + name, err := manufacturerNameForTemplate(context.Background(), catalog, tmpl, big.NewInt(131)) + require.NoError(t, err) + assert.Equal(t, "Toyota", name, "a known token id keeps identity as the source of the name") +} + +// The fiber and gRPC error mappers type-assert rather than unwrap, so the +// not-found must come back bare to be answered as one. +func TestManufacturerNameForTemplateWithNeitherIsNotFound(t *testing.T) { + ctrl := gomock.NewController(t) + catalog := mock_gateways.NewMockDeviceDefinitionCatalogService(ctrl) + catalog.EXPECT().GetManufacturerNameByID(gomock.Any(), gomock.Any()).Times(0) + + _, err := manufacturerNameForTemplate(context.Background(), catalog, &coremodels.Template{ID: "toyota_camry_2026"}, nil) + require.Error(t, err) + assert.IsType(t, &exceptions.NotFoundError{}, err) +} diff --git a/internal/core/services/powertrain_type_service.go b/internal/core/services/powertrain_type_service.go index 3019280d..163afeef 100644 --- a/internal/core/services/powertrain_type_service.go +++ b/internal/core/services/powertrain_type_service.go @@ -23,10 +23,10 @@ type PowerTrainTypeService interface { type powerTrainTypeService struct { logger *zerolog.Logger powerTrainRuleData coremodels.PowerTrainTypeRuleData - deviceDefinitionOnChainService gateways.DeviceDefinitionOnChainService + deviceDefinitionCatalogService gateways.DeviceDefinitionCatalogService } -func NewPowerTrainTypeService(rulesFileName string, logger *zerolog.Logger, ddOnChainSvc gateways.DeviceDefinitionOnChainService) (PowerTrainTypeService, error) { +func NewPowerTrainTypeService(rulesFileName string, logger *zerolog.Logger, ddCatalogSvc gateways.DeviceDefinitionCatalogService) (PowerTrainTypeService, error) { if rulesFileName == "" { rulesFileName = "powertrain_type_rule.yaml" } @@ -41,7 +41,7 @@ func NewPowerTrainTypeService(rulesFileName string, logger *zerolog.Logger, ddOn return nil, err } - return &powerTrainTypeService{logger: logger, powerTrainRuleData: powerTrainTypeData, deviceDefinitionOnChainService: ddOnChainSvc}, nil + return &powerTrainTypeService{logger: logger, powerTrainRuleData: powerTrainTypeData, deviceDefinitionCatalogService: ddCatalogSvc}, nil } // ResolvePowerTrainFromVinInfo uses standard vin info StyleName and FuelType to figure out powertrain, otherwise returns an empty string diff --git a/internal/core/services/powertrain_type_service_test.go b/internal/core/services/powertrain_type_service_test.go index 0a5ef7fd..dc87d1f4 100644 --- a/internal/core/services/powertrain_type_service_test.go +++ b/internal/core/services/powertrain_type_service_test.go @@ -18,10 +18,10 @@ func Test_powerTrainTypeService_ResolvePowerTrainType(t *testing.T) { logger := dbtesthelper.Logger() ctrl := gomock.NewController(t) - onChainSvc := mock_gateways.NewMockDeviceDefinitionOnChainService(ctrl) + catalogSvc := mock_gateways.NewMockDeviceDefinitionCatalogService(ctrl) defer ctrl.Finish() - ptSvc, err := NewPowerTrainTypeService("../../../powertrain_type_rule.yaml", logger, onChainSvc) + ptSvc, err := NewPowerTrainTypeService("../../../powertrain_type_rule.yaml", logger, catalogSvc) require.NoError(t, err) type args struct { diff --git a/internal/core/services/trim_match.go b/internal/core/services/trim_match.go new file mode 100644 index 00000000..9c196118 --- /dev/null +++ b/internal/core/services/trim_match.go @@ -0,0 +1,234 @@ +package services + +import ( + "reflect" + "regexp" + "strings" + + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" +) + +// MatchSignals are the decoded-VIN signals MatchTrim narrows a Template +// against. A zero-value field means that signal was not available; it never +// participates in matching. +type MatchSignals struct { + ManufacturerCode string + StyleName string + VIN string +} + +// MatchQuality reports how confidently MatchTrim narrowed a Template to a +// single Trim. +type MatchQuality string + +const ( + // MatchExact means exactly one trim's selectors matched the signals. + MatchExact MatchQuality = "exact" + // MatchAmbiguous means more than one trim's selectors matched. Picking + // one arbitrarily would silently reintroduce the blended-record bug this + // matcher exists to fix, so no trim is chosen. + MatchAmbiguous MatchQuality = "ambiguous" + // MatchModelOnly means no trim's selectors matched. Only the template's + // own attributes are returned -- never a partial merge from a trim that + // nearly matched. + MatchModelOnly MatchQuality = "model-only" +) + +// Resolved is the outcome of narrowing a Template to (at most) one Trim. +type Resolved struct { + DefinitionID string + TemplateVersion int + Trim string + Quality MatchQuality + MatchedBy []string + Candidates []string + Attributes map[string]any + HardwareTemplateID string +} + +// MatchTrim narrows tmpl to the single Trim whose selectors agree with sig. +// +// A trim matches when every selector it declares agrees with sig; a trim +// with no selectors at all matches unconditionally (the single-trim, +// no-disambiguation-needed case). Exactly one matching trim is an exact +// match: its attributes are merged over the template's, and its +// powertrain/tank/etc. always come from that same trim -- never a mix of +// trims. Zero matches is model-only: only the template's own attributes are +// returned. More than one match is ambiguous: no trim is chosen, and only +// the attributes every candidate agrees on are returned, alongside the +// names of the trims still in contention. +// +// HardwareTemplateID is DIMO hardware configuration, not a vehicle +// attribute; it is resolved independently of Attributes, taking the matched +// trim's value when set and otherwise the template's. On an ambiguous or +// model-only result, no single trim is chosen, so the template's value is +// used unchanged -- taking a candidate's hardware value when we have +// explicitly declined to pick a candidate would still be picking one, in +// the one field that decides what hardware DIMO ships. The template's value +// is what every candidate shares by construction, so it's the only +// non-arbitrary answer available. +// +// MatchTrim is pure: no I/O, no logging, no clock. The same tmpl and sig +// always produce the same Resolved. +func MatchTrim(tmpl *coremodels.Template, sig MatchSignals) Resolved { + res := Resolved{ + DefinitionID: tmpl.ID, + TemplateVersion: tmpl.Version, + Attributes: copyAttributes(tmpl.Attributes), + HardwareTemplateID: tmpl.HardwareTemplateID, + } + + var matches []trimMatch + for _, trim := range tmpl.Trims { + if ok, matchedBy := selectorsMatch(trim.Selectors, sig); ok { + matches = append(matches, trimMatch{trim: trim, matchedBy: matchedBy}) + } + } + + switch len(matches) { + case 0: + // res.HardwareTemplateID stays the template's value: no trim + // matched, so there is no candidate to defer to. + res.Quality = MatchModelOnly + case 1: + m := matches[0] + res.Quality = MatchExact + res.Trim = m.trim.Name + res.MatchedBy = m.matchedBy + for k, v := range m.trim.Attributes { + res.Attributes[k] = v + } + if m.trim.HardwareTemplateID != "" { + res.HardwareTemplateID = m.trim.HardwareTemplateID + } + default: + // res.HardwareTemplateID stays the template's value here too. Do + // NOT "improve" this by taking the first (or any) candidate's + // HardwareTemplateID: we have explicitly declined to pick a + // candidate trim, and doing so anyway -- even for just this field -- + // reintroduces arbitrary selection in the one field that decides + // what hardware DIMO ships. The template's value is what every + // candidate shares by construction, so it's the only answer that + // isn't a guess. + res.Quality = MatchAmbiguous + res.Candidates = make([]string, len(matches)) + for i, m := range matches { + res.Candidates[i] = m.trim.Name + } + for k, v := range agreedAttributes(matches) { + res.Attributes[k] = v + } + } + + return res +} + +type trimMatch struct { + trim coremodels.Trim + matchedBy []string +} + +// selectorsMatch reports whether every selector sel declares agrees with +// sig, and which selector kinds matched. A selector that sel does not +// declare (empty slice / empty string) never blocks a match; a selector sel +// does declare only matches when sig supplies the corresponding signal and +// it agrees. +func selectorsMatch(sel coremodels.TrimSelectors, sig MatchSignals) (bool, []string) { + var matchedBy []string + + if len(sel.ManufacturerCode) > 0 { + if sig.ManufacturerCode == "" || !containsExact(sel.ManufacturerCode, sig.ManufacturerCode) { + return false, nil + } + matchedBy = append(matchedBy, "manufacturerCode") + } + + if len(sel.StyleName) > 0 { + if sig.StyleName == "" || !containsFold(sel.StyleName, sig.StyleName) { + return false, nil + } + matchedBy = append(matchedBy, "styleName") + } + + if sel.VINPattern != "" { + if sig.VIN == "" || !vinMatchesPattern(sel.VINPattern, sig.VIN) { + return false, nil + } + matchedBy = append(matchedBy, "vinPattern") + } + + return true, matchedBy +} + +func containsExact(values []string, want string) bool { + for _, v := range values { + if v == want { + return true + } + } + return false +} + +func containsFold(values []string, want string) bool { + for _, v := range values { + if strings.EqualFold(v, want) { + return true + } + } + return false +} + +// vinMatchesPattern treats a selector's vinPattern as an anchored regular +// expression over the full 17-character VIN. It is anchored here, not left +// to the pattern's author: under the open-contribution model these +// selectors are headed for, vinPattern is contributor-authored and the +// least-reviewed input in this path. An unanchored pattern matches anywhere +// in the string, so a pattern meant to identify one trim by a VIN prefix +// would silently claim every VIN that merely contains it as a substring. +// Anchoring here means correctness doesn't depend on every contributor +// remembering to anchor their own pattern. +// +// A malformed pattern is data the matcher cannot trust, so it fails safe +// (no match) rather than panicking -- consistent with MatchTrim never +// panicking on odd template data. Go's regexp is RE2: a hostile pattern is +// a compile error or a linear-time match, never catastrophic backtracking. +func vinMatchesPattern(pattern, vin string) bool { + re, err := regexp.Compile(`^(?:` + pattern + `)$`) + if err != nil { + return false + } + return re.MatchString(vin) +} + +// copyAttributes returns an independent copy of base, never nil, so callers +// can freely layer trim attributes on top without mutating the template. +func copyAttributes(base map[string]any) map[string]any { + out := make(map[string]any, len(base)) + for k, v := range base { + out[k] = v + } + return out +} + +// agreedAttributes returns only the attributes on which every candidate +// trim agrees, both on the key being present and its value being equal. +func agreedAttributes(matches []trimMatch) map[string]any { + if len(matches) == 0 { + return nil + } + agreed := make(map[string]any) + for k, v := range matches[0].trim.Attributes { + agree := true + for _, m := range matches[1:] { + other, ok := m.trim.Attributes[k] + if !ok || !reflect.DeepEqual(other, v) { + agree = false + break + } + } + if agree { + agreed[k] = v + } + } + return agreed +} diff --git a/internal/core/services/trim_match_test.go b/internal/core/services/trim_match_test.go new file mode 100644 index 00000000..d531c9b0 --- /dev/null +++ b/internal/core/services/trim_match_test.go @@ -0,0 +1,204 @@ +package services + +import ( + "testing" + + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func camry() *coremodels.Template { + return &coremodels.Template{ + ID: "toyota_camry_2020", DeviceType: "vehicle", + Manufacturer: coremodels.TemplateManufacturer{Slug: "toyota", Name: "Toyota", TokenID: 131}, + Model: "Camry", Year: 2020, Version: 3, + Attributes: map[string]any{"number_of_doors": float64(4)}, + Trims: []coremodels.Trim{ + {Name: "LE", Selectors: coremodels.TrimSelectors{ManufacturerCode: []string{"2532"}}, + Attributes: map[string]any{"powertrain_type": "ICE", "fuel_tank_capacity_gal": 16.0, "driven_wheels": "FWD"}}, + {Name: "Hybrid LE", Selectors: coremodels.TrimSelectors{ManufacturerCode: []string{"2559"}}, + Attributes: map[string]any{"powertrain_type": "HEV", "fuel_tank_capacity_gal": 13.2, "driven_wheels": "FWD"}}, + }, + } +} + +func TestMatchTrim_ExactOnManufacturerCode(t *testing.T) { + r := MatchTrim(camry(), MatchSignals{ManufacturerCode: "2559"}) + assert.Equal(t, MatchExact, r.Quality) + assert.Equal(t, "Hybrid LE", r.Trim) + assert.Equal(t, []string{"manufacturerCode"}, r.MatchedBy) + assert.Equal(t, "HEV", r.Attributes["powertrain_type"]) + assert.Equal(t, 13.2, r.Attributes["fuel_tank_capacity_gal"]) + // Template-level attributes merge in. + assert.Equal(t, float64(4), r.Attributes["number_of_doors"]) + assert.Equal(t, 3, r.TemplateVersion) +} + +func TestMatchTrim_TheBlendedCamryIsNoLongerPossible(t *testing.T) { + // The production record declares ICE while carrying the hybrid's 13.2 gal + // tank. Whichever trim matches, powertrain and tank must come from the + // SAME trim. + for _, tc := range []struct { + code, pt string + tank float64 + }{ + {"2532", "ICE", 16.0}, + {"2559", "HEV", 13.2}, + } { + r := MatchTrim(camry(), MatchSignals{ManufacturerCode: tc.code}) + assert.Equal(t, tc.pt, r.Attributes["powertrain_type"]) + assert.Equal(t, tc.tank, r.Attributes["fuel_tank_capacity_gal"]) + } +} + +func TestMatchTrim_AmbiguousEmitsOnlyAgreedAttributes(t *testing.T) { + tmpl := camry() + // Both trims claim the same code: a template defect, not a decode failure. + tmpl.Trims[1].Selectors.ManufacturerCode = []string{"2532"} + r := MatchTrim(tmpl, MatchSignals{ManufacturerCode: "2532"}) + assert.Equal(t, MatchAmbiguous, r.Quality) + assert.ElementsMatch(t, []string{"LE", "Hybrid LE"}, r.Candidates) + assert.Empty(t, r.Trim) + // They disagree on powertrain and tank, agree on drive. + assert.NotContains(t, r.Attributes, "powertrain_type") + assert.NotContains(t, r.Attributes, "fuel_tank_capacity_gal") + assert.Equal(t, "FWD", r.Attributes["driven_wheels"]) +} + +func TestMatchTrim_ModelOnlyWhenNothingMatches(t *testing.T) { + r := MatchTrim(camry(), MatchSignals{ManufacturerCode: "9999"}) + assert.Equal(t, MatchModelOnly, r.Quality) + assert.Empty(t, r.Trim) + // Only template-level attributes survive; no trim's values leak in. + assert.Equal(t, float64(4), r.Attributes["number_of_doors"]) + assert.NotContains(t, r.Attributes, "powertrain_type") +} + +func TestMatchTrim_SingleTrimTemplateMatchesWithoutSelectors(t *testing.T) { + tmpl := camry() + tmpl.Trims = tmpl.Trims[:1] + tmpl.Trims[0].Selectors = coremodels.TrimSelectors{} + r := MatchTrim(tmpl, MatchSignals{}) + assert.Equal(t, MatchExact, r.Quality) + assert.Equal(t, "LE", r.Trim) +} + +func TestMatchTrim_StyleNameIsCaseInsensitive(t *testing.T) { + tmpl := camry() + tmpl.Trims[0].Selectors = coremodels.TrimSelectors{StyleName: []string{"LE 4dr Sedan"}} + r := MatchTrim(tmpl, MatchSignals{StyleName: "le 4dr sedan"}) + assert.Equal(t, MatchExact, r.Quality) + assert.Equal(t, "LE", r.Trim) +} + +func TestMatchTrim_TrimOverridesTemplateHardwareTemplateID(t *testing.T) { + tmpl := camry() + tmpl.HardwareTemplateID = "130" + tmpl.Trims[1].HardwareTemplateID = "115" + r := MatchTrim(tmpl, MatchSignals{ManufacturerCode: "2559"}) + assert.Equal(t, "115", r.HardwareTemplateID) + r2 := MatchTrim(tmpl, MatchSignals{ManufacturerCode: "2532"}) + assert.Equal(t, "130", r2.HardwareTemplateID) +} + +func TestMatchTrim_EmptyTemplateIsModelOnlyNotAPanic(t *testing.T) { + tmpl := camry() + tmpl.Trims = nil + r := MatchTrim(tmpl, MatchSignals{ManufacturerCode: "2532"}) + assert.Equal(t, MatchModelOnly, r.Quality) + require.NotNil(t, r.Attributes) +} + +func TestMatchTrim_HardwareTemplateIDStaysTemplatesWhenAmbiguous(t *testing.T) { + tmpl := camry() + tmpl.HardwareTemplateID = "130" + tmpl.Trims[0].HardwareTemplateID = "115" + tmpl.Trims[1].HardwareTemplateID = "999" + // Both trims claim the same code: a template defect, not a decode failure. + tmpl.Trims[1].Selectors.ManufacturerCode = []string{"2532"} + r := MatchTrim(tmpl, MatchSignals{ManufacturerCode: "2532"}) + require.Equal(t, MatchAmbiguous, r.Quality) + // Neither candidate's HardwareTemplateID wins -- that would still be + // picking one, in the field that decides what hardware DIMO ships. + assert.Equal(t, "130", r.HardwareTemplateID) +} + +func TestMatchTrim_HardwareTemplateIDStaysTemplatesWhenModelOnly(t *testing.T) { + tmpl := camry() + tmpl.HardwareTemplateID = "130" + tmpl.Trims[0].HardwareTemplateID = "115" + tmpl.Trims[1].HardwareTemplateID = "999" + r := MatchTrim(tmpl, MatchSignals{ManufacturerCode: "9999"}) + require.Equal(t, MatchModelOnly, r.Quality) + assert.Equal(t, "130", r.HardwareTemplateID) +} + +func TestMatchTrim_VINPatternIsAnchoredToTheWholeVIN(t *testing.T) { + tmpl := camry() + tmpl.Trims = tmpl.Trims[:1] + tmpl.Trims[0].Selectors = coremodels.TrimSelectors{VINPattern: "4T1B11HK.{9}"} + + whole := MatchTrim(tmpl, MatchSignals{VIN: "4T1B11HK5LU123456"}) + assert.Equal(t, MatchExact, whole.Quality) + + // The same pattern is a bare substring of a longer VIN. Unanchored, + // regexp.MatchString would find it anywhere in the string; anchored, it + // must not match unless the pattern accounts for the whole VIN. + substring := MatchTrim(tmpl, MatchSignals{VIN: "XX4T1B11HK5LU123456XX"}) + assert.Equal(t, MatchModelOnly, substring.Quality) +} + +func TestMatchTrim_InvalidVINPatternDoesNotMatchOrPanic(t *testing.T) { + tmpl := camry() + tmpl.Trims = tmpl.Trims[:1] + tmpl.Trims[0].Selectors = coremodels.TrimSelectors{VINPattern: "("} + assert.NotPanics(t, func() { + r := MatchTrim(tmpl, MatchSignals{VIN: "4T1B11HK5LU123456"}) + assert.Equal(t, MatchModelOnly, r.Quality) + }) +} + +func TestMatchTrim_EmptyVINSignalDoesNotMatchVINPattern(t *testing.T) { + tmpl := camry() + tmpl.Trims = tmpl.Trims[:1] + tmpl.Trims[0].Selectors = coremodels.TrimSelectors{VINPattern: "4T1B11HK.{9}"} + r := MatchTrim(tmpl, MatchSignals{}) + assert.Equal(t, MatchModelOnly, r.Quality) +} + +// Selectors are a conjunction: a trim declaring both manufacturerCode and +// styleName matches only when BOTH agree. Until now the AND was verified by +// reading the code, and reading the code is exactly what has repeatedly +// missed defects in this migration. If it ever degraded to an OR, a VIN +// carrying the right style name but the wrong OEM code would resolve to a +// trim it is not, silently -- the failure mode the matcher exists to prevent. +func TestMatchTrim_SelectorsAreConjunctiveNotDisjunctive(t *testing.T) { + tmpl := camry() + tmpl.Trims[0].Selectors = coremodels.TrimSelectors{ + ManufacturerCode: []string{"2532"}, + StyleName: []string{"LE 4dr Sedan"}, + } + // Give the other trim selectors nothing can match, so any result other + // than "trim 0 matched" is unambiguously trim 0 failing to match. + tmpl.Trims[1].Selectors = coremodels.TrimSelectors{ManufacturerCode: []string{"none"}} + + // Both agree: matched. + both := MatchTrim(tmpl, MatchSignals{ManufacturerCode: "2532", StyleName: "LE 4dr Sedan"}) + require.Equal(t, MatchExact, both.Quality) + assert.Equal(t, "LE", both.Trim) + assert.ElementsMatch(t, []string{"manufacturerCode", "styleName"}, both.MatchedBy) + + // Only the style name agrees: no match. + styleOnly := MatchTrim(tmpl, MatchSignals{ManufacturerCode: "9999", StyleName: "LE 4dr Sedan"}) + assert.Equal(t, MatchModelOnly, styleOnly.Quality, "styleName alone must not satisfy a trim that also declares a manufacturerCode") + + // Only the code agrees: no match. + codeOnly := MatchTrim(tmpl, MatchSignals{ManufacturerCode: "2532", StyleName: "XSE 4dr Sedan"}) + assert.Equal(t, MatchModelOnly, codeOnly.Quality, "manufacturerCode alone must not satisfy a trim that also declares a styleName") + + // A declared selector with no corresponding signal is a non-match, not a + // free pass: an absent signal cannot confirm a selector. + codeOnlySignal := MatchTrim(tmpl, MatchSignals{ManufacturerCode: "2532"}) + assert.Equal(t, MatchModelOnly, codeOnlySignal.Quality, "a missing styleName signal must not satisfy a declared styleName selector") +} diff --git a/internal/core/services/vin_decoding_service.go b/internal/core/services/vin_decoding_service.go index 4360e1f1..d44a368d 100644 --- a/internal/core/services/vin_decoding_service.go +++ b/internal/core/services/vin_decoding_service.go @@ -27,6 +27,10 @@ import ( type VINDecodingService interface { // GetVIN decodes a vin using one of the providers passed in or if AllProviders applies an ordered logic. Only pass TeslaProvider if know it is a Tesla. + // + // The vendor extra is never nil, on any path including a failure: it is + // what the caller writes to failed_vin_decodes, and returning nil there + // panicked the decode instead of recording the failure. GetVIN(ctx context.Context, vin string, provider coremodels.DecodeProviderEnum, country string) (*coremodels.VINDecodingInfoData, *coremodels.VINDecodingVendorExtra, error) } @@ -39,15 +43,15 @@ type vinDecodingService struct { japan17VINAPI gateways.Japan17VINAPI carvxAPI gateways.CarVxVINAPI elevaAPI gateways.ElevaAPI - onChainSvc gateways.DeviceDefinitionOnChainService + catalogSvc gateways.DeviceDefinitionCatalogService dbs func() *db.ReaderWriter } func NewVINDecodingService(drivlyAPISvc gateways.DrivlyAPIService, vincarioAPISvc gateways.VincarioAPIService, autoIso gateways.AutoIsoAPIService, logger *zerolog.Logger, - onChainSvc gateways.DeviceDefinitionOnChainService, datGroupAPIService gateways.DATGroupAPIService, dbs func() *db.ReaderWriter, + catalogSvc gateways.DeviceDefinitionCatalogService, datGroupAPIService gateways.DATGroupAPIService, dbs func() *db.ReaderWriter, japan17VINAPI gateways.Japan17VINAPI, carvxAPI gateways.CarVxVINAPI, elevaAPI gateways.ElevaAPI) VINDecodingService { return &vinDecodingService{drivlyAPISvc: drivlyAPISvc, vincarioAPISvc: vincarioAPISvc, autoIsoAPIService: autoIso, - japan17VINAPI: japan17VINAPI, carvxAPI: carvxAPI, logger: logger, onChainSvc: onChainSvc, + japan17VINAPI: japan17VINAPI, carvxAPI: carvxAPI, logger: logger, catalogSvc: catalogSvc, DATGroupAPIService: datGroupAPIService, dbs: dbs, elevaAPI: elevaAPI} } @@ -62,11 +66,17 @@ func (c vinDecodingService) GetVIN(ctx context.Context, vin string, provider cor if country == "CHL" { providersToTry = append(providersToTry, coremodels.ElevaKaufmannProvider) providersToTry = append(providersToTry, coremodels.VincarioProvider) // sometimes works in latam as backup - } else if provider == coremodels.AllProviders && ((len(vin) < 17 && len(vin) > 10) || country == "JPN") { + } else if provider == coremodels.AllProviders && ((len(vin) < 17 && len(vin) >= 10) || country == "JPN") { + // A Japan chassis number can be exactly 10 characters (ZWR9-80001); + // Handle admits one, and IsValidJapanChassis accepts one. Excluding + // that length sent a perfectly valid chassis number to the 17-character + // VIN validator, which refused it before any provider was tried. providersToTry = append(providersToTry, coremodels.CarVXVIN) providersToTry = append(providersToTry, coremodels.Japan17VIN) } else if !ValidateVIN(vin) { - return nil, nil, fmt.Errorf("invalid vin: %s", vin) + // The vendor extra is returned on every path, never nil: the caller + // reads it to record the failure, and a nil there panicked the decode. + return nil, resultVendorExtra, fmt.Errorf("invalid vin: %s", vin) } localLog := c.logger.With(). @@ -75,12 +85,12 @@ func (c vinDecodingService) GetVIN(ctx context.Context, vin string, provider cor Logger() if strings.HasPrefix(vin, "0SC") { - dd, _, err := c.onChainSvc.GetDefinitionByID(ctx, DefaultDefinitionID) + dd, _, err := c.catalogSvc.GetTemplateByID(ctx, DefaultDefinitionID) if err != nil { - return nil, nil, err + return nil, resultVendorExtra, errors.Wrapf(err, "unable to read the test-VIN template %s", DefaultDefinitionID) } result = buildFromDDForTestVIN(vin, dd) - return result, nil, nil + return result, resultVendorExtra, nil } if len(providersToTry) == 0 { @@ -343,15 +353,16 @@ func buildFromDrivly(info *coremodels.DrivlyVINResponse) (*coremodels.VINDecodin yrInt, _ := strconv.Atoi(info.Year) v := &coremodels.VINDecodingInfoData{ - VIN: info.Vin, - Year: int32(yrInt), - Make: info.Make, - Model: info.Model, - StyleName: buildDrivlyStyleName(info), - ExternalID: info.GetExternalID(), - Source: coremodels.DrivlyProvider, - Raw: raw, - FuelType: info.Fuel, + VIN: info.Vin, + Year: int32(yrInt), + Make: info.Make, + Model: info.Model, + StyleName: buildDrivlyStyleName(info), + ExternalID: info.GetExternalID(), + Source: coremodels.DrivlyProvider, + Raw: raw, + FuelType: info.Fuel, + ManufacturerCode: info.ManufacturerCode, } if err := validateVinDecoding(v); err != nil { return nil, err @@ -364,7 +375,7 @@ func buildDrivlyStyleName(vinInfo *coremodels.DrivlyVINResponse) string { } // buildFromDDForTestVIN meant for use with test VIN's -func buildFromDDForTestVIN(vin string, info *coremodels.DeviceDefinitionTablelandModel) *coremodels.VINDecodingInfoData { +func buildFromDDForTestVIN(vin string, info *coremodels.Template) *coremodels.VINDecodingInfoData { makeSlug := strings.Split(info.ID, "_")[0] v := &coremodels.VINDecodingInfoData{ diff --git a/internal/core/services/vin_decoding_service_test.go b/internal/core/services/vin_decoding_service_test.go index 24c78c94..67c2f097 100644 --- a/internal/core/services/vin_decoding_service_test.go +++ b/internal/core/services/vin_decoding_service_test.go @@ -34,7 +34,7 @@ type VINDecodingServiceSuite struct { mockJapan17VINAPI *mock_gateways.MockJapan17VINAPI mockCarvxAPI *mock_gateways.MockCarVxVINAPI - mockOnChainSvc *mock_gateways.MockDeviceDefinitionOnChainService + mockOnChainSvc *mock_gateways.MockDeviceDefinitionCatalogService vinDecodingService VINDecodingService mockElevaAPI *mock_gateways.MockElevaAPI } @@ -63,7 +63,7 @@ func (s *VINDecodingServiceSuite) SetupTest() { s.mockJapan17VINAPI = mock_gateways.NewMockJapan17VINAPI(s.ctrl) s.mockCarvxAPI = mock_gateways.NewMockCarVxVINAPI(s.ctrl) s.mockElevaAPI = mock_gateways.NewMockElevaAPI(s.ctrl) - s.mockOnChainSvc = mock_gateways.NewMockDeviceDefinitionOnChainService(s.ctrl) + s.mockOnChainSvc = mock_gateways.NewMockDeviceDefinitionCatalogService(s.ctrl) s.vinDecodingService = NewVINDecodingService(s.mockDrivlyAPISvc, s.mockVincarioAPISvc, s.mockAutoIsoAPISvc, dbtesthelper.Logger(), s.mockOnChainSvc, s.mockDATGroupAPIService, s.pdb.DBS, s.mockJapan17VINAPI, s.mockCarvxAPI, s.mockElevaAPI) @@ -170,6 +170,7 @@ func (s *VINDecodingServiceSuite) Test_VINDecodingService_Drivly_Success() { s.NoError(err) assert.Equal(s.T(), result.VIN, vin) assert.Equal(s.T(), result.Source, coremodels.DrivlyProvider) + assert.Equal(s.T(), "1234", result.ManufacturerCode, "buildFromDrivly must carry DrivlyVINResponse.ManufacturerCode through, not drop it") } func (s *VINDecodingServiceSuite) Test_VINDecodingService_Tesla() { @@ -254,7 +255,11 @@ func (s *VINDecodingServiceSuite) Test_VINDecodingService_DD_Default_Success() { dm := dbtesthelper.SetupCreateMake("Ford") dd := dbtesthelper.SetupCreateDeviceDefinition(s.T(), dm.Name, "Escape", 2020, s.pdb) - s.mockOnChainSvc.EXPECT().GetDefinitionByID(ctx, dd.ID).Times(1).Return(dd, nil, nil) + s.mockOnChainSvc.EXPECT().GetTemplateByID(ctx, dd.ID).Times(1).Return(&coremodels.Template{ + ID: dd.ID, + Model: dd.Model, + Year: dd.Year, + }, nil, nil) result, _, err := s.vinDecodingService.GetVIN(ctx, vin, coremodels.AllProviders, country) diff --git a/internal/core/services/vin_decoding_vendor_extra_test.go b/internal/core/services/vin_decoding_vendor_extra_test.go new file mode 100644 index 00000000..b24dd31a --- /dev/null +++ b/internal/core/services/vin_decoding_vendor_extra_test.go @@ -0,0 +1,121 @@ +package services + +import ( + "context" + "errors" + "testing" + + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" + mock_gateways "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways/mocks" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +// GetVIN's vendor extra is what the decode handler writes to +// failed_vin_decodes when nothing could decode the VIN. Returning nil there +// left the caller dereferencing nothing, so the decode panicked, recorded no +// failure, and repeated the whole vendor fan-out on the next request. +// +// These paths need no Postgres: they return before any provider that touches +// the database. + +func vendorExtraService(t *testing.T) (vinDecodingService, *mock_gateways.MockDeviceDefinitionCatalogService, *gomock.Controller) { + t.Helper() + ctrl := gomock.NewController(t) + t.Cleanup(ctrl.Finish) + logger := zerolog.Nop() + catalog := mock_gateways.NewMockDeviceDefinitionCatalogService(ctrl) + return vinDecodingService{logger: &logger, catalogSvc: catalog}, catalog, ctrl +} + +// The guard that refuses a VIN before any provider is tried. +func TestGetVINReturnsAVendorExtraForAnInvalidVIN(t *testing.T) { + svc, _, _ := vendorExtraService(t) + + info, extra, err := svc.GetVIN(context.Background(), "NOTAVIN", coremodels.AllProviders, "USA") + + require.Error(t, err) + assert.Nil(t, info) + require.NotNil(t, extra, "the caller records the failure from the vendor extra; it may never be nil") + assert.Empty(t, extra.VendorsTried) +} + +// The 0SC test-VIN branch reads a template from the catalog, so it now fails +// whenever the catalog does -- including the not-found this branch sees +// wherever the template import has not run. +func TestGetVINReturnsAVendorExtraWhenTheTestVINTemplateIsUnavailable(t *testing.T) { + svc, catalog, _ := vendorExtraService(t) + catalog.EXPECT().GetTemplateByID(gomock.Any(), "ford_escape_2020"). + Return(nil, nil, errors.New("template not found")) + + info, extra, err := svc.GetVIN(context.Background(), "0SC12345678901234", coremodels.AllProviders, "USA") + + require.Error(t, err) + assert.Nil(t, info) + require.NotNil(t, extra, "the caller records the failure from the vendor extra; it may never be nil") +} + +// A successful test-VIN decode returns one too, so no caller has to care which +// branch produced the answer. +func TestGetVINReturnsAVendorExtraForADecodedTestVIN(t *testing.T) { + svc, catalog, _ := vendorExtraService(t) + catalog.EXPECT().GetTemplateByID(gomock.Any(), "ford_escape_2020"). + Return(&coremodels.Template{ + ID: "ford_escape_2020", + Model: "Escape", + Year: 2020, + DeviceType: "vehicle", + Manufacturer: coremodels.TemplateManufacturer{Slug: "ford", Name: "Ford"}, + }, nil, nil) + + info, extra, err := svc.GetVIN(context.Background(), "0SC12345678901234", coremodels.AllProviders, "USA") + + require.NoError(t, err) + require.NotNil(t, info) + require.NotNil(t, extra) +} + +// A 10-character Japan chassis number is one the handler admits and +// IsValidJapanChassis accepts. The provider guard excluded exactly 10, so it +// fell through to the 17-character VIN validator and was refused before any +// provider was tried. +func TestGetVINSendsATenCharacterChassisToTheJapanProviders(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + logger := zerolog.Nop() + carvx := mock_gateways.NewMockCarVxVINAPI(ctrl) + japan := mock_gateways.NewMockJapan17VINAPI(ctrl) + carvx.EXPECT().GetVINInfo("ZWR980001").Times(0) + carvx.EXPECT().GetVINInfo("ZWR9-80001").Return(nil, nil, errors.New("carvx is down")) + japan.EXPECT().GetVINInfo("ZWR9-80001").Return(nil, nil, errors.New("japan17 is down")) + svc := vinDecodingService{logger: &logger, carvxAPI: carvx, japan17VINAPI: japan} + + info, extra, err := svc.GetVIN(context.Background(), "ZWR9-80001", coremodels.AllProviders, "JPN") + + require.Error(t, err) + assert.Nil(t, info) + require.NotNil(t, extra) + assert.Equal(t, []string{string(coremodels.CarVXVIN), string(coremodels.Japan17VIN)}, extra.VendorsTried, + "a 10 character chassis number belongs to the Japan providers, not the VIN validator") + assert.NotContains(t, err.Error(), "invalid vin") +} + +// The same chassis with no country hint: the length alone has to route it. +func TestGetVINSendsATenCharacterChassisToTheJapanProvidersWithoutACountry(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + logger := zerolog.Nop() + carvx := mock_gateways.NewMockCarVxVINAPI(ctrl) + japan := mock_gateways.NewMockJapan17VINAPI(ctrl) + carvx.EXPECT().GetVINInfo("ZWR9-80001").Return(nil, nil, errors.New("carvx is down")) + japan.EXPECT().GetVINInfo("ZWR9-80001").Return(nil, nil, errors.New("japan17 is down")) + svc := vinDecodingService{logger: &logger, carvxAPI: carvx, japan17VINAPI: japan} + + _, extra, err := svc.GetVIN(context.Background(), "ZWR9-80001", coremodels.AllProviders, "") + + require.Error(t, err) + require.NotNil(t, extra) + assert.Equal(t, []string{string(coremodels.CarVXVIN), string(coremodels.Japan17VIN)}, extra.VendorsTried) +} diff --git a/internal/core/vocabulary/testdata/device-type-vehicle.json b/internal/core/vocabulary/testdata/device-type-vehicle.json new file mode 100644 index 00000000..1c5b12b0 --- /dev/null +++ b/internal/core/vocabulary/testdata/device-type-vehicle.json @@ -0,0 +1,161 @@ +{ + "id": "vehicle", + "name": "Vehicle", + "attributes": [ + { + "name": "powertrain_type", + "label": "Powertrain", + "description": "Primary propulsion system.", + "type": "enum", + "variesByTrim": true, + "options": [ + "ICE", + "HEV", + "PHEV", + "BEV", + "FCEV" + ] + }, + { + "name": "fuel_type", + "label": "Fuel", + "description": "Fuel the vehicle consumes.", + "type": "enum", + "variesByTrim": true, + "options": [ + "gasoline", + "diesel", + "electric", + "flex_fuel", + "hydrogen", + "cng", + "lpg" + ] + }, + { + "name": "driven_wheels", + "label": "Drive", + "description": "Which wheels receive power.", + "type": "enum", + "variesByTrim": true, + "options": [ + "FWD", + "RWD", + "AWD", + "4WD" + ] + }, + { + "name": "vehicle_type", + "label": "Body style", + "type": "enum", + "variesByTrim": true, + "options": [ + "sedan", + "hatchback", + "wagon", + "coupe", + "convertible", + "suv", + "minivan", + "van", + "pickup", + "truck", + "motorcycle", + "chassis_cab", + "other" + ] + }, + { + "name": "number_of_doors", + "label": "Doors", + "type": "integer", + "minimum": 0, + "maximum": 8 + }, + { + "name": "base_msrp", + "label": "Base MSRP", + "type": "number", + "unit": "USD", + "minimum": 0, + "variesByTrim": true + }, + { + "name": "fuel_tank_capacity_gal", + "label": "Fuel tank capacity", + "type": "number", + "unit": "gal", + "minimum": 0, + "maximum": 200, + "variesByTrim": true + }, + { + "name": "battery_capacity_kwh", + "label": "Battery capacity", + "type": "number", + "unit": "kWh", + "minimum": 0, + "maximum": 500, + "variesByTrim": true + }, + { + "name": "mpg_city", + "label": "MPG city", + "type": "number", + "unit": "mpg", + "minimum": 0, + "maximum": 200, + "variesByTrim": true + }, + { + "name": "mpg_highway", + "label": "MPG highway", + "type": "number", + "unit": "mpg", + "minimum": 0, + "maximum": 200, + "variesByTrim": true + }, + { + "name": "mpg_combined", + "label": "MPG combined", + "type": "number", + "unit": "mpg", + "minimum": 0, + "maximum": 200, + "variesByTrim": true + }, + { + "name": "wheelbase_in", + "label": "Wheelbase", + "type": "number", + "unit": "in", + "minimum": 0, + "maximum": 400, + "variesByTrim": true + }, + { + "name": "manufacturer_code", + "label": "OEM model code", + "description": "Manufacturer's own code for this trim. Used to match a decoded VIN.", + "type": "string", + "variesByTrim": true + }, + { + "name": "emissions_standard", + "label": "Emissions standard", + "type": "enum", + "variesByTrim": true, + "options": [ + "euro_4", + "euro_5", + "euro_6", + "euro_6d", + "tier_2", + "tier_3", + "other" + ] + } + ] +} diff --git a/internal/core/vocabulary/testdata/regenerate-parity.mjs b/internal/core/vocabulary/testdata/regenerate-parity.mjs new file mode 100644 index 00000000..9bb2ff1f --- /dev/null +++ b/internal/core/vocabulary/testdata/regenerate-parity.mjs @@ -0,0 +1,18 @@ +import { readFile } from 'node:fs/promises'; +import { mapAttributes } from '../../../../../definitions-worker/scripts/extract/vocabulary.mjs'; +const vocab = JSON.parse(await readFile(new URL('./device-type-vehicle.json', import.meta.url),'utf8')); +const cases = [ + {fuel_type:'Petrol'}, {fuel_type:'Hybrid'}, {fuel_type:'Flexible Fuel Vehicle (FFV)'}, + {driven_wheels:'4x2'}, {driven_wheels:'AWD/All-Wheel Drive'}, {driven_wheels:'4WD/4-Wheel Drive/4x4'}, + {epa_class:'6L'}, {epa_class:'Euro 6d-Temp'}, {epa_class:'Calss III'}, + {vehicle_type:'Crossover Utility Vehicle (CUV)'}, {vehicle_type:'Incomplete Vehicle'}, + {wheelbase:'111.2 in'}, {wheelbase:'abc'}, + {number_of_doors:'4'}, {number_of_doors:'4.5'}, {number_of_doors:'99'}, + {fuel_tank_capacity_gal:'15.800000'}, {mpg:'28'}, + {generation:'6'}, {fuel_type:''}, {fuel_type:''}, {powertrain_type:'ICE'}, +]; +const out = cases.map((c) => { + const { mapped, dropped } = mapAttributes(c, vocab); + return { in: c, mapped, dropped: dropped.map(d => ({name: d.name, reason: d.reason})) }; +}); +console.log(JSON.stringify(out, null, 1)); diff --git a/internal/core/vocabulary/testdata/vocabulary_parity.json b/internal/core/vocabulary/testdata/vocabulary_parity.json new file mode 100644 index 00000000..72350a6c --- /dev/null +++ b/internal/core/vocabulary/testdata/vocabulary_parity.json @@ -0,0 +1,217 @@ +[ + { + "in": { + "fuel_type": "Petrol" + }, + "mapped": { + "fuel_type": "gasoline" + }, + "dropped": [] + }, + { + "in": { + "fuel_type": "Hybrid" + }, + "mapped": { + "fuel_type": "gasoline" + }, + "dropped": [] + }, + { + "in": { + "fuel_type": "Flexible Fuel Vehicle (FFV)" + }, + "mapped": { + "fuel_type": "flex_fuel" + }, + "dropped": [] + }, + { + "in": { + "driven_wheels": "4x2" + }, + "mapped": {}, + "dropped": [ + { + "name": "driven_wheels", + "reason": "ambiguous: names a driven wheel count, not an axle — could be RWD or FWD (or split further on multi-axle trucks) depending on the vehicle" + } + ] + }, + { + "in": { + "driven_wheels": "AWD/All-Wheel Drive" + }, + "mapped": { + "driven_wheels": "AWD" + }, + "dropped": [] + }, + { + "in": { + "driven_wheels": "4WD/4-Wheel Drive/4x4" + }, + "mapped": { + "driven_wheels": "4WD" + }, + "dropped": [] + }, + { + "in": { + "epa_class": "6L" + }, + "mapped": {}, + "dropped": [ + { + "name": "epa_class", + "reason": "unmapped: a known epa_class code with no vocabulary equivalent, deliberately left unmapped pending identification of the source coding scheme" + } + ] + }, + { + "in": { + "epa_class": "Euro 6d-Temp" + }, + "mapped": { + "emissions_standard": "euro_6d" + }, + "dropped": [] + }, + { + "in": { + "epa_class": "Calss III" + }, + "mapped": {}, + "dropped": [ + { + "name": "epa_class", + "reason": "value not in the vocabulary and no mapping" + } + ] + }, + { + "in": { + "vehicle_type": "Crossover Utility Vehicle (CUV)" + }, + "mapped": { + "vehicle_type": "suv" + }, + "dropped": [] + }, + { + "in": { + "vehicle_type": "Incomplete Vehicle" + }, + "mapped": { + "vehicle_type": "chassis_cab" + }, + "dropped": [] + }, + { + "in": { + "wheelbase": "111.2 in" + }, + "mapped": { + "wheelbase_in": 111.2 + }, + "dropped": [] + }, + { + "in": { + "wheelbase": "abc" + }, + "mapped": {}, + "dropped": [ + { + "name": "wheelbase", + "reason": "unparseable wheelbase" + } + ] + }, + { + "in": { + "number_of_doors": "4" + }, + "mapped": { + "number_of_doors": 4 + }, + "dropped": [] + }, + { + "in": { + "number_of_doors": "4.5" + }, + "mapped": {}, + "dropped": [ + { + "name": "number_of_doors", + "reason": "not an integer" + } + ] + }, + { + "in": { + "number_of_doors": "99" + }, + "mapped": {}, + "dropped": [ + { + "name": "number_of_doors", + "reason": "above the vocabulary range" + } + ] + }, + { + "in": { + "fuel_tank_capacity_gal": "15.800000" + }, + "mapped": { + "fuel_tank_capacity_gal": 15.8 + }, + "dropped": [] + }, + { + "in": { + "mpg": "28" + }, + "mapped": { + "mpg_combined": 28 + }, + "dropped": [] + }, + { + "in": { + "generation": "6" + }, + "mapped": {}, + "dropped": [ + { + "name": "generation", + "reason": "no such attribute in the vocabulary" + } + ] + }, + { + "in": { + "fuel_type": "" + }, + "mapped": {}, + "dropped": [] + }, + { + "in": { + "fuel_type": "" + }, + "mapped": {}, + "dropped": [] + }, + { + "in": { + "powertrain_type": "ICE" + }, + "mapped": { + "powertrain_type": "ICE" + }, + "dropped": [] + } +] diff --git a/internal/core/vocabulary/vocabulary.go b/internal/core/vocabulary/vocabulary.go new file mode 100644 index 00000000..79979689 --- /dev/null +++ b/internal/core/vocabulary/vocabulary.go @@ -0,0 +1,258 @@ +package vocabulary + +import ( + "fmt" + "math" + "regexp" + "sort" + "strconv" + "strings" +) + +// This is a port of definitions-worker/scripts/extract/vocabulary.mjs. The two +// must agree: the extraction import and a decode-path create write into the +// same contract, and a value one of them folds and the other drops produces a +// template whose attributes depend on which path created it. +// +// The governing rule, unchanged from the original: map a different name for +// the same thing; drop a value whose meaning would have to be invented. + +// DeviceType is /schema/device-type-vehicle.json. +type DeviceType struct { + ID string `json:"id"` + Name string `json:"name"` + Attributes []Attribute `json:"attributes"` +} + +type Attribute struct { + Name string `json:"name"` + Label string `json:"label"` + Type string `json:"type"` + Unit string `json:"unit,omitempty"` + Options []string `json:"options,omitempty"` + Minimum *float64 `json:"minimum,omitempty"` + Maximum *float64 `json:"maximum,omitempty"` + VariesByTrim bool `json:"variesByTrim,omitempty"` +} + +// DroppedAttribute records a value that was read and deliberately not carried. +// Reporting only parse failures is what makes a silent drop silent: the +// extraction's own follow-ups name this as the recurring defect class. +type DroppedAttribute struct { + Name string + Value string + Reason string +} + +func (d DroppedAttribute) String() string { + return fmt.Sprintf("%s=%q: %s", d.Name, d.Value, d.Reason) +} + +// rename maps a source field onto the vocabulary's name for it. The unit +// belongs in the vocabulary's `unit`, not in the attribute name. +var rename = map[string]string{ + "epa_class": "emissions_standard", + "wheelbase": "wheelbase_in", + "mpg": "mpg_combined", +} + +// valueMap is the vocabulary the catalog never had: Options[] was defined in +// 2022 and never populated, so the data holds 14 spellings of fuel_type, 17 of +// driven_wheels and 15 of epa_class. +// +// fuel_type hybrid -> gasoline is deliberate. A hybrid burns gasoline, and +// powertrain derivation has already turned "Hybrid" into powertrain_type HEV +// before this runs, so folding the leftover fuel_type string onto its actual +// fuel is what stops a hybrid record claiming a fuel the vocabulary lacks. +var valueMap = map[string]map[string]string{ + "fuel_type": { + "gasoline": "gasoline", "petrol": "gasoline", "diesel": "diesel", + "electric": "electric", "hybrid": "gasoline", + "flexible-fuel": "flex_fuel", "flexible fuel vehicle (ffv)": "flex_fuel", + "hydrogen": "hydrogen", "cng": "cng", "lpg": "lpg", + }, + "driven_wheels": { + "fwd": "FWD", "front-wheel drive": "FWD", "front wheel drive": "FWD", + "rwd": "RWD", "rear-wheel drive": "RWD", "rear wheel drive": "RWD", + "awd": "AWD", "all wheel drive": "AWD", "all-wheel drive": "AWD", + "4wd": "4WD", "4x4": "4WD", "4x4 - four-wheel drive": "4WD", + "4wd/4-wheel drive/4x4": "4WD", + // Slash-joined forms where both halves name the same axle: the source + // said the same thing twice, so folding them asserts nothing new. + // Unlike 4x2, there is no axle-count/drive-type conflict to arbitrate. + "fwd/front-wheel drive": "FWD", + "rwd/rear-wheel drive": "RWD", "rwd/ rear wheel drive": "RWD", + "awd/all-wheel drive": "AWD", + // '4x2' is deliberately absent -- see ambiguous below. + }, + "vehicle_type": { + "passenger car": "sedan", "sedan/saloon": "sedan", "sedan": "sedan", + "hatchback/liftback/notchback": "hatchback", "hatchback": "hatchback", + "wagon": "wagon", "coupe": "coupe", "cabriolet/convertible": "convertible", + "multipurpose passenger vehicle (mpv)": "suv", + "sport utility vehicle (suv)/multi purpose vehicle (mpv)": "suv", + "suv": "suv", + "minivan": "minivan", "van": "van", "pickup": "pickup", + "truck": "truck", "conventional type truck": "truck", + "motorcycle": "motorcycle", "incomplete vehicle": "chassis_cab", + "incomplete - chassis cab (single cab)": "chassis_cab", + // A crossover is a different name for a category the vocabulary already + // offers, not an assertion the source did not make. + "crossover utility vehicle (cuv)": "suv", + }, + "emissions_standard": { + "euro 4": "euro_4", "euro 5": "euro_5", + "euro 6": "euro_6", "euro6": "euro_6", "euro 6 b": "euro_6", + "euro 6 w": "euro_6", "euro 6 dg": "euro_6", + "euro 6d": "euro_6d", "euro6d-temp": "euro_6d", "euro 6d-temp": "euro_6d", + "euro 6d-isc-fcm": "euro_6d", "euro 6d/euro 6": "euro_6d", + }, +} + +// '4x2' and '6x4' state how many wheels are driven, not which: 4x2 is RWD on +// most pickups and FWD on most cars. A wrong guess looks exactly like a +// verified fact downstream and nobody rechecks it; a dropped attribute is +// recoverable by a Console contributor who knows the vehicle. +const wheelCountAmbiguous = "ambiguous: names a driven wheel count, not an axle — could be RWD or FWD (or split further on multi-axle trucks) depending on the vehicle" + +// '6L'/'5L'/'4L'/'U' are a real epa_class coding nobody on this migration has +// identified. Unlike 4x2 the value does not assert the wrong thing; its +// meaning is unknown, so there is nothing to map it to without guessing. +const unidentifiedEPACode = "unmapped: a known epa_class code with no vocabulary equivalent, deliberately left unmapped pending identification of the source coding scheme" + +// ambiguous routes deliberate drops through their own reason. The generic +// "value not in the vocabulary" reason is used for genuine spelling gaps and +// typos, and would make these decisions invisible to anyone reading the drop +// report rather than this file -- which is everyone the report is for. +var ambiguous = map[string]map[string]string{ + "driven_wheels": { + "4x2": wheelCountAmbiguous, + "6x4": wheelCountAmbiguous, + }, + "emissions_standard": { + "6l": unidentifiedEPACode, + "5l": unidentifiedEPACode, + "4l": unidentifiedEPACode, + "u": unidentifiedEPACode, + }, +} + +// dead values are the placeholders the old model used for "unknown". The +// contract makes them unrepresentable: an unknown attribute is absent. +var dead = map[string]struct{}{"": {}, "": {}, "null": {}, "N/A": {}} + +var leadingNumber = regexp.MustCompile(`^([\d.]+)`) + +// MapAttributes folds source attribute name/value pairs onto the vocabulary, +// returning typed values and an explicit account of everything it did not +// carry. Order of the input does not affect the result. +func MapAttributes(attrs map[string]string, vocab *DeviceType) (map[string]any, []DroppedAttribute) { + mapped := map[string]any{} + dropped := []DroppedAttribute{} + if vocab == nil { + return mapped, dropped + } + defs := make(map[string]Attribute, len(vocab.Attributes)) + for _, a := range vocab.Attributes { + defs[a.Name] = a + } + + // Sorted so the drop report is stable between runs; map iteration order + // would otherwise reorder it on every call. + for _, rawName := range sortedKeys(attrs) { + rawValue := attrs[rawName] + drop := func(reason string) { + dropped = append(dropped, DroppedAttribute{Name: rawName, Value: rawValue, Reason: reason}) + } + // Tested against the raw value, as the original does: a + // whitespace-only value is not dead, it fails its type check below and + // is reported as a drop rather than vanishing. + if _, isDead := dead[rawValue]; isDead { + continue + } + name := rawName + if renamed, ok := rename[rawName]; ok { + name = renamed + } + def, ok := defs[name] + if !ok { + drop("no such attribute in the vocabulary") + continue + } + + value := strings.TrimSpace(rawValue) + + if reason, isAmbiguous := ambiguous[name][strings.ToLower(value)]; isAmbiguous { + drop(reason) + continue + } + + if name == "wheelbase_in" { + m := leadingNumber.FindStringSubmatch(value) + if m == nil { + drop("unparseable wheelbase") + continue + } + value = m[1] + } + + switch def.Type { + case "enum": + hit, found := valueMap[name][strings.ToLower(value)] + if !found { + for _, opt := range def.Options { + if opt == value { + hit, found = value, true + break + } + } + } + if !found { + drop("value not in the vocabulary and no mapping") + continue + } + mapped[name] = hit + case "number", "integer": + n, err := strconv.ParseFloat(value, 64) + if err != nil || math.IsInf(n, 0) || math.IsNaN(n) { + drop("not a number") + continue + } + if def.Type == "integer" && n != math.Trunc(n) { + drop("not an integer") + continue + } + if def.Minimum != nil && n < *def.Minimum { + drop("below the vocabulary range") + continue + } + if def.Maximum != nil && n > *def.Maximum { + drop("above the vocabulary range") + continue + } + if def.Type == "integer" { + mapped[name] = int(n) + continue + } + mapped[name] = n + case "boolean": + if value != "true" && value != "false" { + drop("not a boolean") + continue + } + mapped[name] = value == "true" + default: + mapped[name] = value + } + } + return mapped, dropped +} + +func sortedKeys(m map[string]string) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} diff --git a/internal/core/vocabulary/vocabulary_parity_test.go b/internal/core/vocabulary/vocabulary_parity_test.go new file mode 100644 index 00000000..ff5b09fa --- /dev/null +++ b/internal/core/vocabulary/vocabulary_parity_test.go @@ -0,0 +1,74 @@ +package vocabulary + +import ( + "encoding/json" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// MapAttributes is a port, and the risk a port carries is that the two copies +// drift silently. The extraction import and a decode-path create write into the +// same contract: if one folds a value the other drops, a template's attributes +// depend on which path happened to create it, which is unobservable from either +// side. +// +// testdata/vocabulary_parity.json is the OUTPUT of the JavaScript original, run +// against the real vocabulary. Regenerate it with: +// +// node internal/core/services/testdata/regenerate-parity.mjs > \ +// internal/core/services/testdata/vocabulary_parity.json +// +// A diff there is the two implementations disagreeing. Resolve it; do not +// regenerate to make this pass. +type parityCase struct { + In map[string]string `json:"in"` + Mapped map[string]any `json:"mapped"` + Dropped []struct { + Name string `json:"name"` + Reason string `json:"reason"` + } `json:"dropped"` +} + +func TestMapAttributesMatchesTheJavaScriptOriginal(t *testing.T) { + rawVocab, err := os.ReadFile("testdata/device-type-vehicle.json") + require.NoError(t, err) + var vocab DeviceType + require.NoError(t, json.Unmarshal(rawVocab, &vocab)) + require.NotEmpty(t, vocab.Attributes, "the real vocabulary must load, or this compares nothing") + + rawCases, err := os.ReadFile("testdata/vocabulary_parity.json") + require.NoError(t, err) + var cases []parityCase + require.NoError(t, json.Unmarshal(rawCases, &cases)) + require.NotEmpty(t, cases) + + for _, c := range cases { + mapped, dropped := MapAttributes(c.In, &vocab) + + // Through JSON so an int on one side and a float on the other are + // compared as the contract sees them, not as Go types. + var got map[string]any + b, err := json.Marshal(mapped) + require.NoError(t, err) + require.NoError(t, json.Unmarshal(b, &got)) + if len(got) == 0 { + got = map[string]any{} + } + want := c.Mapped + if want == nil { + want = map[string]any{} + } + assert.Equal(t, want, got, "mapped values differ for %v", c.In) + + require.Len(t, dropped, len(c.Dropped), "drop count differs for %v", c.In) + for i, d := range c.Dropped { + assert.Equal(t, d.Name, dropped[i].Name, "dropped name differs for %v", c.In) + // The reason is the part a human reads to decide whether a drop was + // a decision or a defect, so it has to match too, not just the count. + assert.Equal(t, d.Reason, dropped[i].Reason, "drop reason differs for %v", c.In) + } + } +} diff --git a/internal/core/vocabulary/vocabulary_test.go b/internal/core/vocabulary/vocabulary_test.go new file mode 100644 index 00000000..28344625 --- /dev/null +++ b/internal/core/vocabulary/vocabulary_test.go @@ -0,0 +1,158 @@ +package vocabulary + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func ptr(f float64) *float64 { return &f } + +// A trimmed stand-in for /schema/device-type-vehicle.json, carrying one +// attribute of each type plus the four the mapping tables actually act on. +func testVocab() *DeviceType { + return &DeviceType{ + ID: "vehicle", + Attributes: []Attribute{ + {Name: "powertrain_type", Type: "enum", Options: []string{"ICE", "HEV", "PHEV", "BEV", "FCEV"}}, + {Name: "fuel_type", Type: "enum", Options: []string{"gasoline", "diesel", "electric", "flex_fuel", "hydrogen", "cng", "lpg"}}, + {Name: "driven_wheels", Type: "enum", Options: []string{"FWD", "RWD", "AWD", "4WD"}}, + {Name: "vehicle_type", Type: "enum", Options: []string{"sedan", "hatchback", "wagon", "coupe", "convertible", "suv", "minivan", "van", "pickup", "truck", "motorcycle", "chassis_cab"}}, + {Name: "emissions_standard", Type: "enum", Options: []string{"euro_4", "euro_5", "euro_6", "euro_6d"}}, + {Name: "number_of_doors", Type: "integer", Minimum: ptr(1), Maximum: ptr(8)}, + {Name: "fuel_tank_capacity_gal", Type: "number", Minimum: ptr(0), Maximum: ptr(100)}, + {Name: "wheelbase_in", Type: "number", Minimum: ptr(0), Maximum: ptr(500)}, + {Name: "manufacturer_code", Type: "string"}, + }, + } +} + +func TestMapAttributesTypesValues(t *testing.T) { + // The contract requires typed values: fuel_tank_capacity_gal is 15.8, not + // "15.800000". 6% of the old catalog's rows were "" or "". + mapped, dropped := MapAttributes(map[string]string{ + "fuel_tank_capacity_gal": "15.800000", + "number_of_doors": "4", + "manufacturer_code": "2532", + }, testVocab()) + + assert.Empty(t, dropped) + assert.Equal(t, 15.8, mapped["fuel_tank_capacity_gal"]) + assert.Equal(t, 4, mapped["number_of_doors"]) + assert.Equal(t, "2532", mapped["manufacturer_code"]) +} + +func TestMapAttributesOmitsDeadPlaceholders(t *testing.T) { + mapped, dropped := MapAttributes(map[string]string{ + "fuel_type": "", + "driven_wheels": "", + "number_of_doors": "N/A", + "vehicle_type": "null", + }, testVocab()) + + // Absent, never empty: these are unrepresentable in the contract, and they + // are not drops either -- there was nothing there to carry. + assert.Empty(t, mapped) + assert.Empty(t, dropped) +} + +func TestMapAttributesFoldsSpellings(t *testing.T) { + mapped, dropped := MapAttributes(map[string]string{ + "fuel_type": "Petrol", + "driven_wheels": "All-Wheel Drive", + "vehicle_type": "Crossover Utility Vehicle (CUV)", + "epa_class": "Euro 6d-temp", + }, testVocab()) + + require.Empty(t, dropped) + assert.Equal(t, "gasoline", mapped["fuel_type"]) + assert.Equal(t, "AWD", mapped["driven_wheels"]) + assert.Equal(t, "suv", mapped["vehicle_type"]) + // epa_class is renamed: the unit and the axis belong to the vocabulary. + assert.Equal(t, "euro_6d", mapped["emissions_standard"]) + assert.NotContains(t, mapped, "epa_class") +} + +// "Hybrid" arrives as a raw fuel_type. Powertrain derivation has already made +// it HEV; a hybrid burns gasoline, so folding the leftover string onto its +// actual fuel is what stops the record claiming a fuel the vocabulary lacks. +// This conflation is what produced the blended Camry. +func TestMapAttributesFoldsHybridFuelOntoGasoline(t *testing.T) { + mapped, dropped := MapAttributes(map[string]string{"fuel_type": "Hybrid"}, testVocab()) + assert.Empty(t, dropped) + assert.Equal(t, "gasoline", mapped["fuel_type"]) +} + +// A drop must say which decision it was. Routing these through the generic +// reason would make a deliberate choice look like a typo to everyone reading +// the report rather than the source. +func TestMapAttributesReportsDeliberateDropsDistinctly(t *testing.T) { + _, dropped := MapAttributes(map[string]string{ + "driven_wheels": "4x2", + "epa_class": "6L", + }, testVocab()) + + require.Len(t, dropped, 2) + byName := map[string]DroppedAttribute{} + for _, d := range dropped { + byName[d.Name] = d + } + assert.Contains(t, byName["driven_wheels"].Reason, "driven wheel count") + assert.Contains(t, byName["epa_class"].Reason, "coding scheme") + // Distinct from the generic reason, which is the whole point. + assert.NotContains(t, byName["driven_wheels"].Reason, "no mapping") + assert.NotContains(t, byName["epa_class"].Reason, "no mapping") +} + +func TestMapAttributesReportsWhatItDidNotCarry(t *testing.T) { + mapped, dropped := MapAttributes(map[string]string{ + "generation": "6", + "epa_class": "Calss III", + "number_of_doors": "4.5", + "fuel_tank_capacity_gal": "unknown", + }, testVocab()) + + assert.Empty(t, mapped) + require.Len(t, dropped, 4) + reasons := map[string]string{} + for _, d := range dropped { + reasons[d.Name] = d.Reason + } + assert.Equal(t, "no such attribute in the vocabulary", reasons["generation"]) + assert.Equal(t, "value not in the vocabulary and no mapping", reasons["epa_class"]) + assert.Equal(t, "not an integer", reasons["number_of_doors"]) + assert.Equal(t, "not a number", reasons["fuel_tank_capacity_gal"]) +} + +func TestMapAttributesEnforcesVocabularyRange(t *testing.T) { + _, dropped := MapAttributes(map[string]string{"number_of_doors": "12"}, testVocab()) + require.Len(t, dropped, 1) + assert.Equal(t, "above the vocabulary range", dropped[0].Reason) +} + +func TestMapAttributesParsesWheelbase(t *testing.T) { + mapped, dropped := MapAttributes(map[string]string{"wheelbase": "111.2 in"}, testVocab()) + assert.Empty(t, dropped) + assert.Equal(t, 111.2, mapped["wheelbase_in"]) +} + +// The drop report is read by a human deciding what to fix. Map iteration order +// would otherwise reshuffle it on every call and make two runs look different. +func TestMapAttributesDropReportIsStable(t *testing.T) { + in := map[string]string{"zulu": "1", "alpha": "2", "mike": "3", "bravo": "4"} + first, _ := MapAttributes(in, testVocab()) + assert.Empty(t, first) + _, dropped := MapAttributes(in, testVocab()) + names := make([]string, len(dropped)) + for i, d := range dropped { + names[i] = d.Name + } + assert.Equal(t, []string{"alpha", "bravo", "mike", "zulu"}, names) +} + +func TestMapAttributesWithoutVocabularyCarriesNothing(t *testing.T) { + mapped, dropped := MapAttributes(map[string]string{"fuel_type": "Petrol"}, nil) + assert.Empty(t, mapped) + assert.Empty(t, dropped) +} diff --git a/internal/infrastructure/db/repositories/vin_repo.go b/internal/infrastructure/db/repositories/vin_repo.go index 8d7ec6dd..974cac7b 100644 --- a/internal/infrastructure/db/repositories/vin_repo.go +++ b/internal/infrastructure/db/repositories/vin_repo.go @@ -9,9 +9,6 @@ import ( "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways" - "github.com/DIMO-Network/device-definitions-api/internal/contracts" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - stringutils "github.com/DIMO-Network/shared/pkg/strings" "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/db/models" @@ -26,13 +23,12 @@ type VINRepository interface { } type vinRepository struct { - DBS func() *db.ReaderWriter - registryInstance *contracts.Registry - identity gateways.IdentityAPI + DBS func() *db.ReaderWriter + identity gateways.IdentityAPI } -func NewVINRepository(dbs func() *db.ReaderWriter, registryInstance *contracts.Registry, identity gateways.IdentityAPI) VINRepository { - return &vinRepository{DBS: dbs, registryInstance: registryInstance, identity: identity} +func NewVINRepository(dbs func() *db.ReaderWriter, identity gateways.IdentityAPI) VINRepository { + return &vinRepository{DBS: dbs, identity: identity} } func (r *vinRepository) GetOrCreateWMI(ctx context.Context, wmi string, mk string) (*models.Wmi, error) { @@ -53,9 +49,8 @@ func (r *vinRepository) GetOrCreateWMI(ctx context.Context, wmi string, mk strin } return nil, err } - manufacturerID, err := r.registryInstance.GetManufacturerIdByName(&bind.CallOpts{Context: ctx, Pending: true}, deviceMake.Name) - if err != nil || manufacturerID == nil { - return nil, &exceptions.ValidationError{Err: fmt.Errorf("make has not been minted yet or no tokenID set: %s :%s", mk, err)} + if deviceMake.TokenID <= 0 { + return nil, &exceptions.ValidationError{Err: fmt.Errorf("make has not been minted yet or no tokenID set: %s", mk)} } //dbWMI, err := models.FindWmi(ctx, r.dbs().Reader, wmi, deviceMake.ID) // there can be WMI's for more than one Make diff --git a/internal/infrastructure/dbtest/test_helper.go b/internal/infrastructure/dbtest/test_helper.go index 827ebec3..e4ddf4a2 100644 --- a/internal/infrastructure/dbtest/test_helper.go +++ b/internal/infrastructure/dbtest/test_helper.go @@ -142,8 +142,15 @@ func TruncateTables(db *sql.DB, t *testing.T) { func SetupCreateDeviceDefinition(t *testing.T, manufacturerName, model string, year int, pdb db.Store) *coremodels.DeviceDefinitionTablelandModel { SetupCreateDeviceType(t, pdb) + // A fixture built on an id no template can exist at would make the test + // assert against a definition the catalog could never hold, so fail the + // test here rather than let it pass or fail for the wrong reason. + id, err := common.DeviceDefinitionSlug(stringutils.SlugString(manufacturerName), stringutils.SlugString(model), int16(year)) + if err != nil { + t.Fatalf("test fixture asks for a definition id definitions-worker can never hold: %v", err) + } dd := &coremodels.DeviceDefinitionTablelandModel{ - ID: common.DeviceDefinitionSlug(stringutils.SlugString(manufacturerName), stringutils.SlugString(model), int16(year)), + ID: id, KSUID: ksuid.New().String(), Model: model, Year: year, diff --git a/internal/infrastructure/gateways/device_definition_catalog_e2e_test.go b/internal/infrastructure/gateways/device_definition_catalog_e2e_test.go new file mode 100644 index 00000000..7b44a9b3 --- /dev/null +++ b/internal/infrastructure/gateways/device_definition_catalog_e2e_test.go @@ -0,0 +1,47 @@ +package gateways + +import ( + "context" + "math/big" + "os" + "testing" + + "github.com/DIMO-Network/device-definitions-api/internal/config" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// Runs only against a live catalog (local wrangler dev or deployed worker): +// +// CATALOG_E2E_URL=http://localhost:8787 go test ./internal/infrastructure/gateways/ -run TestCatalogServiceE2E +func TestCatalogServiceE2E(t *testing.T) { + url := os.Getenv("CATALOG_E2E_URL") + if url == "" { + t.Skip("CATALOG_E2E_URL not set") + } + logger := zerolog.Nop() + svc := NewDeviceDefinitionCatalogService(&config.Settings{DefinitionsCatalogURL: url}, &logger) + ctx := context.Background() + + dd, manufID, err := svc.GetTemplateByID(ctx, "dodge_town-&-country_2012") + require.NoError(t, err) + require.NotNil(t, dd) + assert.Equal(t, "Town & Country", dd.Model) + assert.Equal(t, int64(33), manufID.Int64()) + require.NotEmpty(t, dd.Trims) + + // Manufacturer scoping: right owner resolves, wrong owner returns nil. + scoped, err := svc.GetDeviceDefinitionByID(ctx, big.NewInt(33), "dodge_town-&-country_2012") + require.NoError(t, err) + require.NotNil(t, scoped) + wrong, err := svc.GetDeviceDefinitionByID(ctx, big.NewInt(13), "dodge_town-&-country_2012") + require.NoError(t, err) + assert.Nil(t, wrong) + + // No fallback to the pre-migration definitions/.json: a missing + // template must fail loudly, not resolve as a quiet nil. + missing, _, err := svc.GetTemplateByID(ctx, "not_areal_2020") + require.Error(t, err) + assert.Nil(t, missing) +} diff --git a/internal/infrastructure/gateways/device_definition_catalog_service.go b/internal/infrastructure/gateways/device_definition_catalog_service.go new file mode 100644 index 00000000..5242f699 --- /dev/null +++ b/internal/infrastructure/gateways/device_definition_catalog_service.go @@ -0,0 +1,612 @@ +//nolint:tagliatelle +package gateways + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "math/big" + "net/http" + "net/url" + "strconv" + "strings" + "sync/atomic" + "time" + + "github.com/DIMO-Network/device-definitions-api/internal/config" + "github.com/DIMO-Network/device-definitions-api/internal/core/common" + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" + "github.com/DIMO-Network/device-definitions-api/internal/core/vocabulary" + "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/metrics" + "github.com/patrickmn/go-cache" + "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" + "github.com/rs/zerolog" +) + +// Metric method labels for the shared request counters; dashboards filter on +// these the way they previously filtered on the Tableland* labels. +const ( + metricCatalogRead = "CatalogRead" + metricManifestRead = "CatalogManifestRead" + metricCatalogWrite = "CatalogWrite" +) + +// ErrTemplateNotFound is returned by GetTemplateByID/GetTemplateByIDFresh +// only for a genuine 404 from t/.json -- the template import has not run +// for this id. Callers must check it with errors.Is, never by inspecting the +// error's message: any other status, a transport error, or a decode failure +// returns a distinct, non-sentinel error, so a catalog outage is never +// mistaken for "this vehicle does not exist." Conflating the two would let a +// caller respond to a 500 by creating a duplicate definition mid-outage. +var ErrTemplateNotFound = errors.New("template not found in catalog") + +// ErrManufacturerUnresolved is returned by Create when identity-api cannot +// resolve the definition's manufacturer to a minted token id, whether because +// the make is not minted or because identity failed to answer. Nothing is +// written. A template created without a tokenId cannot be used by +// UpsertDecoding or addvin, and the on-chain create this replaced refused the +// same case. +var ErrManufacturerUnresolved = errors.New("manufacturer not resolved in identity") + +// ErrTemplateExists is returned by Create when a template is already stored at +// the id: the worker answered 412 to its If-None-Match: * write, and nothing +// was written. A caller that only needs the template to exist -- the decode +// path -- treats it as success by another writer and reads the stored template +// back; it must not retry the write unconditionally. +var ErrTemplateExists = errors.New("template already exists in catalog") + +func countOutcome(method string, err error) { + if err != nil { + metrics.InternalError.With(prometheus.Labels{"method": method}).Inc() + return + } + metrics.Success.With(prometheus.Labels{"method": method}).Inc() +} + +//go:generate mockgen -source device_definition_catalog_service.go -destination mocks/device_definition_catalog_service_mock.go -package mocks + +// DeviceDefinitionCatalogService reads device definitions from the R2-backed +// catalog (CDN) and writes them through the definitions-worker. It replaces +// the Tableland on-chain service. +type DeviceDefinitionCatalogService interface { + GetManufacturer(manufacturerSlug string) (*coremodels.Manufacturer, error) + GetManufacturerNameByID(ctx context.Context, manufacturerID *big.Int) (string, error) + // GetDeviceDefinitionByID gets a definition by slug ID, requiring it to belong to the given manufacturer. + GetDeviceDefinitionByID(ctx context.Context, manufacturerID *big.Int, ID string) (*coremodels.DeviceDefinitionTablelandModel, error) + // GetTemplateByID reads the vehicle template for a slug ID from t/.json + // and returns the manufacturer token id too. The token id is nil when the + // template carries none: tokenId is optional in the contract, and a caller + // must treat nil as unknown, never as manufacturer 0. It does not fall + // back to the pre-migration definitions/.json: a 404 here means the template + // import has not run for this id, and that must fail loudly rather than + // silently serving the flat pre-migration record. + GetTemplateByID(ctx context.Context, ID string) (*coremodels.Template, *big.Int, error) + // GetTemplateByIDFresh is GetTemplateByID with a request the edge cache + // cannot answer. A caller that reads, mutates and writes back must use it: + // documents are served with max-age=86400, so a cached read silently + // discards any edit made in the last day when the result is PUT back. + // + // The worker and the catalog are one hostname, so this is not a different + // host -- it is a different cache key, a unique query parameter the worker + // ignores. See fetchTemplateDocFresh. + // + // The decode path uses it after Create returns ErrTemplateExists, to read + // back the template another writer just stored: the edge may still be + // serving the 404 the decode saw moments earlier. + GetTemplateByIDFresh(ctx context.Context, ID string) (*coremodels.Template, *big.Int, error) + // GetDefinition is GetDeviceDefinitionByID under its historical secondary name. + GetDefinition(ctx context.Context, manufacturerID *big.Int, ID string) (*coremodels.DeviceDefinitionTablelandModel, error) + // Create writes a template that does not exist yet and returns the + // document the worker stored -- the PUT's own response, so no read-back + // is needed. A caller must narrow that document to a trim exactly as it + // would a template it had found, or a definition's first decode answers + // differently from its second. + Create(ctx context.Context, manufacturerName string, dd coremodels.DeviceDefinitionTablelandModel) (*coremodels.Template, error) + Delete(ctx context.Context, manufacturerName, id string) (*string, error) +} + +const ( + // CatalogPageSize is the page size QueryDefinitionsByManufacturer returns. + // Exported because callers page until a short page and must agree with it; + // a private copy elsewhere silently truncates their iteration if it drifts. + CatalogPageSize = 500 + manifestCacheKey = "definitions_manifest" + manifestCacheTTL = time.Minute + manufacturersCached = "manufacturers_by_token_id" +) + +type deviceDefinitionCatalogService struct { + settings *config.Settings + logger *zerolog.Logger + identityAPI IdentityAPI + httpClient *http.Client + memCache *cache.Cache +} + +func NewDeviceDefinitionCatalogService(settings *config.Settings, logger *zerolog.Logger) DeviceDefinitionCatalogService { + return &deviceDefinitionCatalogService{ + settings: settings, + logger: logger, + identityAPI: NewIdentityAPIService(logger, settings), + httpClient: &http.Client{Timeout: 30 * time.Second}, + memCache: cache.New(5*time.Minute, 10*time.Minute), + } +} + +func (e *deviceDefinitionCatalogService) catalogURL(pathSuffix string) string { + return strings.TrimSuffix(e.settings.DefinitionsCatalogURL, "/") + pathSuffix +} + +func (e *deviceDefinitionCatalogService) fetchTemplateDoc(ctx context.Context, id string) (*coremodels.Template, error) { + tmpl, err := e.fetchTemplateDocFrom(ctx, e.catalogURL("/t/"+url.PathEscape(id)+".json"), id) + countOutcome(metricCatalogRead, err) + return tmpl, err +} + +// freshParam is the query parameter that makes a fresh read miss the edge +// cache. definitions-worker routes on url.pathname alone (src/index.ts's +// templateMatch), so it never reads this and the request reaches exactly the +// same handler the cached read reaches; Cloudflare's cache key is the whole +// URL, so a value it has not seen cannot be served from cache. +const freshParam = "fresh" + +// freshSeq disambiguates two fresh reads minted inside one clock tick. The +// value only has to be unique, never unguessable. +var freshSeq atomic.Uint64 + +func freshValue() string { + return strconv.FormatInt(time.Now().UnixNano(), 36) + "-" + strconv.FormatUint(freshSeq.Add(1), 36) +} + +// fetchTemplateDocFresh reads a template past the edge cache, so +// read-modify-write never merges a stale cached base and a read-back after a +// create-only conflict is never served the 404 the create just saw. +// +// It does NOT read "through the worker instead of the CDN": there is no second +// host to read through. DEFINITIONS_CATALOG_URL and DEFINITIONS_WORKER_URL are +// the same hostname in both dev and prod (charts/device-definitions-api), +// because the worker IS what serves definitions.dimo.org -- so the fresh read +// built a byte-identical request to the cached one and got the cached answer. +// Keeping one hostname and missing the cache by cache key is the decision: +// a unique query parameter the worker ignores and the edge cannot match. +// +// A request header cannot do this job: Cloudflare does not honour a client's +// Cache-Control on a cached response, and the document is served +// `public, max-age=86400, stale-while-revalidate=604800`. +func (e *deviceDefinitionCatalogService) fetchTemplateDocFresh(ctx context.Context, id string) (*coremodels.Template, error) { + base := e.settings.DefinitionsWorkerURL + if base == "" { + base = e.settings.DefinitionsCatalogURL + } + reqURL := strings.TrimSuffix(base, "/") + "/t/" + url.PathEscape(id) + ".json?" + freshParam + "=" + freshValue() + tmpl, err := e.fetchTemplateDocFrom(ctx, reqURL, id) + countOutcome(metricCatalogRead, err) + return tmpl, err +} + +func (e *deviceDefinitionCatalogService) fetchTemplateDocFrom(ctx context.Context, reqURL, id string) (*coremodels.Template, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, nil) + if err != nil { + return nil, err + } + resp, err := e.httpClient.Do(req) + if err != nil { + return nil, errors.Wrapf(err, "failed to fetch template %s from catalog", id) + } + defer resp.Body.Close() //nolint:errcheck + if resp.StatusCode == http.StatusNotFound { + // Unlike fetchDocFrom, a 404 is an error here, not a nil result: it + // means the template import for this id has not run, and that must + // fail loudly rather than be treated as a normal "not found". It is + // ErrTemplateNotFound specifically -- and only this -- so a caller + // can tell "does not exist" apart from every other failure below. + return nil, errors.Wrapf(ErrTemplateNotFound, "template %s", id) + } + if resp.StatusCode != http.StatusOK { + // Any other status is a catalog problem, not a missing template: + // callers must not reclassify this as not-found. + return nil, fmt.Errorf("catalog returned %d for template %s", resp.StatusCode, id) + } + var tmpl coremodels.Template + if err := json.NewDecoder(resp.Body).Decode(&tmpl); err != nil { + return nil, errors.Wrapf(err, "failed to decode template %s", id) + } + return &tmpl, nil +} + +func (e *deviceDefinitionCatalogService) GetManufacturer(manufacturerSlug string) (*coremodels.Manufacturer, error) { + return e.identityAPI.GetManufacturer(manufacturerSlug) +} + +func (e *deviceDefinitionCatalogService) GetManufacturerNameByID(_ context.Context, manufacturerID *big.Int) (string, error) { + // A template's tokenId is optional, so a caller can hold none. No + // manufacturer has a token id below 1: asking identity would only fail + // after a round trip, and a nil id would panic below. + if manufacturerID == nil || manufacturerID.Sign() <= 0 { + return "", fmt.Errorf("no manufacturer token id to look up: %v", manufacturerID) + } + byID := map[int]string{} + if v, ok := e.memCache.Get(manufacturersCached); ok { + byID = v.(map[int]string) + } else { + all, err := e.identityAPI.GetManufacturers() + if err != nil { + return "", errors.Wrap(err, "failed to get manufacturers from identity") + } + // identity answers 200 with an `errors` array and null data when it + // fails, which the client surfaces as (nil, nil). Caching that empty + // map for ten minutes turns a brief blip into ten minutes of every + // lookup failing, and callers that treat the failure as "skip this row" + // drop work silently. + if len(all) == 0 { + return "", fmt.Errorf("identity returned no manufacturers") + } + for _, m := range all { + byID[m.TokenID] = m.Name + } + e.memCache.Set(manufacturersCached, byID, 10*time.Minute) + } + name, ok := byID[int(manufacturerID.Int64())] + if !ok { + return "", fmt.Errorf("no manufacturer found for token id %d", manufacturerID.Int64()) + } + return name, nil +} + +// GetDeviceDefinitionByID returns the flat pre-migration shape for the callers +// that still take it, built from the template's SHARED attributes only. +// +// Attributes that vary by trim are deliberately absent. This shape has exactly +// one slot per attribute, and filling it from an arbitrary trim is precisely +// what produced the record that claimed powertrain ICE while carrying a +// hybrid's tank size. Absent is honest; a guess is not. +// +// (nil, nil) still means "not found", as it did before, and also covers a +// template owned by a different manufacturer. Unlike GetTemplateByID this does +// not turn a missing template into an error: its callers branch on nil and +// report it, and none of them create anything on the strength of it. +func (e *deviceDefinitionCatalogService) GetDeviceDefinitionByID(ctx context.Context, manufacturerID *big.Int, ID string) (*coremodels.DeviceDefinitionTablelandModel, error) { + tmpl, tokenID, err := e.GetTemplateByID(ctx, ID) + if err != nil { + if errors.Is(err, ErrTemplateNotFound) { + return nil, nil + } + return nil, err + } + // Ownership is compared only when both sides are known. A template with no + // tokenId belongs to no token, so it cannot belong to another manufacturer's. + if manufacturerID != nil && tokenID != nil && tokenID.Int64() != manufacturerID.Int64() { + return nil, nil + } + return templateToDefinitionModel(tmpl), nil +} + +// templateToDefinitionModel flattens a template into the legacy shape. KSUID is +// not populated: it is gone from the contract, and inventing one here would put +// a value into a field consumers read as an identifier. +func templateToDefinitionModel(tmpl *coremodels.Template) *coremodels.DeviceDefinitionTablelandModel { + names := common.SortedAttributeNames(tmpl.Attributes) + attrs := make([]coremodels.DeviceTypeAttribute, 0, len(names)) + for _, name := range names { + attrs = append(attrs, coremodels.DeviceTypeAttribute{Name: name, Value: common.AttributeString(tmpl.Attributes[name])}) + } + return &coremodels.DeviceDefinitionTablelandModel{ + ID: tmpl.ID, + Model: tmpl.Model, + Year: tmpl.Year, + DeviceType: tmpl.DeviceType, + ImageURI: tmpl.ImageURI, + Metadata: &coremodels.DeviceDefinitionMetadata{DeviceAttributes: attrs}, + } +} + +func (e *deviceDefinitionCatalogService) GetDefinition(ctx context.Context, manufacturerID *big.Int, ID string) (*coremodels.DeviceDefinitionTablelandModel, error) { + return e.GetDeviceDefinitionByID(ctx, manufacturerID, ID) +} + +func (e *deviceDefinitionCatalogService) GetTemplateByID(ctx context.Context, ID string) (*coremodels.Template, *big.Int, error) { + tmpl, err := e.fetchTemplateDoc(ctx, ID) + if err != nil { + return nil, nil, err + } + return tmpl, manufacturerTokenID(tmpl), nil +} + +func (e *deviceDefinitionCatalogService) GetTemplateByIDFresh(ctx context.Context, ID string) (*coremodels.Template, *big.Int, error) { + tmpl, err := e.fetchTemplateDocFresh(ctx, ID) + if err != nil { + return nil, nil, err + } + return tmpl, manufacturerTokenID(tmpl), nil +} + +// manufacturerTokenID is the template's manufacturer token id, or nil when the +// template carries none. tokenId is optional in the contract and at least 1 +// when present, so the zero value can only mean absent. Reporting it as token +// id 0 sent callers to look up, and compare against, a manufacturer that does +// not exist. +func manufacturerTokenID(tmpl *coremodels.Template) *big.Int { + if tmpl.Manufacturer.TokenID <= 0 { + return nil + } + return big.NewInt(int64(tmpl.Manufacturer.TokenID)) +} + +// workerRequest sends an authenticated request to the definitions-worker. +// An unconfigured worker URL is an error, not a mode: silently skipping the +// write and reporting success meant a decode could answer 200 with a definition +// id that was never written to R2, and a delete could log success for a +// definition that still exists. +// +// It returns the worker's status code alongside any error, so a caller can act +// on a refusal it understands without reading the message; 0 means no response +// was received. +func (e *deviceDefinitionCatalogService) workerRequest(ctx context.Context, method, pathSuffix string, body any) (int, error) { + status, _, err := e.workerRequestWithHeader(ctx, method, pathSuffix, body, nil) + return status, err +} + +// maxWorkerResponseBytes bounds the response body read back from a write. The +// worker refuses a request body over 64KB (MAX_DOC_BYTES) and answers a write +// with the document it stored, so this is generous by an order of magnitude +// and exists only so a misbehaving upstream cannot be read without limit. +const maxWorkerResponseBytes = 1 << 20 + +// workerRequestWithHeader is workerRequest with extra request headers, such as +// a write precondition, and it returns the response body. +// +// The worker answers a write with the document it stored -- version, author +// and timestamps stamped. A caller that needs that document must not have to +// fetch it again: the read-back is a second round trip against a CDN that may +// still be serving what the write just replaced. +func (e *deviceDefinitionCatalogService) workerRequestWithHeader(ctx context.Context, method, pathSuffix string, body any, header http.Header) (int, []byte, error) { + if e.settings.DefinitionsWorkerURL == "" { + metrics.InternalError.With(prometheus.Labels{"method": metricCatalogWrite}).Inc() + return 0, nil, fmt.Errorf("definitions-worker is not configured (DEFINITIONS_WORKER_URL is empty); refusing to report %s %s as written", method, pathSuffix) + } + var reader io.Reader + if body != nil { + b, err := json.Marshal(body) + if err != nil { + return 0, nil, err + } + reader = bytes.NewReader(b) + } + reqURL := strings.TrimSuffix(e.settings.DefinitionsWorkerURL, "/") + pathSuffix + req, err := http.NewRequestWithContext(ctx, method, reqURL, reader) + if err != nil { + return 0, nil, err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+e.settings.DefinitionsWorkerToken) + for name, values := range header { + for _, v := range values { + req.Header.Add(name, v) + } + } + resp, err := e.httpClient.Do(req) + if err != nil { + metrics.InternalError.With(prometheus.Labels{"method": metricCatalogWrite}).Inc() + return 0, nil, errors.Wrapf(err, "definitions-worker %s %s failed", method, pathSuffix) + } + defer resp.Body.Close() //nolint:errcheck + if resp.StatusCode >= 300 { + metrics.InternalError.With(prometheus.Labels{"method": metricCatalogWrite}).Inc() + msg, _ := io.ReadAll(io.LimitReader(resp.Body, 2048)) + return resp.StatusCode, nil, fmt.Errorf("definitions-worker %s %s returned %d: %s", method, pathSuffix, resp.StatusCode, string(msg)) + } + respBody, err := io.ReadAll(io.LimitReader(resp.Body, maxWorkerResponseBytes)) + if err != nil { + // The write landed; only the answer was lost. Report the status and + // the read failure and let the caller decide -- treating this as a + // failed write would have the decode path create a duplicate. + metrics.InternalError.With(prometheus.Labels{"method": metricCatalogWrite}).Inc() + return resp.StatusCode, nil, errors.Wrapf(err, "definitions-worker %s %s response could not be read", method, pathSuffix) + } + metrics.Success.With(prometheus.Labels{"method": metricCatalogWrite}).Inc() + return resp.StatusCode, respBody, nil +} + +// templatePutBody is Template minus the fields definitions-worker owns. +// Marshalling coremodels.Template directly would send "version": 0, and the +// worker rejects a client-supplied version, createdAt, updatedAt or author by +// name rather than stripping it -- a writer that thinks it set them and was +// quietly overruled has learned nothing. +type templatePutBody struct { + ID string `json:"id"` + DeviceType string `json:"deviceType"` + Manufacturer coremodels.TemplateManufacturer `json:"manufacturer"` + Model string `json:"model"` + Year int `json:"year"` + ImageURI string `json:"imageURI,omitempty"` + HardwareTemplateID string `json:"hardwareTemplateId,omitempty"` + Attributes map[string]any `json:"attributes"` + Trims []templatePutTrim `json:"trims"` +} + +// templatePutTrim omits Selectors when empty. coremodels.Trim marshals them +// unconditionally, and a single-trim template has nothing to select on. +type templatePutTrim struct { + Name string `json:"name"` + Selectors *coremodels.TrimSelectors `json:"selectors,omitempty"` + HardwareTemplateID string `json:"hardwareTemplateId,omitempty"` + Attributes map[string]any `json:"attributes"` +} + +// defaultTrimName matches the extraction pipeline's fallback +// (definitions-worker/scripts/extract/trims.mjs): a model-year sold in one +// configuration still has a trim, because the schema has no other shape for it. +const defaultTrimName = "Base" + +const ( + vocabularyCacheKey = "device_type_vocabulary" + // The worker serves /schema with max-age=300, so holding it longer than + // that would show a contributor a vocabulary the validator has stopped + // using. + vocabularyCacheTTL = 5 * time.Minute +) + +// vocabulary fetches the DeviceType the template's attributes are validated +// against. It is read from the worker rather than vendored: a stale local copy +// would fold values the validator rejects, and the mismatch would only appear +// as a failed write. +func (e *deviceDefinitionCatalogService) vocabulary(ctx context.Context, deviceType string) (*vocabulary.DeviceType, error) { + key := vocabularyCacheKey + ":" + deviceType + if v, ok := e.memCache.Get(key); ok { + return v.(*vocabulary.DeviceType), nil + } + base := e.settings.DefinitionsWorkerURL + if base == "" { + base = e.settings.DefinitionsCatalogURL + } + reqURL := strings.TrimSuffix(base, "/") + "/schema/device-type-" + url.PathEscape(deviceType) + ".json" + req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, nil) + if err != nil { + return nil, err + } + resp, err := e.httpClient.Do(req) + if err != nil { + return nil, errors.Wrapf(err, "failed to fetch the %s vocabulary", deviceType) + } + defer resp.Body.Close() //nolint:errcheck + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("catalog returned %d for the %s vocabulary", resp.StatusCode, deviceType) + } + var vocab vocabulary.DeviceType + if err := json.NewDecoder(resp.Body).Decode(&vocab); err != nil { + return nil, errors.Wrapf(err, "failed to decode the %s vocabulary", deviceType) + } + e.memCache.Set(key, &vocab, vocabularyCacheTTL) + return &vocab, nil +} + +// templateFromDefinition builds the template for a definition that does not +// exist yet, folding dd.Metadata onto the DeviceType vocabulary. +// +// The manufacturer is resolved through identity first, and a make identity +// cannot resolve to a token id fails with ErrManufacturerUnresolved before +// anything else is fetched or written. +// +// A vocabulary that cannot be fetched is an error, not a reason to write fewer +// attributes: silently storing less because a fetch failed is indistinguishable +// afterwards from the source not having carried the value. +// +// Attributes go on the template rather than the trim. There is exactly one +// trim, so every attribute is shared by all of them, and the contract requires +// an attribute to be in one place or the other and never both. +func (e *deviceDefinitionCatalogService) templateFromDefinition(ctx context.Context, manufacturerName string, dd coremodels.DeviceDefinitionTablelandModel) (templatePutBody, []vocabulary.DroppedAttribute, error) { + slug := dd.ID + if i := strings.Index(dd.ID, "_"); i > 0 { + slug = dd.ID[:i] + } + // Not best effort. tokenId is optional in the contract, but a template + // written without one is unusable by UpsertDecoding and addvin, and best + // effort turned a single identity blip into a permanently tokenless + // template. The on-chain create this replaced refused the same case. + m, err := e.GetManufacturer(slug) + if err != nil { + return templatePutBody{}, nil, fmt.Errorf("%w: %s: %w", ErrManufacturerUnresolved, slug, err) + } + if m == nil || m.TokenID <= 0 { + return templatePutBody{}, nil, fmt.Errorf("%w: %s has no manufacturer token id", ErrManufacturerUnresolved, slug) + } + manufacturer := coremodels.TemplateManufacturer{Slug: slug, Name: manufacturerName, TokenID: m.TokenID} + if manufacturer.Name == "" { + manufacturer.Name = m.Name + } + deviceType := dd.DeviceType + if deviceType == "" { + deviceType = common.DefaultDeviceType + } + + vocab, err := e.vocabulary(ctx, deviceType) + if err != nil { + return templatePutBody{}, nil, err + } + raw := map[string]string{} + if dd.Metadata != nil { + for _, a := range dd.Metadata.DeviceAttributes { + raw[a.Name] = a.Value + } + } + attributes, dropped := vocabulary.MapAttributes(raw, vocab) + + return templatePutBody{ + ID: dd.ID, + DeviceType: deviceType, + Manufacturer: manufacturer, + Model: dd.Model, + Year: dd.Year, + ImageURI: dd.ImageURI, + Attributes: attributes, + Trims: []templatePutTrim{{Name: defaultTrimName, Attributes: map[string]any{}}}, + }, dropped, nil +} + +// Create writes the template for a definition that does not exist yet, and +// never overwrites one. The worker's PUT is an upsert unless told otherwise, so +// the write carries If-None-Match: * and the existence check happens at the +// worker, atomically with the write. Reading first and then writing +// unconditionally left a window in which a curator's save was replaced by a +// single Base trim while the create reported success. +// +// A template already stored at the id returns an error wrapping +// ErrTemplateExists, with nothing written. Every other refusal -- a 422 for an +// invalid template, an outage -- is a plain error. +// +// On success it returns the document the worker stored, which the worker +// answers the PUT with: version stamped, and the Base trim the decode has to +// narrow to. Discarding it left the decode that created a definition with no +// template to match against, so it answered an empty trim and version zero +// while the next decode of the same VIN answered Base and version 1. +// +// A response that cannot be read back as this template is (nil, nil): the +// write did land, and reporting it as failed would have the caller create a +// duplicate, but there is nothing to hand back and a caller that needs the +// document must read it. It is never (nil, nil) in normal operation. +func (e *deviceDefinitionCatalogService) Create(ctx context.Context, manufacturerName string, dd coremodels.DeviceDefinitionTablelandModel) (*coremodels.Template, error) { + e.logger.Info().Msgf("catalog create for device definition %s (manufacturer %s)", dd.ID, manufacturerName) + body, dropped, err := e.templateFromDefinition(ctx, manufacturerName, dd) + if err != nil { + return nil, err + } + // Report what was read and not carried, not only what failed to parse. A + // value dropped without a trace is the defect class this migration keeps + // producing. + for _, d := range dropped { + e.logger.Info().Msgf("catalog create %s: dropped %s", dd.ID, d) + } + createOnly := http.Header{"If-None-Match": []string{"*"}} + status, respBody, err := e.workerRequestWithHeader(ctx, http.MethodPut, "/t/"+url.PathEscape(dd.ID), body, createOnly) + if status == http.StatusPreconditionFailed { + return nil, fmt.Errorf("%w: %s: %w", ErrTemplateExists, dd.ID, err) + } + if err != nil { + return nil, err + } + e.memCache.Delete(manifestCacheKey) + var stored coremodels.Template + if err := json.Unmarshal(respBody, &stored); err != nil { + e.logger.Warn().Err(err).Msgf("catalog create %s stored the template but its response could not be read as one", dd.ID) + return nil, nil + } + if stored.ID != dd.ID { + // Not the document we asked for. Handing it back would have a caller + // narrow trims for a different definition than the one it decoded. + e.logger.Warn().Msgf("catalog create %s answered with template %q", dd.ID, stored.ID) + return nil, nil + } + return &stored, nil +} + +func (e *deviceDefinitionCatalogService) Delete(ctx context.Context, manufacturerName, id string) (*string, error) { + e.logger.Info().Msgf("catalog delete for device definition %s (manufacturer %s)", id, manufacturerName) + if _, err := e.workerRequest(ctx, http.MethodDelete, "/t/"+url.PathEscape(id), nil); err != nil { + return nil, err + } + e.memCache.Delete(manifestCacheKey) + return &id, nil +} diff --git a/internal/infrastructure/gateways/device_definition_catalog_service_test.go b/internal/infrastructure/gateways/device_definition_catalog_service_test.go new file mode 100644 index 00000000..757ea80e --- /dev/null +++ b/internal/infrastructure/gateways/device_definition_catalog_service_test.go @@ -0,0 +1,675 @@ +package gateways + +import ( + "context" + "encoding/json" + "math/big" + "net/http" + "net/http/httptest" + "net/url" + "strconv" + "strings" + "testing" + + "github.com/DIMO-Network/device-definitions-api/internal/config" + coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// An unconfigured worker URL used to make every write a no-op that still +// reported success: Create returned the id, Delete logged "Deleted", and the +// API answered 200 while nothing reached R2. A missing write endpoint is a +// misconfiguration, not a mode of operation. +func TestWritesFailWhenWorkerURLUnset(t *testing.T) { + logger := zerolog.Nop() + svc := NewDeviceDefinitionCatalogService(&config.Settings{DefinitionsCatalogURL: "http://127.0.0.1:1"}, &logger) + + id, err := svc.Delete(context.Background(), "Toyota", "toyota_camry_2020") + require.Error(t, err, "a delete with no worker configured must not report success") + assert.Nil(t, id) + assert.Contains(t, err.Error(), "not configured") +} + +// Verbatim trim of the Camry template the definitions-worker pipeline +// produces. +const templateJSON = `{ + "id": "toyota_camry_2020", + "deviceType": "vehicle", + "manufacturer": {"slug": "toyota", "name": "Toyota", "tokenId": 131}, + "model": "Camry", + "year": 2020, + "attributes": {"number_of_doors": 4, "vehicle_type": "sedan"}, + "trims": [ + {"name": "LE", "selectors": {"manufacturerCode": ["2532"]}, + "attributes": {"powertrain_type": "ICE", "fuel_type": "gasoline", "fuel_tank_capacity_gal": 16, "mpg_city": 28}}, + {"name": "Hybrid LE", "selectors": {"manufacturerCode": ["2559"]}, + "attributes": {"powertrain_type": "HEV", "fuel_type": "gasoline", "fuel_tank_capacity_gal": 13.2, "mpg_city": 51}} + ], + "version": 3, + "createdAt": "2026-08-27T00:00:00.000Z", + "updatedAt": "2026-08-28T00:00:00.000Z" +}` + +func TestTemplateUnmarshal(t *testing.T) { + var tmpl coremodels.Template + require.NoError(t, json.Unmarshal([]byte(templateJSON), &tmpl)) + + assert.Equal(t, "toyota_camry_2020", tmpl.ID) + assert.Equal(t, 2020, tmpl.Year) + assert.Equal(t, 3, tmpl.Version) + assert.Equal(t, "Toyota", tmpl.Manufacturer.Name) + assert.Equal(t, 131, tmpl.Manufacturer.TokenID) + + // Attributes are typed, not stringified. + assert.Equal(t, float64(4), tmpl.Attributes["number_of_doors"]) + + require.Len(t, tmpl.Trims, 2) + assert.Equal(t, "LE", tmpl.Trims[0].Name) + assert.Equal(t, []string{"2532"}, tmpl.Trims[0].Selectors.ManufacturerCode) + assert.Equal(t, "ICE", tmpl.Trims[0].Attributes["powertrain_type"]) + assert.Equal(t, 16.0, tmpl.Trims[0].Attributes["fuel_tank_capacity_gal"]) + assert.Equal(t, 13.2, tmpl.Trims[1].Attributes["fuel_tank_capacity_gal"]) +} + +func TestTemplateHasNoLegacyFields(t *testing.T) { + // ksuid and tableId were removed from the model deliberately. Asserting + // on the fixture JSON alone can never fail -- the fixture just doesn't + // carry those keys, and nothing here reads the type. Round-tripping a + // document that DOES carry them through coremodels.Template is what + // would catch a regression: if the struct ever grew a field capturing + // either key, it would come back out on re-marshal. + withLegacyFields := `{ + "id": "toyota_camry_2020", + "deviceType": "vehicle", + "manufacturer": {"slug": "toyota", "name": "Toyota", "tokenId": 131}, + "model": "Camry", + "year": 2020, + "ksuid": "26G3iFH7Xc9Wvsw7pg6sD7uzoSS", + "tableId": 42, + "attributes": {}, + "trims": [{"name": "LE", "attributes": {}}], + "version": 1 +}` + + var tmpl coremodels.Template + require.NoError(t, json.Unmarshal([]byte(withLegacyFields), &tmpl)) + + out, err := json.Marshal(tmpl) + require.NoError(t, err) + + var raw map[string]any + require.NoError(t, json.Unmarshal(out, &raw)) + assert.NotContains(t, raw, "ksuid") + assert.NotContains(t, raw, "tableId") +} + +func TestGetTemplateByIDReadsTheTemplateKey(t *testing.T) { + var gotPath string + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + gotPath = r.URL.Path + w.Header().Set("content-type", "application/json") + _, _ = w.Write([]byte(templateJSON)) + })) + defer srv.Close() + + logger := zerolog.Nop() + svc := NewDeviceDefinitionCatalogService(&config.Settings{DefinitionsCatalogURL: srv.URL}, &logger) + + tmpl, tokenID, err := svc.GetTemplateByID(context.Background(), "toyota_camry_2020") + require.NoError(t, err) + assert.Equal(t, "/t/toyota_camry_2020.json", gotPath) + assert.Equal(t, "toyota_camry_2020", tmpl.ID) + assert.Equal(t, int64(131), tokenID.Int64()) +} + +func TestGetTemplateByIDDoesNotFallBackToTheOldKey(t *testing.T) { + // A 404 on t/.json means the import has not run. Falling back to + // definitions/.json would serve the pre-migration flat record and hide + // an incomplete import behind apparently-working decodes. + var paths []string + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + paths = append(paths, r.URL.Path) + w.WriteHeader(http.StatusNotFound) + })) + defer srv.Close() + + logger := zerolog.Nop() + svc := NewDeviceDefinitionCatalogService(&config.Settings{DefinitionsCatalogURL: srv.URL}, &logger) + + _, _, err := svc.GetTemplateByID(context.Background(), "toyota_camry_2020") + require.Error(t, err) + assert.Equal(t, []string{"/t/toyota_camry_2020.json"}, paths) + // A genuine 404 must be the typed sentinel, checked by identity, so a + // caller can tell "does not exist" apart from every other failure. + assert.ErrorIs(t, err, ErrTemplateNotFound) +} + +// A 500 from the catalog is an outage, not a missing template. It must not +// satisfy errors.Is(err, ErrTemplateNotFound): a caller that reclassified it +// as not-found could react by creating a duplicate definition for a vehicle +// that already exists, during the worst possible moment to do so. +func TestGetTemplateByID500IsNotErrTemplateNotFound(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + })) + defer srv.Close() + + logger := zerolog.Nop() + svc := NewDeviceDefinitionCatalogService(&config.Settings{DefinitionsCatalogURL: srv.URL}, &logger) + + _, _, err := svc.GetTemplateByID(context.Background(), "toyota_camry_2020") + require.Error(t, err) + assert.NotErrorIs(t, err, ErrTemplateNotFound) +} + +// manufacturer.tokenId is optional in the worker's schema (minimum 1 when +// present). Reporting an absent one as token id 0 sent UpsertDecoding to look +// up manufacturer 0, and made addvin reject a template that exists because 0 +// never equals the caller's manufacturer. +const templateWithoutTokenIDJSON = `{ + "id": "toyota_camry_2026", + "deviceType": "vehicle", + "manufacturer": {"slug": "toyota", "name": "Toyota"}, + "model": "Camry", + "year": 2026, + "attributes": {"number_of_doors": 4}, + "trims": [{"name": "Base", "attributes": {}}], + "version": 1 +}` + +func TestGetTemplateByIDReportsAnAbsentTokenIDAsUnknown(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + _, _ = w.Write([]byte(templateWithoutTokenIDJSON)) + })) + defer srv.Close() + + logger := zerolog.Nop() + svc := NewDeviceDefinitionCatalogService(&config.Settings{DefinitionsCatalogURL: srv.URL}, &logger) + + tmpl, tokenID, err := svc.GetTemplateByID(context.Background(), "toyota_camry_2026") + require.NoError(t, err) + require.NotNil(t, tmpl) + assert.Nil(t, tokenID, "an absent tokenId is unknown, not manufacturer 0") +} + +// GetTemplateByIDFresh shares fetchTemplateDocFrom with GetTemplateByID, so +// the no-fallback guarantee holds for it by inspection -- but this proves it +// for the worker-backed path itself rather than leaving it proven for only +// one of the two exported methods. +func TestGetTemplateByIDFreshDoesNotFallBackToTheOldKey(t *testing.T) { + var paths []string + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + paths = append(paths, r.URL.Path) + w.WriteHeader(http.StatusNotFound) + })) + defer srv.Close() + + logger := zerolog.Nop() + svc := NewDeviceDefinitionCatalogService(&config.Settings{ + DefinitionsCatalogURL: srv.URL, + DefinitionsWorkerURL: srv.URL, + }, &logger) + + _, _, err := svc.GetTemplateByIDFresh(context.Background(), "toyota_camry_2020") + require.Error(t, err) + assert.Equal(t, []string{"/t/toyota_camry_2020.json"}, paths) + assert.ErrorIs(t, err, ErrTemplateNotFound) +} + +// Create used to PUT the pre-migration /definitions/ route, which the new +// worker does not serve at all: every catalog miss on the decode path would +// have failed once deployed. These pin the route and the body shape, because +// both are only observable from outside the process. +func newCreateStub(t *testing.T, existing func(w http.ResponseWriter)) (*httptest.Server, *[]string, *map[string]any) { + t.Helper() + paths := []string{} + var body map[string]any + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + paths = append(paths, r.Method+" "+r.URL.Path) + if r.Method == http.MethodPost { + // identity-api's GraphQL endpoint; createSvc points identity here. + _, _ = w.Write([]byte(identityToyotaJSON)) + return + } + if r.Method == http.MethodGet && strings.HasPrefix(r.URL.Path, "/schema/") { + _, _ = w.Write([]byte(vocabularyJSON)) + return + } + if r.Method == http.MethodGet { + existing(w) + return + } + if r.Method == http.MethodPut { + require.NoError(t, json.NewDecoder(r.Body).Decode(&body)) + } + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"id":"toyota_camry_2020"}`)) + })) + t.Cleanup(srv.Close) + return srv, &paths, &body +} + +func createSvc(srv *httptest.Server) DeviceDefinitionCatalogService { + logger := zerolog.Nop() + // identity points at the stub too: Create resolves the manufacturer there + // before it writes anything. + identity, err := url.Parse(srv.URL) + if err != nil { + panic(err) + } + return NewDeviceDefinitionCatalogService(&config.Settings{ + DefinitionsCatalogURL: srv.URL, + DefinitionsWorkerURL: srv.URL, + DefinitionsWorkerToken: "test-token", + IdentityAPIURL: *identity, + }, &logger) +} + +// A trim of the real /schema/device-type-vehicle.json the worker serves. +const vocabularyJSON = `{ + "id": "vehicle", + "attributes": [ + {"name": "fuel_type", "type": "enum", "options": ["gasoline", "diesel", "electric"]}, + {"name": "driven_wheels", "type": "enum", "options": ["FWD", "RWD", "AWD", "4WD"]}, + {"name": "number_of_doors", "type": "integer", "minimum": 1, "maximum": 8}, + {"name": "fuel_tank_capacity_gal", "type": "number", "minimum": 0, "maximum": 100} + ] +}` + +// What identity-api answers for a minted make. +const identityToyotaJSON = `{"data":{"manufacturer":{"tokenId":131,"name":"Toyota","tableId":0,"owner":"0x0000000000000000000000000000000000000000"}}}` + +var newDefinition = coremodels.DeviceDefinitionTablelandModel{ + ID: "toyota_camry_2020", + Model: "Camry", + Year: 2020, + DeviceType: "vehicle", + KSUID: "26G3iFH7Xc9Wvsw7pg6sD7uzoSS", +} + +func TestCreateWritesATemplate(t *testing.T) { + srv, paths, body := newCreateStub(t, func(w http.ResponseWriter) { w.WriteHeader(http.StatusNotFound) }) + + id, err := createSvc(srv).Create(context.Background(), "Toyota", newDefinition) + require.NoError(t, err) + require.NotNil(t, id) + + assert.Contains(t, *paths, "PUT /t/toyota_camry_2020", "the write must go to the template route") + for _, p := range *paths { + assert.NotContains(t, p, "/definitions/", "no write may touch the pre-migration route") + } + + // The worker rejects a client-supplied server-owned field by name rather + // than stripping it, so sending one fails the whole write. + for _, k := range []string{"version", "createdAt", "updatedAt", "author"} { + assert.NotContains(t, *body, k, "%s is server-owned and must not be sent", k) + } + assert.Equal(t, "toyota_camry_2020", (*body)["id"]) + assert.Equal(t, "vehicle", (*body)["deviceType"]) + assert.Equal(t, "Camry", (*body)["model"]) + assert.Equal(t, float64(2020), (*body)["year"]) + // tokenId is optional in the schema, but a create must never omit it: + // UpsertDecoding and addvin both resolve the template through it. + assert.Equal(t, map[string]any{"slug": "toyota", "name": "Toyota", "tokenId": float64(131)}, (*body)["manufacturer"]) + // ksuid is gone from the contract; it must not ride along in any form. + assert.NotContains(t, *body, "ksuid") + + // trims has minItems 1 in the schema: a model-year sold in one + // configuration still has a trim. + trims, ok := (*body)["trims"].([]any) + require.True(t, ok, "trims must be present") + require.Len(t, trims, 1) + trim := trims[0].(map[string]any) + assert.Equal(t, "Base", trim["name"]) + // A single-trim template has nothing to select on, and an empty selector + // object is what the worker rejects as degenerate on a multi-trim template. + assert.NotContains(t, trim, "selectors") +} + +// The worker's PUT is an upsert unless told otherwise. Create used to read the +// template and then write unconditionally, and in between a Console curator +// could save the same id with its trims: the create replaced them with a single +// Base trim and reported success. The existence check is now the write's own +// precondition, so there is no read before it to race. +func TestCreateIsCreateOnly(t *testing.T) { + paths := []string{} + var ifNoneMatch []string + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + paths = append(paths, r.Method+" "+r.URL.Path) + switch { + case r.Method == http.MethodPost: + _, _ = w.Write([]byte(identityToyotaJSON)) + case strings.HasPrefix(r.URL.Path, "/schema/"): + _, _ = w.Write([]byte(vocabularyJSON)) + case r.Method == http.MethodPut: + ifNoneMatch = append(ifNoneMatch, r.Header.Get("If-None-Match")) + _, _ = w.Write([]byte(`{"id":"toyota_camry_2020"}`)) + default: + w.WriteHeader(http.StatusNotFound) + } + })) + defer srv.Close() + + id, err := createSvc(srv).Create(context.Background(), "Toyota", newDefinition) + require.NoError(t, err) + require.NotNil(t, id) + assert.Equal(t, []string{"*"}, ifNoneMatch, "exactly one PUT, and it must be create-only") + for _, p := range paths { + assert.False(t, strings.HasPrefix(p, "GET /t/"), "a read before the write is the race, not a guard against it: %s", p) + } +} + +// A 412 to If-None-Match: * means a template is already stored at the id. It is +// the one refusal a caller may treat as someone else's success, so it is the +// typed sentinel, and the write is neither retried nor forced. +func TestCreateReportsAnExistingTemplateAsErrTemplateExists(t *testing.T) { + puts := 0 + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch { + case r.Method == http.MethodPost: + _, _ = w.Write([]byte(identityToyotaJSON)) + case strings.HasPrefix(r.URL.Path, "/schema/"): + _, _ = w.Write([]byte(vocabularyJSON)) + case r.Method == http.MethodPut: + puts++ + w.WriteHeader(http.StatusPreconditionFailed) + _, _ = w.Write([]byte(`{"error":"template toyota_camry_2020 already exists","expected":null,"actual":2}`)) + default: + w.WriteHeader(http.StatusNotFound) + } + })) + defer srv.Close() + + id, err := createSvc(srv).Create(context.Background(), "Toyota", newDefinition) + require.Error(t, err) + assert.ErrorIs(t, err, ErrTemplateExists) + assert.Nil(t, id) + assert.Equal(t, 1, puts, "the write must not be retried or forced") +} + +// Every other refusal is a failure. An invalid body must not be mistaken for a +// template someone else stored, and neither may an outage. +func TestCreateSurfacesOtherWorkerFailures(t *testing.T) { + for _, status := range []int{http.StatusUnprocessableEntity, http.StatusInternalServerError} { + t.Run(strconv.Itoa(status), func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch { + case r.Method == http.MethodPost: + _, _ = w.Write([]byte(identityToyotaJSON)) + case strings.HasPrefix(r.URL.Path, "/schema/"): + _, _ = w.Write([]byte(vocabularyJSON)) + case r.Method == http.MethodPut: + w.WriteHeader(status) + _, _ = w.Write([]byte(`{"errors":["rejected"]}`)) + default: + w.WriteHeader(http.StatusNotFound) + } + })) + defer srv.Close() + + id, err := createSvc(srv).Create(context.Background(), "Toyota", newDefinition) + require.Error(t, err) + assert.NotErrorIs(t, err, ErrTemplateExists) + assert.Nil(t, id) + assert.Contains(t, err.Error(), strconv.Itoa(status)) + }) + } +} + +func TestDeleteUsesTheTemplateRoute(t *testing.T) { + srv, paths, _ := newCreateStub(t, func(w http.ResponseWriter) { w.WriteHeader(http.StatusNotFound) }) + + id, err := createSvc(srv).Delete(context.Background(), "Toyota", "toyota_camry_2020") + require.NoError(t, err) + require.NotNil(t, id) + assert.Contains(t, *paths, "DELETE /t/toyota_camry_2020") +} + +// The decode path's metadata is stringified under source-specific names. The +// contract requires typed values drawn from the DeviceType vocabulary, so the +// create folds them the same way the extraction pipeline does. +func TestCreateFoldsMetadataOntoTheVocabulary(t *testing.T) { + srv, _, body := newCreateStub(t, func(w http.ResponseWriter) { w.WriteHeader(http.StatusNotFound) }) + + withMetadata := newDefinition + withMetadata.Metadata = &coremodels.DeviceDefinitionMetadata{ + DeviceAttributes: []coremodels.DeviceTypeAttribute{ + {Name: "fuel_type", Value: "Petrol"}, + {Name: "number_of_doors", Value: "4"}, + {Name: "fuel_tank_capacity_gal", Value: "15.800000"}, + }, + } + _, err := createSvc(srv).Create(context.Background(), "Toyota", withMetadata) + require.NoError(t, err) + + attrs, ok := (*body)["attributes"].(map[string]any) + require.True(t, ok) + // Folded to the vocabulary's spelling, and typed: 15.8, not "15.800000". + assert.Equal(t, "gasoline", attrs["fuel_type"]) + assert.Equal(t, float64(4), attrs["number_of_doors"]) + assert.Equal(t, 15.8, attrs["fuel_tank_capacity_gal"]) + + // Shared by every trim, so they belong on the template. The contract + // forbids an attribute being in both places. + trim := (*body)["trims"].([]any)[0].(map[string]any) + assert.Empty(t, trim["attributes"]) +} + +func TestCreateDropsValuesItCannotMap(t *testing.T) { + srv, _, body := newCreateStub(t, func(w http.ResponseWriter) { w.WriteHeader(http.StatusNotFound) }) + + withJunk := newDefinition + withJunk.Metadata = &coremodels.DeviceDefinitionMetadata{ + DeviceAttributes: []coremodels.DeviceTypeAttribute{ + {Name: "fuel_type", Value: "gasoline"}, + // Names a driven wheel count, not an axle: deliberately unmapped. + {Name: "driven_wheels", Value: "4x2"}, + // Not in the vocabulary at all. + {Name: "generation", Value: "6"}, + // The placeholders the contract makes unrepresentable. + {Name: "number_of_doors", Value: ""}, + }, + } + _, err := createSvc(srv).Create(context.Background(), "Toyota", withJunk) + require.NoError(t, err) + + attrs := (*body)["attributes"].(map[string]any) + assert.Equal(t, map[string]any{"fuel_type": "gasoline"}, attrs, + "only values the vocabulary accepts may be written") +} + +// Writing fewer attributes because a fetch failed is indistinguishable +// afterwards from the source never having carried them. +func TestCreateAbortsWhenTheVocabularyIsUnavailable(t *testing.T) { + paths := []string{} + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + paths = append(paths, r.Method+" "+r.URL.Path) + if r.Method == http.MethodPost { + // identity resolves the make, so the vocabulary is what fails. + _, _ = w.Write([]byte(identityToyotaJSON)) + return + } + if strings.HasPrefix(r.URL.Path, "/schema/") { + w.WriteHeader(http.StatusInternalServerError) + return + } + w.WriteHeader(http.StatusNotFound) + })) + defer srv.Close() + + withMetadata := newDefinition + withMetadata.Metadata = &coremodels.DeviceDefinitionMetadata{ + DeviceAttributes: []coremodels.DeviceTypeAttribute{{Name: "fuel_type", Value: "Petrol"}}, + } + id, err := createSvc(srv).Create(context.Background(), "Toyota", withMetadata) + require.Error(t, err, "a create must not silently write an attribute-free template") + assert.Nil(t, id) + for _, p := range paths { + assert.NotEqual(t, "PUT /t/toyota_camry_2020", p) + } +} + +// The on-chain create this replaced refused a make identity could not resolve. +// Writing the template without a tokenId instead produced definitions that +// UpsertDecoding and addvin could not use, so nothing may be written at all. +func TestCreateRefusesAManufacturerIdentityCannotResolve(t *testing.T) { + for name, identityAnswer := range map[string]string{ + "not minted": `{"data":{"manufacturer":null}}`, + "no token id": `{"data":{"manufacturer":{"tokenId":0,"name":"Toyota"}}}`, + } { + t.Run(name, func(t *testing.T) { + puts := 0 + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch { + case r.Method == http.MethodPost: + _, _ = w.Write([]byte(identityAnswer)) + case r.Method == http.MethodPut: + puts++ + w.WriteHeader(http.StatusOK) + case strings.HasPrefix(r.URL.Path, "/schema/"): + _, _ = w.Write([]byte(vocabularyJSON)) + default: + w.WriteHeader(http.StatusNotFound) + } + })) + defer srv.Close() + + id, err := createSvc(srv).Create(context.Background(), "Toyota", newDefinition) + require.Error(t, err) + assert.ErrorIs(t, err, ErrManufacturerUnresolved) + assert.Nil(t, id) + assert.Zero(t, puts, "nothing may be written for a manufacturer identity cannot resolve") + }) + } +} + +// The legacy flat shape has exactly one slot per attribute. Filling it from an +// arbitrary trim is what produced the record claiming powertrain ICE while +// carrying a hybrid's tank size, so only attributes shared by every trim cross +// over. The Camry fixture holds ICE and HEV trims with different tank sizes. +func TestGetDeviceDefinitionByIDCarriesOnlySharedAttributes(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + _, _ = w.Write([]byte(templateJSON)) + })) + defer srv.Close() + + dd, err := createSvc(srv).GetDeviceDefinitionByID(context.Background(), nil, "toyota_camry_2020") + require.NoError(t, err) + require.NotNil(t, dd) + require.NotNil(t, dd.Metadata) + + got := map[string]string{} + for _, a := range dd.Metadata.DeviceAttributes { + got[a.Name] = a.Value + } + // Shared by every trim, and rendered without exponent notation. + assert.Equal(t, "4", got["number_of_doors"]) + assert.Equal(t, "sedan", got["vehicle_type"]) + // Trim-varying: present on the trims, absent here rather than guessed. + assert.NotContains(t, got, "powertrain_type") + assert.NotContains(t, got, "fuel_tank_capacity_gal") + assert.NotContains(t, got, "mpg_city") + + // ksuid is gone from the contract; inventing one would put a value in a + // field consumers read as an identifier. + assert.Empty(t, dd.KSUID) +} + +func TestGetDeviceDefinitionByIDIsNilForAnotherManufacturer(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + _, _ = w.Write([]byte(templateJSON)) + })) + defer srv.Close() + + dd, err := createSvc(srv).GetDeviceDefinitionByID(context.Background(), big.NewInt(13), "toyota_camry_2020") + require.NoError(t, err) + assert.Nil(t, dd, "a template owned by another manufacturer must not resolve") +} + +// Ownership can only be compared when both sides are known. A template with no +// tokenId belongs to no token, so it cannot belong to another manufacturer's. +func TestGetDeviceDefinitionByIDResolvesATemplateWithoutATokenID(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + _, _ = w.Write([]byte(templateWithoutTokenIDJSON)) + })) + defer srv.Close() + + dd, err := createSvc(srv).GetDeviceDefinitionByID(context.Background(), big.NewInt(131), "toyota_camry_2026") + require.NoError(t, err) + require.NotNil(t, dd, "a template that exists must resolve for the manufacturer whose id it carries") + assert.Equal(t, "toyota_camry_2026", dd.ID) +} + +func TestGetDeviceDefinitionByIDIsNilWhenMissing(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNotFound) + })) + defer srv.Close() + + dd, err := createSvc(srv).GetDeviceDefinitionByID(context.Background(), nil, "toyota_camry_2020") + require.NoError(t, err, "not found is (nil, nil) here; callers branch on it and none create from it") + assert.Nil(t, dd) +} + +// Any other status is a catalog problem and must not be reclassified as +// not-found: that conflation is how an outage gets answered with a write. +func TestGetDeviceDefinitionByIDPropagatesCatalogFailures(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + })) + defer srv.Close() + + dd, err := createSvc(srv).GetDeviceDefinitionByID(context.Background(), nil, "toyota_camry_2020") + require.Error(t, err) + assert.Nil(t, dd) +} + +// GetTemplateByID reports an absent tokenId as nil. A lookup handed that, or a +// 0, must fail cleanly: not dereference nil, and not ask identity for a +// manufacturer that cannot exist. +func TestGetManufacturerNameByIDRejectsAnUnknownTokenID(t *testing.T) { + calls := 0 + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + calls++ + _, _ = w.Write([]byte(`{"data":{"manufacturers":{"totalCount":1,"nodes":[{"tokenId":131,"name":"Toyota"}]}}}`)) + })) + defer srv.Close() + + svc := createSvc(srv) + for _, tokenID := range []*big.Int{big.NewInt(0), nil} { + name, err := svc.GetManufacturerNameByID(context.Background(), tokenID) + require.Error(t, err, "token id %v", tokenID) + assert.Empty(t, name) + } + assert.Zero(t, calls, "an unknown token id is not worth a round trip to identity") +} + +// The definition path and the device-style path flatten the same template +// attributes, so they share one renderer and one order: a number is never +// served in scientific notation, and the array does not shuffle between calls. +func TestTemplateToDefinitionModelRendersAndOrdersAttributes(t *testing.T) { + tmpl := &coremodels.Template{ + ID: "bugatti_veyron-16.4_2006", + Model: "Veyron 16.4", + Year: 2006, + DeviceType: "vehicle", + Attributes: map[string]any{ + "base_msrp": float64(1250000), + "fuel_tank_capacity_gal": float64(15.8), + "number_of_doors": float64(2), + "driven_wheels": "AWD", + }, + } + + want := []coremodels.DeviceTypeAttribute{ + {Name: "base_msrp", Value: "1250000"}, + {Name: "driven_wheels", Value: "AWD"}, + {Name: "fuel_tank_capacity_gal", Value: "15.8"}, + {Name: "number_of_doors", Value: "2"}, + } + for i := 0; i < 20; i++ { + assert.Equal(t, want, templateToDefinitionModel(tmpl).Metadata.DeviceAttributes) + } +} diff --git a/internal/infrastructure/gateways/device_definition_on_chain_service.go b/internal/infrastructure/gateways/device_definition_on_chain_service.go deleted file mode 100644 index e7c0443f..00000000 --- a/internal/infrastructure/gateways/device_definition_on_chain_service.go +++ /dev/null @@ -1,776 +0,0 @@ -//nolint:tagliatelle -package gateways - -import ( - "context" - "database/sql" - "encoding/json" - "fmt" - "io" - "math/big" - "net/http" - "net/url" - "path" - "strings" - "time" - - "github.com/DIMO-Network/device-definitions-api/internal/config" - "github.com/DIMO-Network/device-definitions-api/internal/contracts" - coremodels "github.com/DIMO-Network/device-definitions-api/internal/core/models" - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/db/models" - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/metrics" - "github.com/DIMO-Network/device-definitions-api/internal/infrastructure/sender" - "github.com/DIMO-Network/device-definitions-api/pkg/grpc" - "github.com/DIMO-Network/shared/pkg/db" - stringutils "github.com/DIMO-Network/shared/pkg/strings" - "github.com/aarondl/null/v8" - "github.com/aarondl/sqlboiler/v4/boil" - "github.com/aarondl/sqlboiler/v4/types" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - eth_types "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/patrickmn/go-cache" - "github.com/pkg/errors" - "github.com/prometheus/client_golang/prometheus" - "github.com/rs/zerolog" - "github.com/tidwall/gjson" -) - -//go:generate mockgen -source device_definition_on_chain_service.go -destination mocks/device_definition_on_chain_service_mock.go -package mocks -type DeviceDefinitionOnChainService interface { - GetManufacturer(manufacturerSlug string) (*coremodels.Manufacturer, error) - GetManufacturerNameByID(ctx context.Context, manufacturerID *big.Int) (string, error) - // GetDeviceDefinitionByID get DD from tableland by slug ID and specifying the manufacturer for the table to lookup in - GetDeviceDefinitionByID(ctx context.Context, manufacturerID *big.Int, ID string) (*coremodels.DeviceDefinitionTablelandModel, error) - // GetDefinitionByID get DD from tableland by slug ID, automatically figures out table by oem portion of slug. returns the manufacturer token id too - GetDefinitionByID(ctx context.Context, ID string) (*coremodels.DeviceDefinitionTablelandModel, *big.Int, error) - GetDefinitionTableland(ctx context.Context, manufacturerID *big.Int, ID string) (*coremodels.DeviceDefinitionTablelandModel, error) - GetDeviceDefinitions(ctx context.Context, manufacturerID types.NullDecimal, ID string, model string, year int, pageIndex, pageSize int32) ([]coremodels.DeviceDefinitionTablelandModel, error) - Create(ctx context.Context, manufacturerName string, dd coremodels.DeviceDefinitionTablelandModel) (*string, error) - Update(ctx context.Context, manufacturerName string, input contracts.DeviceDefinitionUpdateInput) (*string, error) - Delete(ctx context.Context, manufacturerName, id string) (*string, error) - QueryDefinitionsCustom(ctx context.Context, manufacturerID int, whereClause string, pageIndex int) ([]coremodels.DeviceDefinitionTablelandModel, error) -} - -type deviceDefinitionOnChainService struct { - settings *config.Settings - logger *zerolog.Logger - client *ethclient.Client - sender sender.Sender - chainID *big.Int - identityAPI IdentityAPI - inmemCache *cache.Cache - dbs func() *db.ReaderWriter -} - -func NewDeviceDefinitionOnChainService(settings *config.Settings, logger *zerolog.Logger, client *ethclient.Client, - chainID *big.Int, sender sender.Sender, dbs func() *db.ReaderWriter) DeviceDefinitionOnChainService { - return &deviceDefinitionOnChainService{ - settings: settings, - logger: logger, - client: client, - chainID: chainID, - sender: sender, - identityAPI: NewIdentityAPIService(logger, settings), - inmemCache: cache.New(128*time.Hour, 1*time.Hour), - dbs: dbs, - } -} - -// GetDeviceDefinitionByID gets dd from tableland with a select statement, returning a db model object -func (e *deviceDefinitionOnChainService) GetDeviceDefinitionByID(ctx context.Context, manufacturerID *big.Int, ID string) (*coremodels.DeviceDefinitionTablelandModel, error) { - tablelandDD, err := e.GetDefinitionTableland(ctx, manufacturerID, ID) - if err != nil { - return nil, err - } - - return tablelandDD, nil -} - -func (e *deviceDefinitionOnChainService) getTablelandTableName(ctx context.Context, manufacturerID *big.Int) (string, error) { - cacheKey := "manufacturer_" + manufacturerID.String() - value, found := e.inmemCache.Get(cacheKey) - if found { - return value.(string), nil - } - - contractAddress := e.settings.EthereumRegistryAddress - queryInstance, err := contracts.NewRegistry(contractAddress, e.client) - if err != nil { - return "", fmt.Errorf("failed to establish NewRegistry: %w", err) - } - - tableName, err := queryInstance.GetDeviceDefinitionTableName(&bind.CallOpts{Context: ctx, Pending: true}, manufacturerID) - - if err != nil { - return "", errors.Wrapf(err, "failed to getTablelandTableName for %d", manufacturerID.Uint64()) - } - e.inmemCache.Set(cacheKey, tableName, time.Hour*300) - - return tableName, nil -} - -func (e *deviceDefinitionOnChainService) GetManufacturerNameByID(ctx context.Context, manufacturerID *big.Int) (string, error) { - contractAddress := e.settings.EthereumRegistryAddress - queryInstance, err := contracts.NewRegistry(contractAddress, e.client) - if err != nil { - return "", fmt.Errorf("failed to establish NewRegistry: %w", err) - } - return queryInstance.GetManufacturerNameById(&bind.CallOpts{Context: ctx, Pending: true}, manufacturerID) -} - -// GetDefinitionByID returns the tableland on chain DD model and the manufacturer token id -func (e *deviceDefinitionOnChainService) GetDefinitionByID(ctx context.Context, ID string) (*coremodels.DeviceDefinitionTablelandModel, *big.Int, error) { - split := strings.Split(ID, "_") - if len(split) != 3 { - return nil, nil, fmt.Errorf("get dd by slug - invalid slug: %s", ID) - } - manufacturerSlug := split[0] - // call out to identity-api w/ caching - manufacturer, err := e.GetManufacturer(manufacturerSlug) - if err != nil { - return nil, nil, errors.Wrapf(err, "failed get DeviceMake: %s", manufacturerSlug) - } - manufacturerID := big.NewInt(int64(manufacturer.TokenID)) - tblDD, err := e.GetDefinitionTableland(ctx, manufacturerID, ID) - return tblDD, manufacturerID, err -} - -func (e *deviceDefinitionOnChainService) GetManufacturer(manufacturerSlug string) (*coremodels.Manufacturer, error) { - value, found := e.inmemCache.Get(manufacturerSlug) - if found { - return value.(*coremodels.Manufacturer), nil - } - manufacturer, err := e.identityAPI.GetManufacturer(manufacturerSlug) - if err != nil { - return nil, err - } - e.inmemCache.Set(manufacturerSlug, manufacturer, time.Hour*300) - return manufacturer, nil -} - -// GetDefinitionTableland gets dd from tableland with a select statement and returns tbl object -func (e *deviceDefinitionOnChainService) GetDefinitionTableland(ctx context.Context, manufacturerID *big.Int, ID string) (*coremodels.DeviceDefinitionTablelandModel, error) { - if manufacturerID == nil || manufacturerID.Uint64() == 0 { - return nil, fmt.Errorf("GetDefinitionTableland - manufacturerID cannot be 0") - } - - tableName, err := e.getTablelandTableName(ctx, manufacturerID) - if err != nil { - e.logger.Info().Msgf("%s", err) - return nil, err - } - - statement := fmt.Sprintf("SELECT * FROM %s WHERE id = '%s'", tableName, ID) - queryParams := map[string]string{ - "statement": statement, - } - - var modelTableland []coremodels.DeviceDefinitionTablelandModel - if err := e.QueryTableland(queryParams, &modelTableland); err != nil { - return nil, errors.Wrapf(err, "failed to query tableland, manufacturer: %d", manufacturerID.Int64()) - } - if len(modelTableland) == 0 { - return nil, nil - } - - return &modelTableland[0], nil -} - -func (e *deviceDefinitionOnChainService) GetDeviceDefinitions(ctx context.Context, manufacturerID types.NullDecimal, ID string, model string, year int, pageIndex, pageSize int32) ([]coremodels.DeviceDefinitionTablelandModel, error) { - if manufacturerID.IsZero() { - return nil, fmt.Errorf("manufacturerID cannot be 0") - } - bigManufID := manufacturerID.Int(new(big.Int)) - tableName, err := e.getTablelandTableName(ctx, bigManufID) - if err != nil { - return nil, err - } - - var conditions []string - if year > 1980 && year < 2999 { - conditions = append(conditions, fmt.Sprintf("year = %d", year)) - } - if len(model) > 0 { - conditions = append(conditions, fmt.Sprintf("model = '%s'", model)) - } - if len(ID) > 0 { - conditions = append(conditions, fmt.Sprintf("id = '%s'", ID)) - } - - whereClause := strings.Join(conditions, " AND ") - if whereClause != "" { - whereClause = " WHERE " + whereClause - } - - statement := fmt.Sprintf("SELECT * FROM %s%s LIMIT %d OFFSET %d", tableName, whereClause, pageSize, pageIndex) - - queryParams := map[string]string{ - "statement": statement, - } - - var modelTableland []coremodels.DeviceDefinitionTablelandModel - if err := e.QueryTableland(queryParams, &modelTableland); err != nil { - return nil, err - } - - return modelTableland, nil -} - -// QueryDefinitionsCustom queries tableland definitions oem table based on manuf ID. Always page size of 500, but you can alter the page index -func (e *deviceDefinitionOnChainService) QueryDefinitionsCustom(ctx context.Context, manufacturerID int, whereClause string, pageIndex int) ([]coremodels.DeviceDefinitionTablelandModel, error) { - if manufacturerID == 0 { - return nil, fmt.Errorf("manufacturerID cannot be 0") - } - - bigManufID := big.NewInt(int64(manufacturerID)) - tableName, err := e.getTablelandTableName(ctx, bigManufID) - if err != nil { - return nil, err - } - if tableName == "" { - return nil, fmt.Errorf("tableName cannot be empty for manufacturer token id %d", manufacturerID) - } - - const pageSize = 500 - statement := fmt.Sprintf("SELECT * FROM %s %s LIMIT %d OFFSET %d", tableName, whereClause, pageSize, pageIndex*pageSize) - - queryParams := map[string]string{ - "statement": statement, - } - - var modelTableland []coremodels.DeviceDefinitionTablelandModel - if err := e.QueryTableland(queryParams, &modelTableland); err != nil { - return nil, err - } - - return modelTableland, nil -} - -func (e *deviceDefinitionOnChainService) QueryTableland(queryParams map[string]string, result interface{}) error { - fullURL, err := url.Parse(e.settings.TablelandAPIGateway) - if err != nil { - return err - } - - fullURL.Path = path.Join(fullURL.Path, "api/v1/query") - - if queryParams != nil { - values := fullURL.Query() - for key, value := range queryParams { - values.Set(key, value) - } - fullURL.RawQuery = values.Encode() - } - - resp, err := http.Get(fullURL.String()) - if err != nil { - return err - } - defer resp.Body.Close() //nolint - - body, err := io.ReadAll(resp.Body) - if err != nil { - return err - } - - if err := json.Unmarshal(body, result); err != nil { - return errors.Wrapf(err, "resp body: %s. url: %s", string(body), fullURL.String()) - } - return nil -} - -const ( - TablelandRequests = "Tableland_All_Request" - TablelandFindByID = "Tableland_FindByID_Request" - TablelandCreated = "Tableland_Created_Request" - TablelandUpdated = "Tableland_Updated_Request" - TablelandDeleted = "Tableland_Deleted_Request" - TablelandExists = "Tableland_Exists_Request" - TablelandErrors = "Tableland_Error_Request" -) - -// Create does a create for tableland, on-chain operation - checks if already exists, inserts transaction in db. returns the onchain transaction -func (e *deviceDefinitionOnChainService) Create(ctx context.Context, manufacturerName string, dd coremodels.DeviceDefinitionTablelandModel) (*string, error) { - - metrics.Success.With(prometheus.Labels{"method": TablelandRequests}).Inc() - e.logger.Info().Msgf("OnChain Start Create for device definition %s. EthereumSendTransaction %t. payload: %+v", dd.ID, e.settings.EthereumSendTransaction, dd) - - if !e.settings.EthereumSendTransaction { - return nil, nil - } - - contractAddress := e.settings.EthereumRegistryAddress - fromAddress := e.sender.Address() - - nonce, err := e.client.PendingNonceAt(ctx, fromAddress) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", dd.ID) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed get PendingNonceAt: %w", err) - } - - gasPrice, err := e.client.SuggestGasPrice(ctx) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", dd.ID) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed get SuggestGasPrice: %w", err) - } - - bump := big.NewInt(20) - bumpedPrice := getGasPrice(gasPrice, bump) - - e.logger.Info().Msgf("bumped gas price: %d", bumpedPrice) - - auth, err := NewKeyedTransactorWithChainID(ctx, e.sender, e.chainID) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", dd.ID) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed get NewKeyedTransactorWithChainID: %w", err) - } - //auth.Value = big.NewInt(0) - auth.Nonce = big.NewInt(int64(nonce)) - auth.GasLimit = uint64(300000) - auth.GasPrice = bumpedPrice - auth.From = fromAddress - - // call identity instead of the chain since more reliable - manufacturer, err := e.GetManufacturer(stringutils.SlugString(manufacturerName)) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", dd.ID) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed get manufacturer from identity: %w", err) - } - if manufacturer == nil { - return nil, fmt.Errorf("manufacturer not found in identity") - } - e.logger.Info().Msgf("manufacturer to create DD with: %+v", manufacturer) - - instance, err := contracts.NewRegistryTransactor(contractAddress, e.client) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", dd.ID) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed create NewRegistryTransactor: %w", err) - } - - if dd.DeviceType == "" { - return nil, fmt.Errorf("dd DeviceTypeId is required") - } - if dd.ImageURI == "" { - dd.ImageURI = GetDefaultImageURL(ctx, dd.ID, e.dbs().Reader.DB) - } - - deviceInputs := contracts.DeviceDefinitionInput{ - Id: dd.ID, - Model: dd.Model, - Year: big.NewInt(int64(dd.Year)), - Ksuid: dd.ID, - DeviceType: dd.DeviceType, - ImageURI: dd.ImageURI, - } - - if dd.Metadata != nil { - jsonData, _ := json.Marshal(dd.Metadata) - deviceInputs.Metadata = string(jsonData) - } - - bigManufID := big.NewInt(int64(manufacturer.TokenID)) - - // check for duplicate create - currentDeviceDefinition, err := e.GetDeviceDefinitionByID(ctx, bigManufID, deviceInputs.Id) - if err != nil { - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - e.logger.Err(err).Msgf("error occurred get device definition %s from tableland when checking for existence.", deviceInputs.Id) - return nil, err - } - if currentDeviceDefinition != nil { - return nil, fmt.Errorf("cannot create device definition, already exists: %s", deviceInputs.Id) - } - - tx, err := instance.InsertDeviceDefinition(auth, bigManufID, deviceInputs) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", dd.ID) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed insert InsertDeviceDefinition: %w", err) - } - - metrics.Success.With(prometheus.Labels{"method": TablelandCreated}).Inc() - - trx := tx.Hash().Hex() - e.logger.Info().Msgf("Executed InsertDeviceDefinition %s with Trx %s in ManufacturerID %s", deviceInputs.Id, trx, bigManufID) - - dbTrx := models.DefinitionTransaction{ - TransactionHash: trx, - DefinitionID: dd.ID, - ManufacturerID: bigManufID.Int64(), - } - err = dbTrx.Insert(ctx, e.dbs().Writer, boil.Infer()) - if err != nil { - return nil, err - } - - return &trx, nil -} - -// Update on-chain device definition, only has basic validation that some fields be present. Requires existing tableland record to exist to update -func (e *deviceDefinitionOnChainService) Update(ctx context.Context, manufacturerName string, input contracts.DeviceDefinitionUpdateInput) (*string, error) { - // todo add retry logic to this call - metrics.Success.With(prometheus.Labels{"method": TablelandRequests}).Inc() - e.logger.Info().Msgf("OnChain Start Update for device definition %s. EthereumSendTransaction %t. payload: %+v", input.Id, e.settings.EthereumSendTransaction, input) - - if !e.settings.EthereumSendTransaction { - return nil, nil - } - - // validations - if input.DeviceType == "" { - return nil, fmt.Errorf("dd DeviceType is required") - } - if len(input.Metadata) > 4 { - if !gjson.Get(input.Metadata, "device_attributes").Exists() { - return nil, fmt.Errorf("device_attributes node is required in metadata if field is set: %s", input.Metadata) - } - } - - contractAddress := e.settings.EthereumRegistryAddress - fromAddress := e.sender.Address() - - nonce, err := e.client.PendingNonceAt(ctx, fromAddress) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", input.Id) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed get PendingNonceAt: %w", err) - } - - gasPrice, err := e.client.SuggestGasPrice(ctx) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", input.Id) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed get SuggestGasPrice: %w", err) - } - - bump := big.NewInt(20) - bumpedPrice := getGasPrice(gasPrice, bump) - - e.logger.Info().Msgf("bumped gas price: %d", bumpedPrice) - - auth, err := NewKeyedTransactorWithChainID(ctx, e.sender, e.chainID) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", input.Id) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed get NewKeyedTransactorWithChainID: %w", err) - } - //auth.Value = big.NewInt(0) - auth.Nonce = big.NewInt(int64(nonce)) - auth.GasLimit = uint64(300000) - auth.GasPrice = bumpedPrice - auth.From = fromAddress - - queryInstance, err := contracts.NewRegistry(contractAddress, e.client) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", input.Id) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed create NewRegistry: %w", err) - } - - // Validate if manufacturer exists - bigManufID, err := queryInstance.GetManufacturerIdByName(&bind.CallOpts{Context: ctx, Pending: true}, manufacturerName) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", input.Id) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed get GetManufacturerIdByName => %s: %w", manufacturerName, err) - } - instance, err := contracts.NewRegistryTransactor(contractAddress, e.client) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", input.Id) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed create NewRegistryTransactor: %w", err) - } - - // check if any field changed - e.logger.Info().Msgf("Validating if device definition %s with tokenID %s exists in tableland", input.Id, bigManufID) - existingTblDD, err := e.GetDeviceDefinitionByID(ctx, bigManufID, input.Id) - if existingTblDD != nil { - e.logger.Info().Msgf("DD %s found.", existingTblDD.ID) - } - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", input.Id) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - e.logger.Err(err).Msgf("Error occurred get device definition %s from tableland.", input.Id) - return nil, err - } - metrics.Success.With(prometheus.Labels{"method": TablelandFindByID}).Inc() - // change this up if want this method to do update and or create - if existingTblDD == nil { - return nil, fmt.Errorf("device definition %s not found in tableland to update", input.Id) - } - metrics.Success.With(prometheus.Labels{"method": TablelandExists}).Inc() - // todo - change GetDeviceDefinition above to return just the tableland object, and compare with our input for any changes. - // if no changes just return nil trx hash. do not allow changing model or year since it changes the slug id - need to look into these cases better - // as they have vehicle NFT implications. - - e.logger.Info().Msgf("Executing UpdateDeviceDefinition %s with manufacturer ID %s", input.Id, bigManufID) - - tx, err := instance.UpdateDeviceDefinition(auth, bigManufID, input) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", input.Id) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed update UpdateDeviceDefinition: %w", err) - } - metrics.Success.With(prometheus.Labels{"method": TablelandUpdated}).Inc() - - trx := tx.Hash().Hex() - - e.logger.Info().Msgf("Executed UpdateDeviceDefinition %s with Trx %s in ManufacturerID %s", input.Id, trx, bigManufID) - dbTrx := models.DefinitionTransaction{ - TransactionHash: trx, - DefinitionID: existingTblDD.ID, - ManufacturerID: bigManufID.Int64(), - } - err = dbTrx.Insert(ctx, e.dbs().Writer, boil.Infer()) - if err != nil { - return nil, err - } - - return &trx, nil -} - -// Delete on-chain device definition by id. Requires existing tableland record to exist to delete -func (e *deviceDefinitionOnChainService) Delete(ctx context.Context, manufacturerName, id string) (*string, error) { - - metrics.Success.With(prometheus.Labels{"method": TablelandRequests}).Inc() - e.logger.Info().Msgf("OnChain Start Delete for device definition %s. EthereumSendTransaction %t.", id, e.settings.EthereumSendTransaction) - - if !e.settings.EthereumSendTransaction { - return nil, nil - } - - // validations - if len(id) == 0 { - return nil, fmt.Errorf("id is required") - } - - contractAddress := e.settings.EthereumRegistryAddress - fromAddress := e.sender.Address() - - nonce, err := e.client.PendingNonceAt(ctx, fromAddress) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", id) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed get PendingNonceAt: %w", err) - } - - gasPrice, err := e.client.SuggestGasPrice(ctx) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", id) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed get SuggestGasPrice: %w", err) - } - - bump := big.NewInt(20) - bumpedPrice := getGasPrice(gasPrice, bump) - - e.logger.Info().Msgf("bumped gas price: %d", bumpedPrice) - - auth, err := NewKeyedTransactorWithChainID(ctx, e.sender, e.chainID) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", id) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed get NewKeyedTransactorWithChainID: %w", err) - } - //auth.Value = big.NewInt(0) - auth.Nonce = big.NewInt(int64(nonce)) - auth.GasLimit = uint64(300000) - auth.GasPrice = bumpedPrice - auth.From = fromAddress - - queryInstance, err := contracts.NewRegistry(contractAddress, e.client) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", id) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed create NewRegistry: %w", err) - } - - // Validate if manufacturer exists - bigManufID, err := queryInstance.GetManufacturerIdByName(&bind.CallOpts{Context: ctx, Pending: true}, manufacturerName) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", id) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed get GetManufacturerIdByName => %s: %w", manufacturerName, err) - } - instance, err := contracts.NewRegistryTransactor(contractAddress, e.client) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", id) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed create NewRegistryTransactor: %w", err) - } - - // check if any field changed - existingTblDD, err := e.GetDeviceDefinitionByID(ctx, bigManufID, id) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", id) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - e.logger.Err(err).Msgf("Error occurred get device definition %s from tableland, manuf id: %d.", id, bigManufID.Int64()) - return nil, err - } - metrics.Success.With(prometheus.Labels{"method": TablelandFindByID}).Inc() - if existingTblDD == nil { - return nil, fmt.Errorf("device definition %s not found in tableland to update", id) - } - metrics.Success.With(prometheus.Labels{"method": TablelandExists}).Inc() - // todo - change GetDeviceDefinition above to return just the tableland object, and compare with our input for any changes. - // if no changes just return nil trx hash. do not allow changing model or year since it changes the slug id - need to look into these cases better - // as they have vehicle NFT implications. - - e.logger.Info().Msgf("Executing DeleteDeviceDefinition %s with manufacturer ID %d", id, bigManufID.Int64()) - - tx, err := instance.DeleteDeviceDefinition(auth, bigManufID, id) - if err != nil { - e.logger.Err(err).Msgf("OnChainError - %s", id) - metrics.InternalError.With(prometheus.Labels{"method": TablelandErrors}).Inc() - return nil, fmt.Errorf("failed delete DeleteDeviceDefinition: %w", err) - } - metrics.Success.With(prometheus.Labels{"method": TablelandDeleted}).Inc() - - trx := tx.Hash().Hex() - - e.logger.Info().Msgf("Executed DeleteDeviceDefinition %s with Trx %s in ManufacturerID %s", id, trx, bigManufID) - dbTrx := models.DefinitionTransaction{ - TransactionHash: trx, - DefinitionID: existingTblDD.ID, - ManufacturerID: bigManufID.Int64(), - } - err = dbTrx.Insert(ctx, e.dbs().Writer, boil.Infer()) - if err != nil { - return nil, err - } - - return &trx, nil -} - -func validateAttributes(current, newAttrs []coremodels.DeviceTypeAttribute) ([]coremodels.DeviceTypeAttribute, []coremodels.DeviceTypeAttribute) { - currentMap := attributesToMap(current) - newMap := attributesToMap(newAttrs) - - var newOrModifiedAttributes []coremodels.DeviceTypeAttribute - var removedAttributes []coremodels.DeviceTypeAttribute - - // Find new or changed attributes - for name, newValue := range newMap { - if currentValue, exists := currentMap[name]; !exists || currentValue != newValue { - newOrModifiedAttributes = append(newOrModifiedAttributes, coremodels.DeviceTypeAttribute{ - Name: name, - Value: newValue, - }) - } - } - - // Find deleted attributes - for name, currentValue := range currentMap { - if _, exists := newMap[name]; !exists { - removedAttributes = append(removedAttributes, coremodels.DeviceTypeAttribute{ - Name: name, - Value: currentValue, - }) - } - } - - return newOrModifiedAttributes, removedAttributes -} - -func attributesToMap(attributes []coremodels.DeviceTypeAttribute) map[string]string { - attrMap := make(map[string]string) - for _, attr := range attributes { - attrMap[attr.Name] = attr.Value - } - return attrMap -} - -func getGasPrice(price *big.Int, bump *big.Int) *big.Int { - // Calculating the bumped gas price - bumpAmount := new(big.Int).Mul(price, bump) - bumpAmount.Div(bumpAmount, big.NewInt(100)) - bumpedPrice := new(big.Int).Add(bumpAmount, price) - - return bumpedPrice -} - -func NewKeyedTransactorWithChainID(context context.Context, send sender.Sender, chainID *big.Int) (*bind.TransactOpts, error) { - signer := eth_types.LatestSignerForChainID(chainID) - return &bind.TransactOpts{ - From: send.Address(), - Signer: func(_ common.Address, tx *eth_types.Transaction) (*eth_types.Transaction, error) { - signature, err := send.Sign(context, signer.Hash(tx)) - if err != nil { - return nil, err - } - return tx.WithSignature(signer, signature) - }, - Context: context, - }, nil -} - -func GetDeviceAttributesTyped(metadata null.JSON, key string) []coremodels.DeviceTypeAttribute { - var respAttrs []coremodels.DeviceTypeAttribute - var ai map[string]any - if err := metadata.Unmarshal(&ai); err == nil { - if ai != nil { - if a, ok := ai[key]; ok && a != nil { - attributes := ai[key].(map[string]any) - for key, value := range attributes { - v := fmt.Sprint(value) - if len(v) > 0 { - respAttrs = append(respAttrs, coremodels.DeviceTypeAttribute{ - Name: key, - Value: v, - }) - } - } - } - } - } - return respAttrs -} - -func GetDefaultImageURL(ctx context.Context, definitionID string, db2 *sql.DB) string { - - all, err := models.Images(models.ImageWhere.DefinitionID.EQ(definitionID)).All(ctx, db2) - if err != nil { - return "" - } - imgURI := "" - if all != nil { - w := 0 - for _, image := range all { - extra := 0 - if !image.NotExactImage { - extra = 2000 // we want to give preference to exact images - } - if image.Width.Int+extra > w { - w = image.Width.Int + extra - imgURI = image.SourceURL - } - } - } - return imgURI -} - -// note: below code is duplicated in identity-api - -// BuildDeviceTypeAttributesTbland converts a list of DeviceTypeAttributeRequest to a JSON string for the given device type ID. -// It works the same as BuildDeviceTypeAttributes but the metadatakey is always "device_attributes" and does no attribute name validation -func BuildDeviceTypeAttributesTbland(attributes []*grpc.DeviceTypeAttributeRequest) string { - if attributes == nil { - return "" - } - deviceTypeInfo := coremodels.DeviceDefinitionMetadata{} - metaData := make([]coremodels.DeviceTypeAttribute, len(attributes)) - for i, prop := range attributes { - metaData[i].Name = prop.Name - metaData[i].Value = prop.Value - } - deviceTypeInfo.DeviceAttributes = metaData - j, _ := json.Marshal(deviceTypeInfo) - return string(j) -} diff --git a/internal/infrastructure/gateways/device_definition_on_chain_service_test.go b/internal/infrastructure/gateways/device_definition_on_chain_service_test.go deleted file mode 100644 index f35f0ff5..00000000 --- a/internal/infrastructure/gateways/device_definition_on_chain_service_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package gateways - -import ( - _ "embed" // import the embed package - "testing" - - "github.com/DIMO-Network/device-definitions-api/internal/core/models" - - "github.com/stretchr/testify/assert" -) - -func Test_deviceDefinitionOnChainService_validateAttributes(t *testing.T) { - tests := []struct { - name string - currentAttributes []models.DeviceTypeAttribute - newAttributes []models.DeviceTypeAttribute - expectedNewOrMod []models.DeviceTypeAttribute - expectedRemoved []models.DeviceTypeAttribute - }{ - { - name: "add new attribute", - currentAttributes: []models.DeviceTypeAttribute{ - {Name: "driven_wheels", Value: "AWD"}, - {Name: "manufacturer_code", Value: "K3S"}, - }, - newAttributes: []models.DeviceTypeAttribute{ - {Name: "driven_wheels", Value: "AWD"}, - {Name: "manufacturer_code", Value: "K3S"}, - {Name: "number_of_doors", Value: "4"}, - }, - expectedNewOrMod: []models.DeviceTypeAttribute{ - {Name: "number_of_doors", Value: "4"}, - }, - expectedRemoved: []models.DeviceTypeAttribute{}, - }, - { - name: "remove current attribute", - currentAttributes: []models.DeviceTypeAttribute{ - {Name: "driven_wheels", Value: "AWD"}, - {Name: "manufacturer_code", Value: "K3S"}, - }, - newAttributes: []models.DeviceTypeAttribute{ - {Name: "powertrain_type", Value: "BEV"}, - }, - expectedNewOrMod: []models.DeviceTypeAttribute{ - {Name: "powertrain_type", Value: "BEV"}, - }, - expectedRemoved: []models.DeviceTypeAttribute{ - {Name: "driven_wheels", Value: "AWD"}, - {Name: "manufacturer_code", Value: "K3S"}, - }, - }, - { - name: "update current attribute", - currentAttributes: []models.DeviceTypeAttribute{ - {Name: "fuel_type", Value: "AWD"}, - }, - newAttributes: []models.DeviceTypeAttribute{ - {Name: "fuel_type", Value: "Electric"}, - }, - expectedNewOrMod: []models.DeviceTypeAttribute{ - {Name: "fuel_type", Value: "Electric"}, - }, - expectedRemoved: []models.DeviceTypeAttribute{}, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - newOrModified, removed := validateAttributes(test.currentAttributes, test.newAttributes) - - assert.ElementsMatch(t, test.expectedNewOrMod, newOrModified, "New or modified attributes should match expected") - assert.ElementsMatch(t, test.expectedRemoved, removed, "Removed attributes should match expected") - }) - } -} diff --git a/internal/infrastructure/gateways/japan_17vin_api.go b/internal/infrastructure/gateways/japan_17vin_api.go index 2f9c18f9..1ab70519 100644 --- a/internal/infrastructure/gateways/japan_17vin_api.go +++ b/internal/infrastructure/gateways/japan_17vin_api.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "fmt" "io" + "regexp" "strconv" "strings" "time" @@ -18,6 +19,44 @@ import ( "github.com/tidwall/gjson" ) +// bodyStylePattern matches Japanese EPC body-style codes like "4D", "5D", "2D", +// "4DR", "5HB", "4WD", which sometimes appear in the "Model Name" column instead +// of an actual vehicle series. +// +// The shape is deliberately narrow: a single door/drive count followed by one of +// a closed set of body-type abbreviations -- D/DR (door), HB (hatchback), W/WG +// (wagon), WD (wheel drive), WS (wheel steering). An earlier version was +// `^\d+[A-Za-z]{0,3}$`, which also swallowed genuine model names that happen to +// be digit-led: 86, 911, 500, 300, 240, 370Z, 350Z, 240SX, 2000GT. Those decoded +// to an empty model and then to an unresolvable definition id. Widening the +// letter count to {1,3} is not sufficient either -- it still eats 370Z, 240SX and +// 2000GT -- so the letters have to be enumerated rather than counted. +var bodyStylePattern = regexp.MustCompile(`^[1-9](D|DR|HB|W|WG|WD|WS)$`) + +// nonModelTokens are EPC markers observed in the "Additional Vehicle +// Infomation" column that are never a vehicle series. They only matter on the +// last-resort path in extractModelName, which otherwise takes the column's first +// multi-character token and would happily return "LHD" as a model. +var nonModelTokens = map[string]struct{}{ + "LHD": {}, // left-hand drive + "RHD": {}, // right-hand drive + "CBU": {}, // completely built up + "DCB": {}, // double cab + "SED": {}, // sedan + "HB": {}, // hatchback + "WGN": {}, // wagon + "HTWC": {}, // EPC trim marker + "TBO": {}, // turbo + "USA": {}, // market + "CHI": {}, // market + "UK": {}, // market +} + +// modelNameColumns lists Col_name candidates for the vehicle series, in priority order. +// 17vin responses vary by brand; docs show "Model name" (lowercase), existing production +// data used "Model Name", and Chinese-column responses use "车型". +var modelNameColumns = []string{"Model Name", "Model name", "车型"} + //go:generate mockgen -source japan_17vin_api.go -destination mocks/japan_17vin_api_mock.go -package mocks type Japan17VINAPI interface { GetVINInfo(vin string) (*coremodels.Japan17MMY, []byte, error) @@ -60,24 +99,7 @@ func (j *japan17VINAPI) GetVINInfo(vin string) (*coremodels.Japan17MMY, []byte, if err != nil { return nil, nil, errors.Wrapf(err, "failed to parse year string %s", yearString) } - model := "" - modelNameProperty := parsed.Get(`data.model_original_epc_list.0.CarAttributes.#(Col_name="Model Name").Col_value`).String() - if modelNameProperty != "" { - if strings.Contains(modelNameProperty, `/`) { - // this means it has two options, sometimes in the additional info it will have the model - additionalInfo := parsed.Get(`data.model_original_epc_list.0.CarAttributes.#(Col_name="Additional Vehicle Infomation").Col_value`).String() - splitInfo := strings.Split(additionalInfo, " ") - if len(splitInfo) > 0 { - // grab the first name which is usually the model - model = splitInfo[0] - } else { - // if nothing found then just grab the first value from the model name - model = strings.Split(modelNameProperty, "/")[0] - } - } else { - model = modelNameProperty - } - } + model := extractModelName(parsed) result := coremodels.Japan17MMY{ VIN: vin, @@ -89,6 +111,104 @@ func (j *japan17VINAPI) GetVINInfo(vin string) (*coremodels.Japan17MMY, []byte, return &result, bodyBytes, nil } + +// extractModelName finds the vehicle series name from the 17vin response. +// Preference order: (1) data.model_list[0].Model_en — 17vin's standardized +// product name, populated for known 17-char VINs; (2) the EPC +// model_original_epc_list attributes, which may carry raw internal model +// names with body-style codes, parenthetical factory tags, or multi-model +// platform lists (e.g. "NOAH/VOXY/ESQUIRE"). +func extractModelName(parsed gjson.Result) string { + if std := sanitizeModelName(parsed.Get("data.model_list.0.Model_en").String()); std != "" { + return std + } + entries := parsed.Get("data.model_original_epc_list").Array() + for _, entry := range entries { + attrs := entry.Get("CarAttributes") + addl := attrs.Get(`#(Col_name="Additional Vehicle Infomation").Col_value`).String() + for _, col := range modelNameColumns { + raw := attrs.Get(fmt.Sprintf(`#(Col_name=%q).Col_value`, col)).String() + candidate := pickModelCandidate(raw, addl) + if candidate != "" { + return candidate + } + } + // fall back: first meaningful token of Additional Vehicle Infomation + if addl != "" { + for t := range strings.FieldsSeq(addl) { + if isModelCandidateToken(t) { + return sanitizeModelName(t) + } + } + } + } + return "" +} + +// sanitizeModelName strips characters that don't belong in a slugged model +// name: parenthetical factory tags like "(TMMC" and trailing commas. +func sanitizeModelName(s string) string { + s = strings.TrimSpace(s) + if i := strings.IndexAny(s, "(,"); i >= 0 { + s = s[:i] + } + return strings.TrimSpace(s) +} + +// pickModelCandidate accepts a raw Col_value, splits on "/" for multi-model responses, +// and returns the best non-body-style entry. If multiple candidates remain and the +// hint (additional-info column) contains one of them, that one wins; otherwise the +// first valid candidate is returned. Parenthetical suffixes are stripped. +func pickModelCandidate(raw, hint string) string { + raw = sanitizeModelName(raw) + if raw == "" { + return "" + } + var candidates []string + for p := range strings.SplitSeq(raw, "/") { + p = strings.TrimSpace(p) + if p != "" && !isBodyStyleCode(p) { + candidates = append(candidates, p) + } + } + if len(candidates) == 0 { + return "" + } + if len(candidates) > 1 && hint != "" { + hintUpper := strings.ToUpper(hint) + for _, c := range candidates { + if strings.Contains(hintUpper, strings.ToUpper(c)) { + return c + } + } + } + return candidates[0] +} + +func isBodyStyleCode(s string) bool { + return bodyStylePattern.MatchString(strings.TrimSpace(s)) +} + +// isModelCandidateToken reports whether a bare token from the additional-info +// column could plausibly be a vehicle series. It must be longer than one +// character, must contain a letter, and must be neither a body-style code nor a +// known EPC marker. Trim/seating codes such as "05S" and "07S" are rejected by +// the letter-position check: a series name does not lead with a digit and end in +// a single letter. +func isModelCandidateToken(t string) bool { + t = strings.TrimSpace(t) + if len(t) < 2 || isBodyStyleCode(t) { + return false + } + if _, ok := nonModelTokens[strings.ToUpper(t)]; ok { + return false + } + return strings.ContainsFunc(t, unicode.IsLetter) && !seatingCodePattern.MatchString(t) +} + +// seatingCodePattern matches EPC seating/spec codes like "05S", "07S", "08S". +var seatingCodePattern = regexp.MustCompile(`^\d{2}[A-Za-z]$`) + func md5Hex(s string) string { hash := md5.Sum([]byte(s)) return hex.EncodeToString(hash[:]) diff --git a/internal/infrastructure/gateways/japan_17vin_api_test.go b/internal/infrastructure/gateways/japan_17vin_api_test.go new file mode 100644 index 00000000..98cea695 --- /dev/null +++ b/internal/infrastructure/gateways/japan_17vin_api_test.go @@ -0,0 +1,367 @@ +package gateways + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/tidwall/gjson" +) + +func Test_isBodyStyleCode(t *testing.T) { + cases := map[string]bool{ + // Genuine EPC body-style codes. + "4D": true, + "5D": true, + "2D": true, + "3D": true, + "2DR": true, + "4DR": true, + "5DR": true, + "3HB": true, + "5HB": true, + "2WD": true, + "4WD": true, + "4WS": true, + "5W": true, + "5WG": true, + + // Real model names that are digit-led. Every one of these matched the + // original `^\d+[A-Za-z]{0,3}$` and was therefore discarded, leaving the + // decode with an empty model. The starred ones also match the narrower + // `^\d+[A-Za-z]{1,3}$`, which is why the letters are enumerated instead. + "86": false, + "911": false, + "500": false, + "300": false, + "124": false, + "240": false, + "718": false, + "2": false, // Polestar 2 + "4": false, // Polestar 4 + "370Z": false, // * + "350Z": false, // * + "240SX": false, // * + "2000GT": false, // * + "600LT": false, // * + "3000GT": false, // * + + // Word-shaped names and edge cases. + "Crown": false, + "CAMRY": false, + "": false, + "Q7": false, // letter+digit, not digit-leading + "10D": false, // no vehicle has ten doors; not a code we accept + } + for in, want := range cases { + assert.Equalf(t, want, isBodyStyleCode(in), "input %q", in) + } +} + +// Test_pickModelCandidate_digitLedModels is the payload-level counterpart to the +// unit cases above: a digit-led series name must survive candidate selection. +func Test_pickModelCandidate_digitLedModels(t *testing.T) { + assert.Equal(t, "86", pickModelCandidate("86", "")) + assert.Equal(t, "370Z", pickModelCandidate("370Z", "")) + assert.Equal(t, "86", pickModelCandidate("4D/86", "")) + assert.Equal(t, "911", pickModelCandidate("911/CARRERA", "")) + assert.Equal(t, "CARRERA", pickModelCandidate("911/CARRERA", "CARRERA 4S")) +} + +func Test_extractModelName_digitLedModelSurvives(t *testing.T) { + // Toyota 86 (ZN6). Before the body-style pattern was narrowed, "86" was + // classified as a body-style code, extractModelName returned "", and the + // decode produced no usable definition id. + payload := `{"data":{"epc":"toyota","model_year_from_vin":"2017", + "model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"86"}, + {"Col_name":"Additional Vehicle Infomation","Col_value":"2D 06S"} + ]}]}}` + assert.Equal(t, "86", extractModelName(gjson.Parse(payload))) +} + +func Test_isModelCandidateToken(t *testing.T) { + cases := map[string]bool{ + "Crown": true, + "CAMRY": true, + "86": false, // digits only: no letter, cannot be a token-level series + "4D": false, // body-style code + "05S": false, // seating code + "07S": false, + "LHD": false, // EPC marker + "RHD": false, + "HTWC": false, + "SED": false, + "D": false, // too short + "": false, + "Hybrid": true, + } + for in, want := range cases { + assert.Equalf(t, want, isModelCandidateToken(in), "input %q", in) + } +} + +// Test_extractModelName_fallbackRejectsMarkers covers the last-resort path: when +// no model-name column resolves, the additional-info column must not hand back a +// drive-side or trim marker as the vehicle series. +func Test_extractModelName_fallbackRejectsMarkers(t *testing.T) { + payload := `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"4D"}, + {"Col_name":"Additional Vehicle Infomation","Col_value":"LHD 05S HTWC Alphard"} + ]}]}}` + assert.Equal(t, "Alphard", extractModelName(gjson.Parse(payload))) +} + +func Test_pickModelCandidate(t *testing.T) { + assert.Equal(t, "Crown", pickModelCandidate("Crown", "")) + assert.Equal(t, "CAMRY", pickModelCandidate("CAMRY/HYBRID", "")) + assert.Equal(t, "Crown", pickModelCandidate("4D/Crown", "")) + assert.Equal(t, "", pickModelCandidate("4D", "")) + assert.Equal(t, "", pickModelCandidate("", "")) + // hint picks the platform variant actually built + assert.Equal(t, "VOXY", pickModelCandidate("NOAH/VOXY", "VOXY 07S HTWC CBU")) + assert.Equal(t, "VOXY", pickModelCandidate("NOAH/VOXY/ESQUIRE", "VOXY 07S HTWVMCBU")) + // hint irrelevant when it doesn't match any candidate: first wins + assert.Equal(t, "CROWN", pickModelCandidate("CROWN/HYBRID", "4D HTWC")) +} + +func Test_extractModelName_rejectsBodyStyle(t *testing.T) { + // simulates prior bug: Model Name column held "4D"; series name lives in additional info. + payload := `{ + "data": { + "model_original_epc_list": [{ + "CarAttributes": [ + {"Col_name": "Model Name", "Col_value": "4D"}, + {"Col_name": "Additional Vehicle Infomation", "Col_value": "Crown Hybrid"} + ] + }] + } + }` + got := extractModelName(gjson.Parse(payload)) + assert.Equal(t, "Crown", got) +} + +func Test_extractModelName_prefersModelNameWhenValid(t *testing.T) { + payload := `{ + "data": { + "model_original_epc_list": [{ + "CarAttributes": [ + {"Col_name": "Model Name", "Col_value": "CAMRY/HYBRID"}, + {"Col_name": "Additional Vehicle Infomation", "Col_value": "LHD CHI"} + ] + }] + } + }` + assert.Equal(t, "CAMRY", extractModelName(gjson.Parse(payload))) +} + +func Test_extractModelName_fallsThroughColumnVariants(t *testing.T) { + payload := `{ + "data": { + "model_original_epc_list": [{ + "CarAttributes": [ + {"Col_name": "Model name", "Col_value": "Crown"} + ] + }] + } + }` + assert.Equal(t, "Crown", extractModelName(gjson.Parse(payload))) +} + +func Test_extractModelName_chineseFallback(t *testing.T) { + payload := `{ + "data": { + "model_original_epc_list": [{ + "CarAttributes": [ + {"Col_name": "车型", "Col_value": "Crown"} + ] + }] + } + }` + assert.Equal(t, "Crown", extractModelName(gjson.Parse(payload))) +} + +func Test_extractModelName_empty(t *testing.T) { + assert.Equal(t, "", extractModelName(gjson.Parse(`{"data":{}}`))) +} + +// Data-driven regression suite using real 17vin payloads. Each case pairs the +// full `data.model_original_epc_list` attributes with the model name we expect +// the adapter to surface (compare against the DD slug historically indexed). +func Test_extractModelName_realPayloads(t *testing.T) { + cases := []struct { + name string + payload string + want string + }{ + { + name: "JTDZN3EU8HJ060118 Prius v", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"PRIUS V"}, + {"Col_name":"Additional Vehicle Infomation","Col_value":"05S USA"} + ]}]}}`, + want: "PRIUS V", + }, + { + name: "TRJ150-0081549 Land Cruiser Prado", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"LAND CRUISER PRADO"}, + {"Col_name":"Additional Vehicle Infomation","Col_value":"5D 07S"} + ]}]}}`, + want: "LAND CRUISER PRADO", + }, + { + name: "GRX120-3043102 Mark X", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"MARK X"} + ]}]}}`, + want: "MARK X", + }, + { + name: "JTEBU29J940026005 Land Cruiser Prado", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"LAND CRUISER PRADO"}, + {"Col_name":"Additional Vehicle Infomation","Col_value":"LHD 5D"} + ]}]}}`, + want: "LAND CRUISER PRADO", + }, + { + name: "ZWR90-8000186 Voxy (NOAH/VOXY disambiguated by addl info)", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"NOAH/VOXY"}, + {"Col_name":"Additional Vehicle Infomation","Col_value":"VOXY 07S HTWC CBU"} + ]}]}}`, + want: "VOXY", + }, + { + name: "3TYLC5LN5ST036165 Tacoma", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"TACOMA"}, + {"Col_name":"Additional Vehicle Infomation","Col_value":"DCB"} + ]}]}}`, + want: "TACOMA", + }, + { + name: "A210A-0012622 Raize", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"RAIZE"}, + {"Col_name":"Additional Vehicle Infomation","Col_value":"5D 05S"} + ]}]}}`, + want: "RAIZE", + }, + { + name: "AGH30-0397617 Alphard (previously ALPHD07S bug)", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"ALPHARD/VELLFIRE/HV"}, + {"Col_name":"Additional Vehicle Infomation","Col_value":"ALPHD07S"} + ]}]}}`, + want: "ALPHARD", + }, + { + name: "ZVW60-4006778 Prius", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"PRIUS"}, + {"Col_name":"Additional Vehicle Infomation","Col_value":"5D"} + ]}]}}`, + want: "PRIUS", + }, + { + name: "ZRR80-0413374 Voxy (NOAH/VOXY/ESQUIRE disambiguated)", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"NOAH/VOXY/ESQUIRE"}, + {"Col_name":"Additional Vehicle Infomation","Col_value":"VOXY 07S HTWVMCBU"} + ]}]}}`, + want: "VOXY", + }, + { + name: "SJNFAAJ11U2132164 Qashqai UK Make", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"QASHQAI UK MAKE"} + ]}]}}`, + want: "QASHQAI UK MAKE", + }, + { + name: "NHP10-6705283 Aqua", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"AQUA"}, + {"Col_name":"Additional Vehicle Infomation","Col_value":"5D"} + ]}]}}`, + want: "AQUA", + }, + { + name: "NHP170-7078636 Sienta", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"SIENTA"}, + {"Col_name":"Additional Vehicle Infomation","Col_value":"07S HTWC"} + ]}]}}`, + want: "SIENTA", + }, + { + name: "7MUAAABG3PV055668 Corolla Cross", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"COROLLA CROSS"}, + {"Col_name":"Additional Vehicle Infomation","Col_value":"LHD"} + ]}]}}`, + want: "COROLLA CROSS", + }, + { + name: "SUNFAAZE1U0009011 Leaf UK Make", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"LEAF UK MAKE"} + ]}]}}`, + want: "LEAF UK MAKE", + }, + { + name: "GWS214-6014148 Crown (slash with HYBRID variant)", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"CROWN/HYBRID"}, + {"Col_name":"Additional Vehicle Infomation","Col_value":"4D HTWC"} + ]}]}}`, + want: "CROWN", + }, + { + name: "212HGCEZ3NC010151 Lexus NX — prefer model_list.Model_en", + payload: `{"data":{"model_list":[{"Model_en":"NX 350","Brand_en":"Lexus"}],"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"LEXUS NX SERIES(TMMC"}, + {"Col_name":"Additional Vehicle Infomation","Col_value":"LHD TBO USA"} + ]}]}}`, + want: "NX 350", + }, + { + name: "paren stripped even when model_list absent", + payload: `{"data":{"model_original_epc_list":[{"CarAttributes":[ + {"Col_name":"Model Name","Col_value":"LEXUS NX SERIES(TMMC"} + ]}]}}`, + want: "LEXUS NX SERIES", + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.want, extractModelName(gjson.Parse(tc.payload))) + }) + } +} + +// Regression: real 17vin response for GWS214-6014148 (Toyota Crown Hybrid). +// Previously yielded "4D" from the "Additional Vehicle Infomation" column and +// got minted on-chain as toyota_4d_2017. +func Test_extractModelName_gws214Crown(t *testing.T) { + payload := `{ + "data": { + "epc": "toyota", + "model_year_from_vin": "2017", + "model_original_epc_list": [{ + "CarAttributes": [ + {"Col_name": "车型", "Col_value": "CROWN/HYBRID"}, + {"Col_name": "Model Name", "Col_value": "CROWN/HYBRID"}, + {"Col_name": "车型代码", "Col_value": "GWS214-AEXZB"}, + {"Col_name": "Model Code", "Col_value": "GWS214-AEXZB"}, + {"Col_name": "车身", "Col_value": "SED"}, + {"Col_name": "Body", "Col_value": "SED"}, + {"Col_name": "Engine Code", "Col_value": "2GRFXE"}, + {"Col_name": "Additional Vehicle Infomation", "Col_value": "4D HTWC"} + ] + }] + } + }` + assert.Equal(t, "CROWN", extractModelName(gjson.Parse(payload))) +} diff --git a/internal/infrastructure/gateways/mocks/device_definition_catalog_service_mock.go b/internal/infrastructure/gateways/mocks/device_definition_catalog_service_mock.go new file mode 100644 index 00000000..96e04383 --- /dev/null +++ b/internal/infrastructure/gateways/mocks/device_definition_catalog_service_mock.go @@ -0,0 +1,165 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: device_definition_catalog_service.go +// +// Generated by this command: +// +// mockgen -source device_definition_catalog_service.go -destination mocks/device_definition_catalog_service_mock.go -package mocks +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + big "math/big" + reflect "reflect" + + models "github.com/DIMO-Network/device-definitions-api/internal/core/models" + gomock "go.uber.org/mock/gomock" +) + +// MockDeviceDefinitionCatalogService is a mock of DeviceDefinitionCatalogService interface. +type MockDeviceDefinitionCatalogService struct { + ctrl *gomock.Controller + recorder *MockDeviceDefinitionCatalogServiceMockRecorder + isgomock struct{} +} + +// MockDeviceDefinitionCatalogServiceMockRecorder is the mock recorder for MockDeviceDefinitionCatalogService. +type MockDeviceDefinitionCatalogServiceMockRecorder struct { + mock *MockDeviceDefinitionCatalogService +} + +// NewMockDeviceDefinitionCatalogService creates a new mock instance. +func NewMockDeviceDefinitionCatalogService(ctrl *gomock.Controller) *MockDeviceDefinitionCatalogService { + mock := &MockDeviceDefinitionCatalogService{ctrl: ctrl} + mock.recorder = &MockDeviceDefinitionCatalogServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDeviceDefinitionCatalogService) EXPECT() *MockDeviceDefinitionCatalogServiceMockRecorder { + return m.recorder +} + +// Create mocks base method. +func (m *MockDeviceDefinitionCatalogService) Create(ctx context.Context, manufacturerName string, dd models.DeviceDefinitionTablelandModel) (*models.Template, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", ctx, manufacturerName, dd) + ret0, _ := ret[0].(*models.Template) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Create indicates an expected call of Create. +func (mr *MockDeviceDefinitionCatalogServiceMockRecorder) Create(ctx, manufacturerName, dd any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockDeviceDefinitionCatalogService)(nil).Create), ctx, manufacturerName, dd) +} + +// Delete mocks base method. +func (m *MockDeviceDefinitionCatalogService) Delete(ctx context.Context, manufacturerName, id string) (*string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, manufacturerName, id) + ret0, _ := ret[0].(*string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Delete indicates an expected call of Delete. +func (mr *MockDeviceDefinitionCatalogServiceMockRecorder) Delete(ctx, manufacturerName, id any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockDeviceDefinitionCatalogService)(nil).Delete), ctx, manufacturerName, id) +} + +// GetDefinition mocks base method. +func (m *MockDeviceDefinitionCatalogService) GetDefinition(ctx context.Context, manufacturerID *big.Int, ID string) (*models.DeviceDefinitionTablelandModel, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDefinition", ctx, manufacturerID, ID) + ret0, _ := ret[0].(*models.DeviceDefinitionTablelandModel) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDefinition indicates an expected call of GetDefinition. +func (mr *MockDeviceDefinitionCatalogServiceMockRecorder) GetDefinition(ctx, manufacturerID, ID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDefinition", reflect.TypeOf((*MockDeviceDefinitionCatalogService)(nil).GetDefinition), ctx, manufacturerID, ID) +} + +// GetDeviceDefinitionByID mocks base method. +func (m *MockDeviceDefinitionCatalogService) GetDeviceDefinitionByID(ctx context.Context, manufacturerID *big.Int, ID string) (*models.DeviceDefinitionTablelandModel, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDeviceDefinitionByID", ctx, manufacturerID, ID) + ret0, _ := ret[0].(*models.DeviceDefinitionTablelandModel) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDeviceDefinitionByID indicates an expected call of GetDeviceDefinitionByID. +func (mr *MockDeviceDefinitionCatalogServiceMockRecorder) GetDeviceDefinitionByID(ctx, manufacturerID, ID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeviceDefinitionByID", reflect.TypeOf((*MockDeviceDefinitionCatalogService)(nil).GetDeviceDefinitionByID), ctx, manufacturerID, ID) +} + +// GetManufacturer mocks base method. +func (m *MockDeviceDefinitionCatalogService) GetManufacturer(manufacturerSlug string) (*models.Manufacturer, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetManufacturer", manufacturerSlug) + ret0, _ := ret[0].(*models.Manufacturer) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetManufacturer indicates an expected call of GetManufacturer. +func (mr *MockDeviceDefinitionCatalogServiceMockRecorder) GetManufacturer(manufacturerSlug any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetManufacturer", reflect.TypeOf((*MockDeviceDefinitionCatalogService)(nil).GetManufacturer), manufacturerSlug) +} + +// GetManufacturerNameByID mocks base method. +func (m *MockDeviceDefinitionCatalogService) GetManufacturerNameByID(ctx context.Context, manufacturerID *big.Int) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetManufacturerNameByID", ctx, manufacturerID) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetManufacturerNameByID indicates an expected call of GetManufacturerNameByID. +func (mr *MockDeviceDefinitionCatalogServiceMockRecorder) GetManufacturerNameByID(ctx, manufacturerID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetManufacturerNameByID", reflect.TypeOf((*MockDeviceDefinitionCatalogService)(nil).GetManufacturerNameByID), ctx, manufacturerID) +} + +// GetTemplateByID mocks base method. +func (m *MockDeviceDefinitionCatalogService) GetTemplateByID(ctx context.Context, ID string) (*models.Template, *big.Int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateByID", ctx, ID) + ret0, _ := ret[0].(*models.Template) + ret1, _ := ret[1].(*big.Int) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// GetTemplateByID indicates an expected call of GetTemplateByID. +func (mr *MockDeviceDefinitionCatalogServiceMockRecorder) GetTemplateByID(ctx, ID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateByID", reflect.TypeOf((*MockDeviceDefinitionCatalogService)(nil).GetTemplateByID), ctx, ID) +} + +// GetTemplateByIDFresh mocks base method. +func (m *MockDeviceDefinitionCatalogService) GetTemplateByIDFresh(ctx context.Context, ID string) (*models.Template, *big.Int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateByIDFresh", ctx, ID) + ret0, _ := ret[0].(*models.Template) + ret1, _ := ret[1].(*big.Int) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// GetTemplateByIDFresh indicates an expected call of GetTemplateByIDFresh. +func (mr *MockDeviceDefinitionCatalogServiceMockRecorder) GetTemplateByIDFresh(ctx, ID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateByIDFresh", reflect.TypeOf((*MockDeviceDefinitionCatalogService)(nil).GetTemplateByIDFresh), ctx, ID) +} diff --git a/internal/infrastructure/gateways/mocks/device_definition_on_chain_service_mock.go b/internal/infrastructure/gateways/mocks/device_definition_on_chain_service_mock.go deleted file mode 100644 index 5d600c41..00000000 --- a/internal/infrastructure/gateways/mocks/device_definition_on_chain_service_mock.go +++ /dev/null @@ -1,196 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: device_definition_on_chain_service.go -// -// Generated by this command: -// -// mockgen -source device_definition_on_chain_service.go -destination mocks/device_definition_on_chain_service_mock.go -package mocks -// - -// Package mocks is a generated GoMock package. -package mocks - -import ( - context "context" - big "math/big" - reflect "reflect" - - contracts "github.com/DIMO-Network/device-definitions-api/internal/contracts" - models "github.com/DIMO-Network/device-definitions-api/internal/core/models" - types "github.com/aarondl/sqlboiler/v4/types" - gomock "go.uber.org/mock/gomock" -) - -// MockDeviceDefinitionOnChainService is a mock of DeviceDefinitionOnChainService interface. -type MockDeviceDefinitionOnChainService struct { - ctrl *gomock.Controller - recorder *MockDeviceDefinitionOnChainServiceMockRecorder - isgomock struct{} -} - -// MockDeviceDefinitionOnChainServiceMockRecorder is the mock recorder for MockDeviceDefinitionOnChainService. -type MockDeviceDefinitionOnChainServiceMockRecorder struct { - mock *MockDeviceDefinitionOnChainService -} - -// NewMockDeviceDefinitionOnChainService creates a new mock instance. -func NewMockDeviceDefinitionOnChainService(ctrl *gomock.Controller) *MockDeviceDefinitionOnChainService { - mock := &MockDeviceDefinitionOnChainService{ctrl: ctrl} - mock.recorder = &MockDeviceDefinitionOnChainServiceMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockDeviceDefinitionOnChainService) EXPECT() *MockDeviceDefinitionOnChainServiceMockRecorder { - return m.recorder -} - -// Create mocks base method. -func (m *MockDeviceDefinitionOnChainService) Create(ctx context.Context, manufacturerName string, dd models.DeviceDefinitionTablelandModel) (*string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Create", ctx, manufacturerName, dd) - ret0, _ := ret[0].(*string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Create indicates an expected call of Create. -func (mr *MockDeviceDefinitionOnChainServiceMockRecorder) Create(ctx, manufacturerName, dd any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockDeviceDefinitionOnChainService)(nil).Create), ctx, manufacturerName, dd) -} - -// Delete mocks base method. -func (m *MockDeviceDefinitionOnChainService) Delete(ctx context.Context, manufacturerName, id string) (*string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Delete", ctx, manufacturerName, id) - ret0, _ := ret[0].(*string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Delete indicates an expected call of Delete. -func (mr *MockDeviceDefinitionOnChainServiceMockRecorder) Delete(ctx, manufacturerName, id any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockDeviceDefinitionOnChainService)(nil).Delete), ctx, manufacturerName, id) -} - -// GetDefinitionByID mocks base method. -func (m *MockDeviceDefinitionOnChainService) GetDefinitionByID(ctx context.Context, ID string) (*models.DeviceDefinitionTablelandModel, *big.Int, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetDefinitionByID", ctx, ID) - ret0, _ := ret[0].(*models.DeviceDefinitionTablelandModel) - ret1, _ := ret[1].(*big.Int) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 -} - -// GetDefinitionByID indicates an expected call of GetDefinitionByID. -func (mr *MockDeviceDefinitionOnChainServiceMockRecorder) GetDefinitionByID(ctx, ID any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDefinitionByID", reflect.TypeOf((*MockDeviceDefinitionOnChainService)(nil).GetDefinitionByID), ctx, ID) -} - -// GetDefinitionTableland mocks base method. -func (m *MockDeviceDefinitionOnChainService) GetDefinitionTableland(ctx context.Context, manufacturerID *big.Int, ID string) (*models.DeviceDefinitionTablelandModel, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetDefinitionTableland", ctx, manufacturerID, ID) - ret0, _ := ret[0].(*models.DeviceDefinitionTablelandModel) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetDefinitionTableland indicates an expected call of GetDefinitionTableland. -func (mr *MockDeviceDefinitionOnChainServiceMockRecorder) GetDefinitionTableland(ctx, manufacturerID, ID any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDefinitionTableland", reflect.TypeOf((*MockDeviceDefinitionOnChainService)(nil).GetDefinitionTableland), ctx, manufacturerID, ID) -} - -// GetDeviceDefinitionByID mocks base method. -func (m *MockDeviceDefinitionOnChainService) GetDeviceDefinitionByID(ctx context.Context, manufacturerID *big.Int, ID string) (*models.DeviceDefinitionTablelandModel, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetDeviceDefinitionByID", ctx, manufacturerID, ID) - ret0, _ := ret[0].(*models.DeviceDefinitionTablelandModel) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetDeviceDefinitionByID indicates an expected call of GetDeviceDefinitionByID. -func (mr *MockDeviceDefinitionOnChainServiceMockRecorder) GetDeviceDefinitionByID(ctx, manufacturerID, ID any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeviceDefinitionByID", reflect.TypeOf((*MockDeviceDefinitionOnChainService)(nil).GetDeviceDefinitionByID), ctx, manufacturerID, ID) -} - -// GetDeviceDefinitions mocks base method. -func (m *MockDeviceDefinitionOnChainService) GetDeviceDefinitions(ctx context.Context, manufacturerID types.NullDecimal, ID, model string, year int, pageIndex, pageSize int32) ([]models.DeviceDefinitionTablelandModel, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetDeviceDefinitions", ctx, manufacturerID, ID, model, year, pageIndex, pageSize) - ret0, _ := ret[0].([]models.DeviceDefinitionTablelandModel) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetDeviceDefinitions indicates an expected call of GetDeviceDefinitions. -func (mr *MockDeviceDefinitionOnChainServiceMockRecorder) GetDeviceDefinitions(ctx, manufacturerID, ID, model, year, pageIndex, pageSize any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeviceDefinitions", reflect.TypeOf((*MockDeviceDefinitionOnChainService)(nil).GetDeviceDefinitions), ctx, manufacturerID, ID, model, year, pageIndex, pageSize) -} - -// GetManufacturer mocks base method. -func (m *MockDeviceDefinitionOnChainService) GetManufacturer(manufacturerSlug string) (*models.Manufacturer, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetManufacturer", manufacturerSlug) - ret0, _ := ret[0].(*models.Manufacturer) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetManufacturer indicates an expected call of GetManufacturer. -func (mr *MockDeviceDefinitionOnChainServiceMockRecorder) GetManufacturer(manufacturerSlug any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetManufacturer", reflect.TypeOf((*MockDeviceDefinitionOnChainService)(nil).GetManufacturer), manufacturerSlug) -} - -// GetManufacturerNameByID mocks base method. -func (m *MockDeviceDefinitionOnChainService) GetManufacturerNameByID(ctx context.Context, manufacturerID *big.Int) (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetManufacturerNameByID", ctx, manufacturerID) - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetManufacturerNameByID indicates an expected call of GetManufacturerNameByID. -func (mr *MockDeviceDefinitionOnChainServiceMockRecorder) GetManufacturerNameByID(ctx, manufacturerID any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetManufacturerNameByID", reflect.TypeOf((*MockDeviceDefinitionOnChainService)(nil).GetManufacturerNameByID), ctx, manufacturerID) -} - -// QueryDefinitionsCustom mocks base method. -func (m *MockDeviceDefinitionOnChainService) QueryDefinitionsCustom(ctx context.Context, manufacturerID int, whereClause string, pageIndex int) ([]models.DeviceDefinitionTablelandModel, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "QueryDefinitionsCustom", ctx, manufacturerID, whereClause, pageIndex) - ret0, _ := ret[0].([]models.DeviceDefinitionTablelandModel) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// QueryDefinitionsCustom indicates an expected call of QueryDefinitionsCustom. -func (mr *MockDeviceDefinitionOnChainServiceMockRecorder) QueryDefinitionsCustom(ctx, manufacturerID, whereClause, pageIndex any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryDefinitionsCustom", reflect.TypeOf((*MockDeviceDefinitionOnChainService)(nil).QueryDefinitionsCustom), ctx, manufacturerID, whereClause, pageIndex) -} - -// Update mocks base method. -func (m *MockDeviceDefinitionOnChainService) Update(ctx context.Context, manufacturerName string, input contracts.DeviceDefinitionUpdateInput) (*string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Update", ctx, manufacturerName, input) - ret0, _ := ret[0].(*string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Update indicates an expected call of Update. -func (mr *MockDeviceDefinitionOnChainServiceMockRecorder) Update(ctx, manufacturerName, input any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockDeviceDefinitionOnChainService)(nil).Update), ctx, manufacturerName, input) -} diff --git a/internal/infrastructure/gateways/mocks/fuel_api_service_mock.go b/internal/infrastructure/gateways/mocks/fuel_api_service_mock.go index b7201d10..c5d594b2 100644 --- a/internal/infrastructure/gateways/mocks/fuel_api_service_mock.go +++ b/internal/infrastructure/gateways/mocks/fuel_api_service_mock.go @@ -5,6 +5,7 @@ // // mockgen -source fuel_api_service.go -destination mocks/fuel_api_service_mock.go -package mocks // + // Package mocks is a generated GoMock package. package mocks @@ -19,6 +20,7 @@ import ( type MockFuelAPIService struct { ctrl *gomock.Controller recorder *MockFuelAPIServiceMockRecorder + isgomock struct{} } // MockFuelAPIServiceMockRecorder is the mock recorder for MockFuelAPIService. diff --git a/internal/infrastructure/metrics/prometheus_metric_service.go b/internal/infrastructure/metrics/prometheus_metric_service.go index 449fa29d..c83581b8 100644 --- a/internal/infrastructure/metrics/prometheus_metric_service.go +++ b/internal/infrastructure/metrics/prometheus_metric_service.go @@ -33,6 +33,18 @@ var ( Help: "Total execution", }, []string{"method"}) + // TrimMatchQuality counts VIN decodes by how well the decode narrowed its + // template to a single trim, broken down by which provider decoded it. + // Trim selectors are keyed on manufacturerCode, which only drivly + // supplies, so the share of decodes landing on "model-only" -- and which + // sources they come from -- is the measurement that says whether trim + // matching is actually reaching production traffic. Without it the answer + // is only inferable from the response of one decode at a time. + TrimMatchQuality = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: serviceName + "vin_trim_match_quality_total", + Help: "VIN decodes by trim match quality (exact, ambiguous, model-only) and decode source", + }, []string{"quality", "source"}) + GRPCRequestCount = promauto.NewCounterVec( prometheus.CounterOpts{ Name: serviceName + "grpc_request_count", diff --git a/internal/infrastructure/search/typesense_search_service.go b/internal/infrastructure/search/typesense_search_service.go index ebc35ab6..fa433514 100644 --- a/internal/infrastructure/search/typesense_search_service.go +++ b/internal/infrastructure/search/typesense_search_service.go @@ -62,13 +62,18 @@ func (t typesenseAPIService) GetDeviceDefinitions(ctx context.Context, search, m filters.WriteString(fmt.Sprintf("year:=%d", year)) } + // The worker indexes one document per trim. Grouping on definition_id + // with a limit of one keeps the endpoint's contract of one item per + // definition; found then counts groups, so pagination stays per definition. searchParameters := &api.SearchCollectionParams{ - Q: search, - QueryBy: "name", - FacetBy: pointer.String("make,model,year"), - Page: pointer.Int(page), - PerPage: pointer.Int(pageSize), - FilterBy: pointer.String(filters.String()), + Q: search, + QueryBy: "name", + FacetBy: pointer.String("make,model,year"), + Page: pointer.Int(page), + PerPage: pointer.Int(pageSize), + FilterBy: pointer.String(filters.String()), + GroupBy: pointer.String("definition_id"), + GroupLimit: pointer.Int(1), } result, err := t.client.Collection(t.settings.SearchServiceIndexName).Documents().Search(ctx, searchParameters) @@ -82,10 +87,16 @@ func (t typesenseAPIService) GetDeviceDefinitions(ctx context.Context, search, m func (t typesenseAPIService) Autocomplete(ctx context.Context, search string) (*api.SearchResult, error) { + // Grouped on definition_id for the same reason GetDeviceDefinitions is: the + // worker indexes one document per trim, so an ungrouped top-10 for "camry" + // comes back as ten trims of a single Camry rather than ten Camrys. An + // autocomplete list of ten identical labels is worse than useless. searchParameters := &api.SearchCollectionParams{ Q: search, QueryBy: "name", - Limit: pointer.Int(10), + PerPage: pointer.Int(10), + GroupBy: pointer.String("definition_id"), + GroupLimit: pointer.Int(1), HighlightFullFields: pointer.String("name"), HighlightAffixNumTokens: pointer.Int(2), } diff --git a/internal/infrastructure/search/typesense_search_service_test.go b/internal/infrastructure/search/typesense_search_service_test.go new file mode 100644 index 00000000..143ee452 --- /dev/null +++ b/internal/infrastructure/search/typesense_search_service_test.go @@ -0,0 +1,50 @@ +package search + +import ( + "context" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/DIMO-Network/device-definitions-api/internal/config" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// The definitions-worker indexes one document per trim. Without group_by the +// endpoint would return a definition once per trim, and the handler's +// one-item-per-definition contract depends on the query being grouped -- which +// is only observable on the wire. +func TestGetDeviceDefinitionsGroupsByDefinitionID(t *testing.T) { + var gotPath string + var gotQuery url.Values + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + gotPath = r.URL.Path + gotQuery = r.URL.Query() + w.Header().Set("content-type", "application/json") + _, _ = w.Write([]byte(`{"found": 0, "grouped_hits": [], "facet_counts": []}`)) + })) + defer srv.Close() + + apiURL, err := url.Parse(srv.URL) + require.NoError(t, err) + logger := zerolog.Nop() + svc := NewTypesenseAPIService(&config.Settings{ + SearchServiceAPIURL: *apiURL, + SearchServiceAPIKey: "test-key", + SearchServiceIndexName: "definitions_prod", + }, &logger) + + result, err := svc.GetDeviceDefinitions(context.Background(), "camry", "toyota", "", 2020, 1, 20) + require.NoError(t, err) + require.NotNil(t, result) + + assert.Equal(t, "/collections/definitions_prod/documents/search", gotPath) + assert.Equal(t, "definition_id", gotQuery.Get("group_by")) + assert.Equal(t, "1", gotQuery.Get("group_limit")) + assert.Equal(t, "make,model,year", gotQuery.Get("facet_by")) + assert.Equal(t, "name", gotQuery.Get("query_by")) + assert.Equal(t, "make_slug:=toyota && year:=2020", gotQuery.Get("filter_by")) +} diff --git a/internal/infrastructure/sender/kms.go b/internal/infrastructure/sender/kms.go deleted file mode 100644 index 91f88c69..00000000 --- a/internal/infrastructure/sender/kms.go +++ /dev/null @@ -1,135 +0,0 @@ -package sender - -import ( - "context" - "crypto/x509/pkix" - "encoding/asn1" - "fmt" - "math/big" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/kms" - "github.com/aws/aws-sdk-go-v2/service/kms/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/secp256k1" - "golang.org/x/exp/slices" -) - -var secp256k1N = crypto.S256().Params().N -var secp256k1HalfN = new(big.Int).Div(secp256k1N, big.NewInt(2)) - -type kmsSender struct { - keyID string - pub []byte - address common.Address - client *kms.Client -} - -func (s *kmsSender) Address() common.Address { - return s.address -} - -func (s *kmsSender) Sign(ctx context.Context, hash common.Hash) ([]byte, error) { - signInput := &kms.SignInput{ - KeyId: aws.String(s.keyID), - SigningAlgorithm: types.SigningAlgorithmSpecEcdsaSha256, - MessageType: types.MessageTypeDigest, - Message: hash[:], - } - - out, err := s.client.Sign(ctx, signInput) - if err != nil { - return nil, err - } - - sig := new(ecdsaSigFields) - _, err = asn1.Unmarshal(out.Signature, sig) - if err != nil { - return nil, err - } - - sigR, sigS := sig.R.Bytes, sig.S.Bytes - - // Correct S, if necessary, so that it's in the lower half of the group. - sigSNum := new(big.Int).SetBytes(sigS) - if sigSNum.Cmp(secp256k1HalfN) > 0 { - sigS = new(big.Int).Sub(secp256k1N, sigSNum).Bytes() - } - - // Determine whether V ought to be 0 or 1. - sigRS := append(fixLen(sigR), fixLen(sigS)...) - sigRSV := append(sigRS, 0) - - recPub, err := crypto.Ecrecover(hash[:], sigRSV) - if err != nil { - return nil, err - } - - if slices.Equal(recPub, s.pub) { - return sigRSV, nil - } - - sigRSV = append(sigRS, 1) - recPub, err = crypto.Ecrecover(hash[:], sigRSV) - if err != nil { - return nil, err - } - - if slices.Equal(recPub, s.pub) { - return sigRSV, nil - } - - return nil, fmt.Errorf("couldn't choose a working V from the returned R and S") -} - -func fixLen(in []byte) []byte { - outStart := 0 - inLen := len(in) - inStart := 0 - - if inLen > 32 { - inStart = inLen - 32 - } else if inLen < 32 { - outStart = 32 - inLen - } - - out := make([]byte, common.HashLength) - copy(out[outStart:], in[inStart:]) - return out -} - -type publicKeyFields struct { - Algorithm pkix.AlgorithmIdentifier - SubjectPublicKey asn1.BitString -} - -type ecdsaSigFields struct { - R asn1.RawValue - S asn1.RawValue -} - -func FromKMS(ctx context.Context, client *kms.Client, keyID string) (Sender, error) { - pubResp, err := client.GetPublicKey(ctx, &kms.GetPublicKeyInput{KeyId: aws.String(keyID)}) - if err != nil { - return nil, err - } - - cert := new(publicKeyFields) - - _, err = asn1.Unmarshal(pubResp.PublicKey, cert) - if err != nil { - return nil, err - } - - pub, err := crypto.UnmarshalPubkey(cert.SubjectPublicKey.Bytes) - if err != nil { - return nil, err - } - - pubBytes := secp256k1.S256().Marshal(pub.X, pub.Y) - - addr := crypto.PubkeyToAddress(*pub) - - return &kmsSender{keyID: keyID, pub: pubBytes, address: addr, client: client}, nil -} diff --git a/internal/infrastructure/sender/privatekey.go b/internal/infrastructure/sender/privatekey.go deleted file mode 100644 index 390db990..00000000 --- a/internal/infrastructure/sender/privatekey.go +++ /dev/null @@ -1,34 +0,0 @@ -package sender - -import ( - "context" - "crypto/ecdsa" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" -) - -type privateKeySender struct { - privateKey *ecdsa.PrivateKey - address common.Address -} - -func (a *privateKeySender) Address() common.Address { - return a.address -} - -func (a *privateKeySender) Sign(_ context.Context, hash common.Hash) ([]byte, error) { - return crypto.Sign(hash[:], a.privateKey) -} - -func FromKey(hexPriv string) (Sender, error) { - privBytes := common.FromHex(hexPriv) - priv, err := crypto.ToECDSA(privBytes) - if err != nil { - return nil, err - } - - address := crypto.PubkeyToAddress(priv.PublicKey) - - return &privateKeySender{privateKey: priv, address: address}, nil -} diff --git a/internal/infrastructure/sender/sender.go b/internal/infrastructure/sender/sender.go deleted file mode 100644 index e6821b33..00000000 --- a/internal/infrastructure/sender/sender.go +++ /dev/null @@ -1,12 +0,0 @@ -package sender - -import ( - "context" - - "github.com/ethereum/go-ethereum/common" -) - -type Sender interface { - Address() common.Address - Sign(ctx context.Context, hash common.Hash) ([]byte, error) -} diff --git a/pkg/grpc/decoder.pb.go b/pkg/grpc/decoder.pb.go index cbcb6b2d..6fa89442 100644 --- a/pkg/grpc/decoder.pb.go +++ b/pkg/grpc/decoder.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 -// protoc v5.26.1 +// protoc-gen-go v1.30.0 +// protoc v7.36.0 // source: pkg/grpc/decoder.proto package grpc @@ -108,6 +108,27 @@ type DecodeVinResponse struct { DefinitionId string `protobuf:"bytes,9,opt,name=definition_id,json=definitionId,proto3" json:"definition_id,omitempty"` Model string `protobuf:"bytes,10,opt,name=model,proto3" json:"model,omitempty"` Manufacturer string `protobuf:"bytes,11,opt,name=manufacturer,proto3" json:"manufacturer,omitempty"` + // Trim the VIN narrowed to. Empty when match_quality is not "exact". + Trim string `protobuf:"bytes,12,opt,name=trim,proto3" json:"trim,omitempty"` + // Version of the template this answer came from, so a caller can pin, + // cache and reproduce a decode. + TemplateVersion int32 `protobuf:"varint,13,opt,name=template_version,json=templateVersion,proto3" json:"template_version,omitempty"` + // "exact", "ambiguous", or "model-only" when the trim matcher ran. + // Empty means it did not run at all: there is no template for this + // definition yet, or the template could not be read. That is deliberately + // distinct from "model-only", which asserts that a real template was read + // and no trim in it matched. + MatchQuality string `protobuf:"bytes,14,opt,name=match_quality,json=matchQuality,proto3" json:"match_quality,omitempty"` + // Trim names still in contention when match_quality is "ambiguous". + MatchCandidates []string `protobuf:"bytes,15,rep,name=match_candidates,json=matchCandidates,proto3" json:"match_candidates,omitempty"` + // Which selectors fired: any of "manufacturerCode", "styleName", + // "vinPattern". Empty unless match_quality is "exact". + MatchBy []string `protobuf:"bytes,16,rep,name=match_by,json=matchBy,proto3" json:"match_by,omitempty"` + // Effective hardware template: the matched trim's override if it has one, + // otherwise the template's. Resolved here so callers never reimplement the + // fallback. On an ambiguous or model-only match no trim was chosen, so this + // is the template's value. + HardwareTemplateId string `protobuf:"bytes,17,opt,name=hardware_template_id,json=hardwareTemplateId,proto3" json:"hardware_template_id,omitempty"` } func (x *DecodeVinResponse) Reset() { @@ -206,6 +227,48 @@ func (x *DecodeVinResponse) GetManufacturer() string { return "" } +func (x *DecodeVinResponse) GetTrim() string { + if x != nil { + return x.Trim + } + return "" +} + +func (x *DecodeVinResponse) GetTemplateVersion() int32 { + if x != nil { + return x.TemplateVersion + } + return 0 +} + +func (x *DecodeVinResponse) GetMatchQuality() string { + if x != nil { + return x.MatchQuality + } + return "" +} + +func (x *DecodeVinResponse) GetMatchCandidates() []string { + if x != nil { + return x.MatchCandidates + } + return nil +} + +func (x *DecodeVinResponse) GetMatchBy() []string { + if x != nil { + return x.MatchBy + } + return nil +} + +func (x *DecodeVinResponse) GetHardwareTemplateId() string { + if x != nil { + return x.HardwareTemplateId + } + return "" +} + type UpsertDecodingRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -275,7 +338,7 @@ var file_pkg_grpc_decoder_proto_rawDesc = []byte{ 0x6e, 0x6f, 0x77, 0x6e, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x5f, 0x79, 0x65, 0x61, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x09, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x59, 0x65, 0x61, 0x72, 0x22, 0xb2, 0x02, 0x0a, 0x11, + 0x52, 0x09, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x59, 0x65, 0x61, 0x72, 0x22, 0x8e, 0x04, 0x0a, 0x11, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x56, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x61, 0x6b, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0c, 0x64, @@ -295,26 +358,40 @@ var file_pkg_grpc_decoder_proto_rawDesc = []byte{ 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, - 0x22, 0x5b, 0x0a, 0x15, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x69, - 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x76, 0x69, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x76, 0x69, 0x6e, 0x12, 0x30, 0x0a, 0x14, 0x74, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x74, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x32, 0x98, 0x01, - 0x0a, 0x11, 0x56, 0x69, 0x6e, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x3c, 0x0a, 0x09, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x56, 0x69, 0x6e, - 0x12, 0x16, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x56, 0x69, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, - 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x56, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x45, 0x0a, 0x0e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x44, 0x65, 0x63, 0x6f, 0x64, - 0x69, 0x6e, 0x67, 0x12, 0x1b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, - 0x74, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x39, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x49, 0x4d, 0x4f, 0x2d, 0x4e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2d, 0x64, 0x65, 0x66, 0x69, 0x6e, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2d, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, - 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x12, 0x12, 0x0a, 0x04, 0x74, 0x72, 0x69, 0x6d, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x74, 0x72, 0x69, 0x6d, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, + 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x23, 0x0a, 0x0d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x71, 0x75, 0x61, 0x6c, 0x69, 0x74, 0x79, + 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x51, 0x75, 0x61, + 0x6c, 0x69, 0x74, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x63, 0x61, + 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, + 0x6d, 0x61, 0x74, 0x63, 0x68, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, + 0x19, 0x0a, 0x08, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x62, 0x79, 0x18, 0x10, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x07, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, 0x79, 0x12, 0x30, 0x0a, 0x14, 0x68, 0x61, + 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, + 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x64, 0x22, 0x5b, 0x0a, 0x15, + 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x76, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x76, 0x69, 0x6e, 0x12, 0x30, 0x0a, 0x14, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x65, 0x66, + 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x32, 0x98, 0x01, 0x0a, 0x11, 0x56, 0x69, + 0x6e, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x3c, 0x0a, 0x09, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x56, 0x69, 0x6e, 0x12, 0x16, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x56, 0x69, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x63, 0x6f, + 0x64, 0x65, 0x56, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, + 0x0e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x12, + 0x1b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x44, 0x65, 0x63, + 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x42, 0x39, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x44, 0x49, 0x4d, 0x4f, 0x2d, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, + 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2d, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2d, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/pkg/grpc/decoder.proto b/pkg/grpc/decoder.proto index 12bd6f88..0a5d2168 100644 --- a/pkg/grpc/decoder.proto +++ b/pkg/grpc/decoder.proto @@ -24,6 +24,27 @@ message DecodeVinResponse { string definition_id = 9; string model = 10; string manufacturer = 11; + // Trim the VIN narrowed to. Empty when match_quality is not "exact". + string trim = 12; + // Version of the template this answer came from, so a caller can pin, + // cache and reproduce a decode. + int32 template_version = 13; + // "exact", "ambiguous", or "model-only" when the trim matcher ran. + // Empty means it did not run at all: there is no template for this + // definition yet, or the template could not be read. That is deliberately + // distinct from "model-only", which asserts that a real template was read + // and no trim in it matched. + string match_quality = 14; + // Trim names still in contention when match_quality is "ambiguous". + repeated string match_candidates = 15; + // Which selectors fired: any of "manufacturerCode", "styleName", + // "vinPattern". Empty unless match_quality is "exact". + repeated string match_by = 16; + // Effective hardware template: the matched trim's override if it has one, + // otherwise the template's. Resolved here so callers never reimplement the + // fallback. On an ambiguous or model-only match no trim was chosen, so this + // is the template's value. + string hardware_template_id = 17; } message UpsertDecodingRequest { diff --git a/pkg/grpc/decoder_grpc.pb.go b/pkg/grpc/decoder_grpc.pb.go index 0f2df787..52906245 100644 --- a/pkg/grpc/decoder_grpc.pb.go +++ b/pkg/grpc/decoder_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v5.26.1 +// - protoc v7.36.0 // source: pkg/grpc/decoder.proto package grpc diff --git a/pkg/grpc/device_definition.pb.go b/pkg/grpc/device_definition.pb.go index e97db9ed..aee5ca53 100644 --- a/pkg/grpc/device_definition.pb.go +++ b/pkg/grpc/device_definition.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.26.1 +// protoc v7.36.1 // source: pkg/grpc/device_definition.proto package grpc @@ -10,7 +10,6 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" emptypb "google.golang.org/protobuf/types/known/emptypb" - timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" ) @@ -211,61 +210,6 @@ func (x *GetDevicesMMYItemResponse) GetNameSlug() string { return "" } -type ExternalID struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Vendor string `protobuf:"bytes,1,opt,name=vendor,proto3" json:"vendor,omitempty"` - Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` -} - -func (x *ExternalID) Reset() { - *x = ExternalID{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ExternalID) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ExternalID) ProtoMessage() {} - -func (x *ExternalID) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ExternalID.ProtoReflect.Descriptor instead. -func (*ExternalID) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{3} -} - -func (x *ExternalID) GetVendor() string { - if x != nil { - return x.Vendor - } - return "" -} - -func (x *ExternalID) GetId() string { - if x != nil { - return x.Id - } - return "" -} - type DeviceTypeAttribute struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -284,7 +228,7 @@ type DeviceTypeAttribute struct { func (x *DeviceTypeAttribute) Reset() { *x = DeviceTypeAttribute{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[4] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -297,7 +241,7 @@ func (x *DeviceTypeAttribute) String() string { func (*DeviceTypeAttribute) ProtoMessage() {} func (x *DeviceTypeAttribute) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[4] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -310,7 +254,7 @@ func (x *DeviceTypeAttribute) ProtoReflect() protoreflect.Message { // Deprecated: Use DeviceTypeAttribute.ProtoReflect.Descriptor instead. func (*DeviceTypeAttribute) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{4} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{3} } func (x *DeviceTypeAttribute) GetName() string { @@ -369,61 +313,6 @@ func (x *DeviceTypeAttribute) GetDescription() string { return "" } -type DeviceTypeAttributeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` -} - -func (x *DeviceTypeAttributeRequest) Reset() { - *x = DeviceTypeAttributeRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *DeviceTypeAttributeRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DeviceTypeAttributeRequest) ProtoMessage() {} - -func (x *DeviceTypeAttributeRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DeviceTypeAttributeRequest.ProtoReflect.Descriptor instead. -func (*DeviceTypeAttributeRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{5} -} - -func (x *DeviceTypeAttributeRequest) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *DeviceTypeAttributeRequest) GetValue() string { - if x != nil { - return x.Value - } - return "" -} - type DeviceType struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -441,7 +330,7 @@ type DeviceType struct { func (x *DeviceType) Reset() { *x = DeviceType{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[6] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -454,7 +343,7 @@ func (x *DeviceType) String() string { func (*DeviceType) ProtoMessage() {} func (x *DeviceType) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[6] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -467,7 +356,7 @@ func (x *DeviceType) ProtoReflect() protoreflect.Message { // Deprecated: Use DeviceType.ProtoReflect.Descriptor instead. func (*DeviceType) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{6} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{4} } func (x *DeviceType) GetType() string { @@ -540,7 +429,7 @@ type DeviceStyle struct { func (x *DeviceStyle) Reset() { *x = DeviceStyle{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[7] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -553,7 +442,7 @@ func (x *DeviceStyle) String() string { func (*DeviceStyle) ProtoMessage() {} func (x *DeviceStyle) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[7] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -566,7 +455,7 @@ func (x *DeviceStyle) ProtoReflect() protoreflect.Message { // Deprecated: Use DeviceStyle.ProtoReflect.Descriptor instead. func (*DeviceStyle) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{7} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{5} } func (x *DeviceStyle) GetId() string { @@ -648,7 +537,7 @@ type GetDeviceDefinitionByMMYRequest struct { func (x *GetDeviceDefinitionByMMYRequest) Reset() { *x = GetDeviceDefinitionByMMYRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[8] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -661,7 +550,7 @@ func (x *GetDeviceDefinitionByMMYRequest) String() string { func (*GetDeviceDefinitionByMMYRequest) ProtoMessage() {} func (x *GetDeviceDefinitionByMMYRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[8] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -674,7 +563,7 @@ func (x *GetDeviceDefinitionByMMYRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDeviceDefinitionByMMYRequest.ProtoReflect.Descriptor instead. func (*GetDeviceDefinitionByMMYRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{8} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{6} } func (x *GetDeviceDefinitionByMMYRequest) GetMake() string { @@ -716,7 +605,7 @@ type GetIntegrationResponse struct { func (x *GetIntegrationResponse) Reset() { *x = GetIntegrationResponse{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[9] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -729,7 +618,7 @@ func (x *GetIntegrationResponse) String() string { func (*GetIntegrationResponse) ProtoMessage() {} func (x *GetIntegrationResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[9] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -742,7 +631,7 @@ func (x *GetIntegrationResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetIntegrationResponse.ProtoReflect.Descriptor instead. func (*GetIntegrationResponse) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{9} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{7} } func (x *GetIntegrationResponse) GetIntegrations() []*Integration { @@ -773,7 +662,7 @@ type Integration struct { func (x *Integration) Reset() { *x = Integration{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[10] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -786,7 +675,7 @@ func (x *Integration) String() string { func (*Integration) ProtoMessage() {} func (x *Integration) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[10] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -799,7 +688,7 @@ func (x *Integration) ProtoReflect() protoreflect.Message { // Deprecated: Use Integration.ProtoReflect.Descriptor instead. func (*Integration) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{10} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{8} } func (x *Integration) GetId() string { @@ -872,38 +761,31 @@ func (x *Integration) GetManufacturerTokenId() uint64 { return 0 } -type CreateDeviceDefinitionRequest struct { +type BaseResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Make string `protobuf:"bytes,1,opt,name=make,proto3" json:"make,omitempty"` - Model string `protobuf:"bytes,2,opt,name=model,proto3" json:"model,omitempty"` - Year int32 `protobuf:"varint,3,opt,name=year,proto3" json:"year,omitempty"` - Source string `protobuf:"bytes,4,opt,name=source,proto3" json:"source,omitempty"` - DeviceTypeId string `protobuf:"bytes,5,opt,name=device_type_id,json=deviceTypeId,proto3" json:"device_type_id,omitempty"` - DeviceAttributes []*DeviceTypeAttributeRequest `protobuf:"bytes,6,rep,name=device_attributes,json=deviceAttributes,proto3" json:"device_attributes,omitempty"` - HardwareTemplateId string `protobuf:"bytes,7,opt,name=hardware_template_id,json=hardwareTemplateId,proto3" json:"hardware_template_id,omitempty"` - Verified bool `protobuf:"varint,8,opt,name=verified,proto3" json:"verified,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` } -func (x *CreateDeviceDefinitionRequest) Reset() { - *x = CreateDeviceDefinitionRequest{} +func (x *BaseResponse) Reset() { + *x = BaseResponse{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[11] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *CreateDeviceDefinitionRequest) String() string { +func (x *BaseResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*CreateDeviceDefinitionRequest) ProtoMessage() {} +func (*BaseResponse) ProtoMessage() {} -func (x *CreateDeviceDefinitionRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[11] +func (x *BaseResponse) ProtoReflect() protoreflect.Message { + mi := &file_pkg_grpc_device_definition_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -914,92 +796,142 @@ func (x *CreateDeviceDefinitionRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use CreateDeviceDefinitionRequest.ProtoReflect.Descriptor instead. -func (*CreateDeviceDefinitionRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{11} +// Deprecated: Use BaseResponse.ProtoReflect.Descriptor instead. +func (*BaseResponse) Descriptor() ([]byte, []int) { + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{9} } -func (x *CreateDeviceDefinitionRequest) GetMake() string { +func (x *BaseResponse) GetId() string { if x != nil { - return x.Make + return x.Id } return "" } -func (x *CreateDeviceDefinitionRequest) GetModel() string { +type CreateDeviceStyleRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. + DeviceDefinitionId string `protobuf:"bytes,1,opt,name=device_definition_id,json=deviceDefinitionId,proto3" json:"device_definition_id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + ExternalStyleId string `protobuf:"bytes,3,opt,name=external_style_id,json=externalStyleId,proto3" json:"external_style_id,omitempty"` + Source string `protobuf:"bytes,4,opt,name=source,proto3" json:"source,omitempty"` + SubModel string `protobuf:"bytes,5,opt,name=sub_model,json=subModel,proto3" json:"sub_model,omitempty"` + // Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. + HardwareTemplateId string `protobuf:"bytes,6,opt,name=hardware_template_id,json=hardwareTemplateId,proto3" json:"hardware_template_id,omitempty"` + DefinitionId string `protobuf:"bytes,7,opt,name=definition_id,json=definitionId,proto3" json:"definition_id,omitempty"` +} + +func (x *CreateDeviceStyleRequest) Reset() { + *x = CreateDeviceStyleRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_grpc_device_definition_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateDeviceStyleRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateDeviceStyleRequest) ProtoMessage() {} + +func (x *CreateDeviceStyleRequest) ProtoReflect() protoreflect.Message { + mi := &file_pkg_grpc_device_definition_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateDeviceStyleRequest.ProtoReflect.Descriptor instead. +func (*CreateDeviceStyleRequest) Descriptor() ([]byte, []int) { + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{10} +} + +// Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. +func (x *CreateDeviceStyleRequest) GetDeviceDefinitionId() string { if x != nil { - return x.Model + return x.DeviceDefinitionId } return "" } -func (x *CreateDeviceDefinitionRequest) GetYear() int32 { +func (x *CreateDeviceStyleRequest) GetName() string { if x != nil { - return x.Year + return x.Name } - return 0 + return "" } -func (x *CreateDeviceDefinitionRequest) GetSource() string { +func (x *CreateDeviceStyleRequest) GetExternalStyleId() string { if x != nil { - return x.Source + return x.ExternalStyleId } return "" } -func (x *CreateDeviceDefinitionRequest) GetDeviceTypeId() string { +func (x *CreateDeviceStyleRequest) GetSource() string { if x != nil { - return x.DeviceTypeId + return x.Source } return "" } -func (x *CreateDeviceDefinitionRequest) GetDeviceAttributes() []*DeviceTypeAttributeRequest { +func (x *CreateDeviceStyleRequest) GetSubModel() string { if x != nil { - return x.DeviceAttributes + return x.SubModel } - return nil + return "" } -func (x *CreateDeviceDefinitionRequest) GetHardwareTemplateId() string { +// Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. +func (x *CreateDeviceStyleRequest) GetHardwareTemplateId() string { if x != nil { return x.HardwareTemplateId } return "" } -func (x *CreateDeviceDefinitionRequest) GetVerified() bool { +func (x *CreateDeviceStyleRequest) GetDefinitionId() string { if x != nil { - return x.Verified + return x.DefinitionId } - return false + return "" } -type BaseResponse struct { +type GetIntegrationRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Id []string `protobuf:"bytes,1,rep,name=id,proto3" json:"id,omitempty"` } -func (x *BaseResponse) Reset() { - *x = BaseResponse{} +func (x *GetIntegrationRequest) Reset() { + *x = GetIntegrationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[12] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *BaseResponse) String() string { +func (x *GetIntegrationRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*BaseResponse) ProtoMessage() {} +func (*GetIntegrationRequest) ProtoMessage() {} -func (x *BaseResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[12] +func (x *GetIntegrationRequest) ProtoReflect() protoreflect.Message { + mi := &file_pkg_grpc_device_definition_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1010,735 +942,43 @@ func (x *BaseResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use BaseResponse.ProtoReflect.Descriptor instead. -func (*BaseResponse) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{12} +// Deprecated: Use GetIntegrationRequest.ProtoReflect.Descriptor instead. +func (*GetIntegrationRequest) Descriptor() ([]byte, []int) { + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{11} } -func (x *BaseResponse) GetId() string { +func (x *GetIntegrationRequest) GetId() []string { if x != nil { return x.Id } - return "" + return nil } -type CreateDeviceDefinitionResponse struct { +type GetIntegrationByTokenIDRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - NameSlug string `protobuf:"bytes,2,opt,name=name_slug,json=nameSlug,proto3" json:"name_slug,omitempty"` + TokenId uint64 `protobuf:"varint,1,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` } -func (x *CreateDeviceDefinitionResponse) Reset() { - *x = CreateDeviceDefinitionResponse{} +func (x *GetIntegrationByTokenIDRequest) Reset() { + *x = GetIntegrationByTokenIDRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[13] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *CreateDeviceDefinitionResponse) String() string { +func (x *GetIntegrationByTokenIDRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*CreateDeviceDefinitionResponse) ProtoMessage() {} +func (*GetIntegrationByTokenIDRequest) ProtoMessage() {} -func (x *CreateDeviceDefinitionResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CreateDeviceDefinitionResponse.ProtoReflect.Descriptor instead. -func (*CreateDeviceDefinitionResponse) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{13} -} - -func (x *CreateDeviceDefinitionResponse) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *CreateDeviceDefinitionResponse) GetNameSlug() string { - if x != nil { - return x.NameSlug - } - return "" -} - -type UpdateDeviceDefinitionRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // this is the name slug id now - DeviceDefinitionId string `protobuf:"bytes,1,opt,name=device_definition_id,json=deviceDefinitionId,proto3" json:"device_definition_id,omitempty"` - // Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. - Source string `protobuf:"bytes,3,opt,name=source,proto3" json:"source,omitempty"` - ImageUrl string `protobuf:"bytes,4,opt,name=image_url,json=imageUrl,proto3" json:"image_url,omitempty"` - // Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. - Verified bool `protobuf:"varint,5,opt,name=verified,proto3" json:"verified,omitempty"` - Model string `protobuf:"bytes,6,opt,name=model,proto3" json:"model,omitempty"` - Year int32 `protobuf:"varint,7,opt,name=year,proto3" json:"year,omitempty"` - // Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. - DeviceMakeId string `protobuf:"bytes,8,opt,name=device_make_id,json=deviceMakeId,proto3" json:"device_make_id,omitempty"` - DeviceStyles []*UpdateDeviceDefinitionRequest_DeviceStyles `protobuf:"bytes,9,rep,name=device_styles,json=deviceStyles,proto3" json:"device_styles,omitempty"` - // Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. - ExternalId string `protobuf:"bytes,11,opt,name=external_id,json=externalId,proto3" json:"external_id,omitempty"` - DeviceTypeId string `protobuf:"bytes,12,opt,name=device_type_id,json=deviceTypeId,proto3" json:"device_type_id,omitempty"` - DeviceAttributes []*DeviceTypeAttributeRequest `protobuf:"bytes,13,rep,name=device_attributes,json=deviceAttributes,proto3" json:"device_attributes,omitempty"` - // Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. - ExternalIds []*ExternalID `protobuf:"bytes,14,rep,name=external_ids,json=externalIds,proto3" json:"external_ids,omitempty"` - // Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. - HardwareTemplateId string `protobuf:"bytes,15,opt,name=hardware_template_id,json=hardwareTemplateId,proto3" json:"hardware_template_id,omitempty"` - ManufacturerName string `protobuf:"bytes,16,opt,name=manufacturer_name,json=manufacturerName,proto3" json:"manufacturer_name,omitempty"` -} - -func (x *UpdateDeviceDefinitionRequest) Reset() { - *x = UpdateDeviceDefinitionRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UpdateDeviceDefinitionRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpdateDeviceDefinitionRequest) ProtoMessage() {} - -func (x *UpdateDeviceDefinitionRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UpdateDeviceDefinitionRequest.ProtoReflect.Descriptor instead. -func (*UpdateDeviceDefinitionRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{14} -} - -func (x *UpdateDeviceDefinitionRequest) GetDeviceDefinitionId() string { - if x != nil { - return x.DeviceDefinitionId - } - return "" -} - -// Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. -func (x *UpdateDeviceDefinitionRequest) GetSource() string { - if x != nil { - return x.Source - } - return "" -} - -func (x *UpdateDeviceDefinitionRequest) GetImageUrl() string { - if x != nil { - return x.ImageUrl - } - return "" -} - -// Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. -func (x *UpdateDeviceDefinitionRequest) GetVerified() bool { - if x != nil { - return x.Verified - } - return false -} - -func (x *UpdateDeviceDefinitionRequest) GetModel() string { - if x != nil { - return x.Model - } - return "" -} - -func (x *UpdateDeviceDefinitionRequest) GetYear() int32 { - if x != nil { - return x.Year - } - return 0 -} - -// Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. -func (x *UpdateDeviceDefinitionRequest) GetDeviceMakeId() string { - if x != nil { - return x.DeviceMakeId - } - return "" -} - -func (x *UpdateDeviceDefinitionRequest) GetDeviceStyles() []*UpdateDeviceDefinitionRequest_DeviceStyles { - if x != nil { - return x.DeviceStyles - } - return nil -} - -// Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. -func (x *UpdateDeviceDefinitionRequest) GetExternalId() string { - if x != nil { - return x.ExternalId - } - return "" -} - -func (x *UpdateDeviceDefinitionRequest) GetDeviceTypeId() string { - if x != nil { - return x.DeviceTypeId - } - return "" -} - -func (x *UpdateDeviceDefinitionRequest) GetDeviceAttributes() []*DeviceTypeAttributeRequest { - if x != nil { - return x.DeviceAttributes - } - return nil -} - -// Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. -func (x *UpdateDeviceDefinitionRequest) GetExternalIds() []*ExternalID { - if x != nil { - return x.ExternalIds - } - return nil -} - -// Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. -func (x *UpdateDeviceDefinitionRequest) GetHardwareTemplateId() string { - if x != nil { - return x.HardwareTemplateId - } - return "" -} - -func (x *UpdateDeviceDefinitionRequest) GetManufacturerName() string { - if x != nil { - return x.ManufacturerName - } - return "" -} - -type FilterDeviceDefinitionRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. - MakeId string `protobuf:"bytes,1,opt,name=make_id,json=makeId,proto3" json:"make_id,omitempty"` - // Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. - IntegrationId string `protobuf:"bytes,2,opt,name=integration_id,json=integrationId,proto3" json:"integration_id,omitempty"` - // Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. - DeviceDefinitionId string `protobuf:"bytes,3,opt,name=deviceDefinition_id,json=deviceDefinitionId,proto3" json:"deviceDefinition_id,omitempty"` - Year int32 `protobuf:"varint,4,opt,name=year,proto3" json:"year,omitempty"` - Model string `protobuf:"bytes,5,opt,name=model,proto3" json:"model,omitempty"` - VerifiedVinList []string `protobuf:"bytes,6,rep,name=verified_vin_list,json=verifiedVinList,proto3" json:"verified_vin_list,omitempty"` - PageIndex int32 `protobuf:"varint,7,opt,name=page_index,json=pageIndex,proto3" json:"page_index,omitempty"` - PageSize int32 `protobuf:"varint,8,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` - MakeSlug string `protobuf:"bytes,9,opt,name=make_slug,json=makeSlug,proto3" json:"make_slug,omitempty"` - DefinitionId string `protobuf:"bytes,10,opt,name=definition_id,json=definitionId,proto3" json:"definition_id,omitempty"` -} - -func (x *FilterDeviceDefinitionRequest) Reset() { - *x = FilterDeviceDefinitionRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FilterDeviceDefinitionRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FilterDeviceDefinitionRequest) ProtoMessage() {} - -func (x *FilterDeviceDefinitionRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FilterDeviceDefinitionRequest.ProtoReflect.Descriptor instead. -func (*FilterDeviceDefinitionRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{15} -} - -// Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. -func (x *FilterDeviceDefinitionRequest) GetMakeId() string { - if x != nil { - return x.MakeId - } - return "" -} - -// Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. -func (x *FilterDeviceDefinitionRequest) GetIntegrationId() string { - if x != nil { - return x.IntegrationId - } - return "" -} - -// Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. -func (x *FilterDeviceDefinitionRequest) GetDeviceDefinitionId() string { - if x != nil { - return x.DeviceDefinitionId - } - return "" -} - -func (x *FilterDeviceDefinitionRequest) GetYear() int32 { - if x != nil { - return x.Year - } - return 0 -} - -func (x *FilterDeviceDefinitionRequest) GetModel() string { - if x != nil { - return x.Model - } - return "" -} - -func (x *FilterDeviceDefinitionRequest) GetVerifiedVinList() []string { - if x != nil { - return x.VerifiedVinList - } - return nil -} - -func (x *FilterDeviceDefinitionRequest) GetPageIndex() int32 { - if x != nil { - return x.PageIndex - } - return 0 -} - -func (x *FilterDeviceDefinitionRequest) GetPageSize() int32 { - if x != nil { - return x.PageSize - } - return 0 -} - -func (x *FilterDeviceDefinitionRequest) GetMakeSlug() string { - if x != nil { - return x.MakeSlug - } - return "" -} - -func (x *FilterDeviceDefinitionRequest) GetDefinitionId() string { - if x != nil { - return x.DefinitionId - } - return "" -} - -type GetFilteredDeviceDefinitionsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Items []*FilterDeviceDefinitionsReponse `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` -} - -func (x *GetFilteredDeviceDefinitionsResponse) Reset() { - *x = GetFilteredDeviceDefinitionsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[16] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetFilteredDeviceDefinitionsResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetFilteredDeviceDefinitionsResponse) ProtoMessage() {} - -func (x *GetFilteredDeviceDefinitionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[16] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetFilteredDeviceDefinitionsResponse.ProtoReflect.Descriptor instead. -func (*GetFilteredDeviceDefinitionsResponse) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{16} -} - -func (x *GetFilteredDeviceDefinitionsResponse) GetItems() []*FilterDeviceDefinitionsReponse { - if x != nil { - return x.Items - } - return nil -} - -type FilterDeviceDefinitionsReponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Model string `protobuf:"bytes,2,opt,name=model,proto3" json:"model,omitempty"` - Year int32 `protobuf:"varint,3,opt,name=year,proto3" json:"year,omitempty"` - ImageUrl string `protobuf:"bytes,4,opt,name=image_url,json=imageUrl,proto3" json:"image_url,omitempty"` - CreatedAt int64 `protobuf:"varint,5,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - UpdatedAt int64 `protobuf:"varint,6,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` - Metadata string `protobuf:"bytes,7,opt,name=metadata,proto3" json:"metadata,omitempty"` - // Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. - Source string `protobuf:"bytes,8,opt,name=source,proto3" json:"source,omitempty"` - Verified bool `protobuf:"varint,9,opt,name=verified,proto3" json:"verified,omitempty"` - // Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. - External string `protobuf:"bytes,10,opt,name=external,proto3" json:"external,omitempty"` - DeviceMakeId string `protobuf:"bytes,11,opt,name=device_make_id,json=deviceMakeId,proto3" json:"device_make_id,omitempty"` - Make string `protobuf:"bytes,12,opt,name=make,proto3" json:"make,omitempty"` - ExternalIds []*ExternalID `protobuf:"bytes,13,rep,name=external_ids,json=externalIds,proto3" json:"external_ids,omitempty"` - NameSlug string `protobuf:"bytes,14,opt,name=name_slug,json=nameSlug,proto3" json:"name_slug,omitempty"` -} - -func (x *FilterDeviceDefinitionsReponse) Reset() { - *x = FilterDeviceDefinitionsReponse{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[17] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FilterDeviceDefinitionsReponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FilterDeviceDefinitionsReponse) ProtoMessage() {} - -func (x *FilterDeviceDefinitionsReponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[17] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FilterDeviceDefinitionsReponse.ProtoReflect.Descriptor instead. -func (*FilterDeviceDefinitionsReponse) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{17} -} - -func (x *FilterDeviceDefinitionsReponse) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *FilterDeviceDefinitionsReponse) GetModel() string { - if x != nil { - return x.Model - } - return "" -} - -func (x *FilterDeviceDefinitionsReponse) GetYear() int32 { - if x != nil { - return x.Year - } - return 0 -} - -func (x *FilterDeviceDefinitionsReponse) GetImageUrl() string { - if x != nil { - return x.ImageUrl - } - return "" -} - -func (x *FilterDeviceDefinitionsReponse) GetCreatedAt() int64 { - if x != nil { - return x.CreatedAt - } - return 0 -} - -func (x *FilterDeviceDefinitionsReponse) GetUpdatedAt() int64 { - if x != nil { - return x.UpdatedAt - } - return 0 -} - -func (x *FilterDeviceDefinitionsReponse) GetMetadata() string { - if x != nil { - return x.Metadata - } - return "" -} - -// Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. -func (x *FilterDeviceDefinitionsReponse) GetSource() string { - if x != nil { - return x.Source - } - return "" -} - -func (x *FilterDeviceDefinitionsReponse) GetVerified() bool { - if x != nil { - return x.Verified - } - return false -} - -// Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. -func (x *FilterDeviceDefinitionsReponse) GetExternal() string { - if x != nil { - return x.External - } - return "" -} - -func (x *FilterDeviceDefinitionsReponse) GetDeviceMakeId() string { - if x != nil { - return x.DeviceMakeId - } - return "" -} - -func (x *FilterDeviceDefinitionsReponse) GetMake() string { - if x != nil { - return x.Make - } - return "" -} - -func (x *FilterDeviceDefinitionsReponse) GetExternalIds() []*ExternalID { - if x != nil { - return x.ExternalIds - } - return nil -} - -func (x *FilterDeviceDefinitionsReponse) GetNameSlug() string { - if x != nil { - return x.NameSlug - } - return "" -} - -type CreateDeviceStyleRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. - DeviceDefinitionId string `protobuf:"bytes,1,opt,name=device_definition_id,json=deviceDefinitionId,proto3" json:"device_definition_id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - ExternalStyleId string `protobuf:"bytes,3,opt,name=external_style_id,json=externalStyleId,proto3" json:"external_style_id,omitempty"` - Source string `protobuf:"bytes,4,opt,name=source,proto3" json:"source,omitempty"` - SubModel string `protobuf:"bytes,5,opt,name=sub_model,json=subModel,proto3" json:"sub_model,omitempty"` - // Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. - HardwareTemplateId string `protobuf:"bytes,6,opt,name=hardware_template_id,json=hardwareTemplateId,proto3" json:"hardware_template_id,omitempty"` - DefinitionId string `protobuf:"bytes,7,opt,name=definition_id,json=definitionId,proto3" json:"definition_id,omitempty"` -} - -func (x *CreateDeviceStyleRequest) Reset() { - *x = CreateDeviceStyleRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[18] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *CreateDeviceStyleRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CreateDeviceStyleRequest) ProtoMessage() {} - -func (x *CreateDeviceStyleRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[18] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CreateDeviceStyleRequest.ProtoReflect.Descriptor instead. -func (*CreateDeviceStyleRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{18} -} - -// Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. -func (x *CreateDeviceStyleRequest) GetDeviceDefinitionId() string { - if x != nil { - return x.DeviceDefinitionId - } - return "" -} - -func (x *CreateDeviceStyleRequest) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *CreateDeviceStyleRequest) GetExternalStyleId() string { - if x != nil { - return x.ExternalStyleId - } - return "" -} - -func (x *CreateDeviceStyleRequest) GetSource() string { - if x != nil { - return x.Source - } - return "" -} - -func (x *CreateDeviceStyleRequest) GetSubModel() string { - if x != nil { - return x.SubModel - } - return "" -} - -// Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. -func (x *CreateDeviceStyleRequest) GetHardwareTemplateId() string { - if x != nil { - return x.HardwareTemplateId - } - return "" -} - -func (x *CreateDeviceStyleRequest) GetDefinitionId() string { - if x != nil { - return x.DefinitionId - } - return "" -} - -type GetIntegrationRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id []string `protobuf:"bytes,1,rep,name=id,proto3" json:"id,omitempty"` -} - -func (x *GetIntegrationRequest) Reset() { - *x = GetIntegrationRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetIntegrationRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetIntegrationRequest) ProtoMessage() {} - -func (x *GetIntegrationRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[19] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetIntegrationRequest.ProtoReflect.Descriptor instead. -func (*GetIntegrationRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{19} -} - -func (x *GetIntegrationRequest) GetId() []string { - if x != nil { - return x.Id - } - return nil -} - -type GetIntegrationByTokenIDRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TokenId uint64 `protobuf:"varint,1,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` -} - -func (x *GetIntegrationByTokenIDRequest) Reset() { - *x = GetIntegrationByTokenIDRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[20] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetIntegrationByTokenIDRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetIntegrationByTokenIDRequest) ProtoMessage() {} - -func (x *GetIntegrationByTokenIDRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[20] +func (x *GetIntegrationByTokenIDRequest) ProtoReflect() protoreflect.Message { + mi := &file_pkg_grpc_device_definition_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1751,7 +991,7 @@ func (x *GetIntegrationByTokenIDRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetIntegrationByTokenIDRequest.ProtoReflect.Descriptor instead. func (*GetIntegrationByTokenIDRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{20} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{12} } func (x *GetIntegrationByTokenIDRequest) GetTokenId() uint64 { @@ -1772,7 +1012,7 @@ type GetDeviceStyleByIDRequest struct { func (x *GetDeviceStyleByIDRequest) Reset() { *x = GetDeviceStyleByIDRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[21] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1785,7 +1025,7 @@ func (x *GetDeviceStyleByIDRequest) String() string { func (*GetDeviceStyleByIDRequest) ProtoMessage() {} func (x *GetDeviceStyleByIDRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[21] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1798,7 +1038,7 @@ func (x *GetDeviceStyleByIDRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDeviceStyleByIDRequest.ProtoReflect.Descriptor instead. func (*GetDeviceStyleByIDRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{21} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{13} } func (x *GetDeviceStyleByIDRequest) GetId() string { @@ -1819,7 +1059,7 @@ type GetDeviceStyleByDeviceDefinitionIDRequest struct { func (x *GetDeviceStyleByDeviceDefinitionIDRequest) Reset() { *x = GetDeviceStyleByDeviceDefinitionIDRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[22] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1832,7 +1072,7 @@ func (x *GetDeviceStyleByDeviceDefinitionIDRequest) String() string { func (*GetDeviceStyleByDeviceDefinitionIDRequest) ProtoMessage() {} func (x *GetDeviceStyleByDeviceDefinitionIDRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[22] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1845,7 +1085,7 @@ func (x *GetDeviceStyleByDeviceDefinitionIDRequest) ProtoReflect() protoreflect. // Deprecated: Use GetDeviceStyleByDeviceDefinitionIDRequest.ProtoReflect.Descriptor instead. func (*GetDeviceStyleByDeviceDefinitionIDRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{22} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{14} } func (x *GetDeviceStyleByDeviceDefinitionIDRequest) GetId() string { @@ -1866,7 +1106,7 @@ type GetDeviceStyleResponse struct { func (x *GetDeviceStyleResponse) Reset() { *x = GetDeviceStyleResponse{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[23] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1879,7 +1119,7 @@ func (x *GetDeviceStyleResponse) String() string { func (*GetDeviceStyleResponse) ProtoMessage() {} func (x *GetDeviceStyleResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[23] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1892,7 +1132,7 @@ func (x *GetDeviceStyleResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDeviceStyleResponse.ProtoReflect.Descriptor instead. func (*GetDeviceStyleResponse) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{23} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{15} } func (x *GetDeviceStyleResponse) GetDeviceStyles() []*DeviceStyle { @@ -1916,7 +1156,7 @@ type CreateIntegrationRequest struct { func (x *CreateIntegrationRequest) Reset() { *x = CreateIntegrationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[24] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1929,7 +1169,7 @@ func (x *CreateIntegrationRequest) String() string { func (*CreateIntegrationRequest) ProtoMessage() {} func (x *CreateIntegrationRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[24] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1942,7 +1182,7 @@ func (x *CreateIntegrationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateIntegrationRequest.ProtoReflect.Descriptor instead. func (*CreateIntegrationRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{24} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{16} } func (x *CreateIntegrationRequest) GetVendor() string { @@ -1993,7 +1233,7 @@ type UpdateDeviceStyleRequest struct { func (x *UpdateDeviceStyleRequest) Reset() { *x = UpdateDeviceStyleRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[25] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2006,7 +1246,7 @@ func (x *UpdateDeviceStyleRequest) String() string { func (*UpdateDeviceStyleRequest) ProtoMessage() {} func (x *UpdateDeviceStyleRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[25] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2019,7 +1259,7 @@ func (x *UpdateDeviceStyleRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateDeviceStyleRequest.ProtoReflect.Descriptor instead. func (*UpdateDeviceStyleRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{25} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{17} } func (x *UpdateDeviceStyleRequest) GetId() string { @@ -2094,7 +1334,7 @@ type GetDeviceStyleFilterRequest struct { func (x *GetDeviceStyleFilterRequest) Reset() { *x = GetDeviceStyleFilterRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[26] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2107,7 +1347,7 @@ func (x *GetDeviceStyleFilterRequest) String() string { func (*GetDeviceStyleFilterRequest) ProtoMessage() {} func (x *GetDeviceStyleFilterRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[26] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2120,7 +1360,7 @@ func (x *GetDeviceStyleFilterRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDeviceStyleFilterRequest.ProtoReflect.Descriptor instead. func (*GetDeviceStyleFilterRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{26} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{18} } func (x *GetDeviceStyleFilterRequest) GetName() string { @@ -2162,7 +1402,7 @@ type GetDeviceTypeByIDRequest struct { func (x *GetDeviceTypeByIDRequest) Reset() { *x = GetDeviceTypeByIDRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[27] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2175,7 +1415,7 @@ func (x *GetDeviceTypeByIDRequest) String() string { func (*GetDeviceTypeByIDRequest) ProtoMessage() {} func (x *GetDeviceTypeByIDRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[27] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2188,7 +1428,7 @@ func (x *GetDeviceTypeByIDRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDeviceTypeByIDRequest.ProtoReflect.Descriptor instead. func (*GetDeviceTypeByIDRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{27} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{19} } func (x *GetDeviceTypeByIDRequest) GetId() string { @@ -2212,7 +1452,7 @@ type GetDeviceTypeResponse struct { func (x *GetDeviceTypeResponse) Reset() { *x = GetDeviceTypeResponse{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[28] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2225,7 +1465,7 @@ func (x *GetDeviceTypeResponse) String() string { func (*GetDeviceTypeResponse) ProtoMessage() {} func (x *GetDeviceTypeResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[28] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2238,7 +1478,7 @@ func (x *GetDeviceTypeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDeviceTypeResponse.ProtoReflect.Descriptor instead. func (*GetDeviceTypeResponse) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{28} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{20} } func (x *GetDeviceTypeResponse) GetId() string { @@ -2280,7 +1520,7 @@ type GetDeviceTypeListResponse struct { func (x *GetDeviceTypeListResponse) Reset() { *x = GetDeviceTypeListResponse{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[29] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2293,7 +1533,7 @@ func (x *GetDeviceTypeListResponse) String() string { func (*GetDeviceTypeListResponse) ProtoMessage() {} func (x *GetDeviceTypeListResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[29] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2306,7 +1546,7 @@ func (x *GetDeviceTypeListResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDeviceTypeListResponse.ProtoReflect.Descriptor instead. func (*GetDeviceTypeListResponse) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{29} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{21} } func (x *GetDeviceTypeListResponse) GetDeviceTypes() []*GetDeviceTypeResponse { @@ -2328,7 +1568,7 @@ type CreateDeviceTypeRequest struct { func (x *CreateDeviceTypeRequest) Reset() { *x = CreateDeviceTypeRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[30] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2341,7 +1581,7 @@ func (x *CreateDeviceTypeRequest) String() string { func (*CreateDeviceTypeRequest) ProtoMessage() {} func (x *CreateDeviceTypeRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[30] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2354,7 +1594,7 @@ func (x *CreateDeviceTypeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateDeviceTypeRequest.ProtoReflect.Descriptor instead. func (*CreateDeviceTypeRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{30} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{22} } func (x *CreateDeviceTypeRequest) GetId() string { @@ -2384,7 +1624,7 @@ type UpdateDeviceTypeRequest struct { func (x *UpdateDeviceTypeRequest) Reset() { *x = UpdateDeviceTypeRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[31] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2397,7 +1637,7 @@ func (x *UpdateDeviceTypeRequest) String() string { func (*UpdateDeviceTypeRequest) ProtoMessage() {} func (x *UpdateDeviceTypeRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[31] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2410,7 +1650,7 @@ func (x *UpdateDeviceTypeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateDeviceTypeRequest.ProtoReflect.Descriptor instead. func (*UpdateDeviceTypeRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{31} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{23} } func (x *UpdateDeviceTypeRequest) GetId() string { @@ -2451,7 +1691,7 @@ type CreateDeviceTypeAttributeRequest struct { func (x *CreateDeviceTypeAttributeRequest) Reset() { *x = CreateDeviceTypeAttributeRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[32] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2464,7 +1704,7 @@ func (x *CreateDeviceTypeAttributeRequest) String() string { func (*CreateDeviceTypeAttributeRequest) ProtoMessage() {} func (x *CreateDeviceTypeAttributeRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[32] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2477,7 +1717,7 @@ func (x *CreateDeviceTypeAttributeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateDeviceTypeAttributeRequest.ProtoReflect.Descriptor instead. func (*CreateDeviceTypeAttributeRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{32} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{24} } func (x *CreateDeviceTypeAttributeRequest) GetName() string { @@ -2540,7 +1780,7 @@ type DeleteDeviceTypeRequest struct { func (x *DeleteDeviceTypeRequest) Reset() { *x = DeleteDeviceTypeRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[33] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2553,7 +1793,7 @@ func (x *DeleteDeviceTypeRequest) String() string { func (*DeleteDeviceTypeRequest) ProtoMessage() {} func (x *DeleteDeviceTypeRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[33] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2566,7 +1806,7 @@ func (x *DeleteDeviceTypeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteDeviceTypeRequest.ProtoReflect.Descriptor instead. func (*DeleteDeviceTypeRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{33} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{25} } func (x *DeleteDeviceTypeRequest) GetId() string { @@ -2588,7 +1828,7 @@ type GetDeviceDefinitionHardwareTemplateByIDRequest struct { func (x *GetDeviceDefinitionHardwareTemplateByIDRequest) Reset() { *x = GetDeviceDefinitionHardwareTemplateByIDRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[34] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2601,7 +1841,7 @@ func (x *GetDeviceDefinitionHardwareTemplateByIDRequest) String() string { func (*GetDeviceDefinitionHardwareTemplateByIDRequest) ProtoMessage() {} func (x *GetDeviceDefinitionHardwareTemplateByIDRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[34] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2614,7 +1854,7 @@ func (x *GetDeviceDefinitionHardwareTemplateByIDRequest) ProtoReflect() protoref // Deprecated: Use GetDeviceDefinitionHardwareTemplateByIDRequest.ProtoReflect.Descriptor instead. func (*GetDeviceDefinitionHardwareTemplateByIDRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{34} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{26} } func (x *GetDeviceDefinitionHardwareTemplateByIDRequest) GetId() string { @@ -2642,7 +1882,7 @@ type GetDeviceDefinitionHardwareTemplateByIDResponse struct { func (x *GetDeviceDefinitionHardwareTemplateByIDResponse) Reset() { *x = GetDeviceDefinitionHardwareTemplateByIDResponse{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[35] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2655,7 +1895,7 @@ func (x *GetDeviceDefinitionHardwareTemplateByIDResponse) String() string { func (*GetDeviceDefinitionHardwareTemplateByIDResponse) ProtoMessage() {} func (x *GetDeviceDefinitionHardwareTemplateByIDResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[35] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2668,7 +1908,7 @@ func (x *GetDeviceDefinitionHardwareTemplateByIDResponse) ProtoReflect() protore // Deprecated: Use GetDeviceDefinitionHardwareTemplateByIDResponse.ProtoReflect.Descriptor instead. func (*GetDeviceDefinitionHardwareTemplateByIDResponse) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{35} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{27} } func (x *GetDeviceDefinitionHardwareTemplateByIDResponse) GetHardwareTemplateId() string { @@ -2695,7 +1935,7 @@ type DeviceImage struct { func (x *DeviceImage) Reset() { *x = DeviceImage{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[36] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2708,7 +1948,7 @@ func (x *DeviceImage) String() string { func (*DeviceImage) ProtoMessage() {} func (x *DeviceImage) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[36] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2721,7 +1961,7 @@ func (x *DeviceImage) ProtoReflect() protoreflect.Message { // Deprecated: Use DeviceImage.ProtoReflect.Descriptor instead. func (*DeviceImage) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{36} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{28} } // Deprecated: Marked as deprecated in pkg/grpc/device_definition.proto. @@ -2778,7 +2018,7 @@ type GetDeviceImagesResponse struct { func (x *GetDeviceImagesResponse) Reset() { *x = GetDeviceImagesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[37] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2791,7 +2031,7 @@ func (x *GetDeviceImagesResponse) String() string { func (*GetDeviceImagesResponse) ProtoMessage() {} func (x *GetDeviceImagesResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[37] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2804,7 +2044,7 @@ func (x *GetDeviceImagesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDeviceImagesResponse.ProtoReflect.Descriptor instead. func (*GetDeviceImagesResponse) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{37} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{29} } func (x *GetDeviceImagesResponse) GetImages() []*DeviceImage { @@ -2825,7 +2065,7 @@ type SyncStatusResult struct { func (x *SyncStatusResult) Reset() { *x = SyncStatusResult{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[38] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2838,7 +2078,7 @@ func (x *SyncStatusResult) String() string { func (*SyncStatusResult) ProtoMessage() {} func (x *SyncStatusResult) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[38] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2851,7 +2091,7 @@ func (x *SyncStatusResult) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncStatusResult.ProtoReflect.Descriptor instead. func (*SyncStatusResult) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{38} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{30} } func (x *SyncStatusResult) GetStatus() bool { @@ -2874,7 +2114,7 @@ type GetDeviceDefinitionByMakeAndYearRangeRequest struct { func (x *GetDeviceDefinitionByMakeAndYearRangeRequest) Reset() { *x = GetDeviceDefinitionByMakeAndYearRangeRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[39] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2887,7 +2127,7 @@ func (x *GetDeviceDefinitionByMakeAndYearRangeRequest) String() string { func (*GetDeviceDefinitionByMakeAndYearRangeRequest) ProtoMessage() {} func (x *GetDeviceDefinitionByMakeAndYearRangeRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[39] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2900,7 +2140,7 @@ func (x *GetDeviceDefinitionByMakeAndYearRangeRequest) ProtoReflect() protorefle // Deprecated: Use GetDeviceDefinitionByMakeAndYearRangeRequest.ProtoReflect.Descriptor instead. func (*GetDeviceDefinitionByMakeAndYearRangeRequest) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{39} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{31} } func (x *GetDeviceDefinitionByMakeAndYearRangeRequest) GetMake() string { @@ -2938,7 +2178,7 @@ type Integration_AutoPiPowertrainTemplate struct { func (x *Integration_AutoPiPowertrainTemplate) Reset() { *x = Integration_AutoPiPowertrainTemplate{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[40] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2951,7 +2191,7 @@ func (x *Integration_AutoPiPowertrainTemplate) String() string { func (*Integration_AutoPiPowertrainTemplate) ProtoMessage() {} func (x *Integration_AutoPiPowertrainTemplate) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[40] + mi := &file_pkg_grpc_device_definition_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2964,7 +2204,7 @@ func (x *Integration_AutoPiPowertrainTemplate) ProtoReflect() protoreflect.Messa // Deprecated: Use Integration_AutoPiPowertrainTemplate.ProtoReflect.Descriptor instead. func (*Integration_AutoPiPowertrainTemplate) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{10, 0} + return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{8, 0} } func (x *Integration_AutoPiPowertrainTemplate) GetBEV() int32 { @@ -2995,145 +2235,237 @@ func (x *Integration_AutoPiPowertrainTemplate) GetPHEV() int32 { return 0 } -type UpdateDeviceDefinitionRequest_DeviceStyles struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - ExternalStyleId string `protobuf:"bytes,3,opt,name=external_style_id,json=externalStyleId,proto3" json:"external_style_id,omitempty"` - Source string `protobuf:"bytes,4,opt,name=source,proto3" json:"source,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` - SubModel string `protobuf:"bytes,7,opt,name=sub_model,json=subModel,proto3" json:"sub_model,omitempty"` - HardwareTemplateId string `protobuf:"bytes,8,opt,name=hardware_template_id,json=hardwareTemplateId,proto3" json:"hardware_template_id,omitempty"` -} - -func (x *UpdateDeviceDefinitionRequest_DeviceStyles) Reset() { - *x = UpdateDeviceDefinitionRequest_DeviceStyles{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[41] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UpdateDeviceDefinitionRequest_DeviceStyles) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpdateDeviceDefinitionRequest_DeviceStyles) ProtoMessage() {} - -func (x *UpdateDeviceDefinitionRequest_DeviceStyles) ProtoReflect() protoreflect.Message { - mi := &file_pkg_grpc_device_definition_proto_msgTypes[41] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UpdateDeviceDefinitionRequest_DeviceStyles.ProtoReflect.Descriptor instead. -func (*UpdateDeviceDefinitionRequest_DeviceStyles) Descriptor() ([]byte, []int) { - return file_pkg_grpc_device_definition_proto_rawDescGZIP(), []int{14, 0} -} - -func (x *UpdateDeviceDefinitionRequest_DeviceStyles) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *UpdateDeviceDefinitionRequest_DeviceStyles) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *UpdateDeviceDefinitionRequest_DeviceStyles) GetExternalStyleId() string { - if x != nil { - return x.ExternalStyleId - } - return "" -} - -func (x *UpdateDeviceDefinitionRequest_DeviceStyles) GetSource() string { - if x != nil { - return x.Source - } - return "" -} - -func (x *UpdateDeviceDefinitionRequest_DeviceStyles) GetCreatedAt() *timestamppb.Timestamp { - if x != nil { - return x.CreatedAt - } - return nil -} - -func (x *UpdateDeviceDefinitionRequest_DeviceStyles) GetUpdatedAt() *timestamppb.Timestamp { - if x != nil { - return x.UpdatedAt - } - return nil -} - -func (x *UpdateDeviceDefinitionRequest_DeviceStyles) GetSubModel() string { - if x != nil { - return x.SubModel - } - return "" -} - -func (x *UpdateDeviceDefinitionRequest_DeviceStyles) GetHardwareTemplateId() string { - if x != nil { - return x.HardwareTemplateId - } - return "" -} - var File_pkg_grpc_device_definition_proto protoreflect.FileDescriptor var file_pkg_grpc_device_definition_proto_rawDesc = []byte{ 0x0a, 0x20, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x4b, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x03, 0x69, 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x6b, 0x65, 0x5f, 0x73, - 0x6c, 0x75, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x6b, 0x65, 0x53, - 0x6c, 0x75, 0x67, 0x22, 0x50, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x4d, 0x4d, 0x59, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x06, - 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x4d, 0x4d, - 0x59, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x06, 0x64, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x22, 0xb8, 0x01, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x4d, 0x4d, 0x59, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x6b, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6d, 0x61, 0x6b, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x12, 0x0a, - 0x04, 0x79, 0x65, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x79, 0x65, 0x61, - 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x30, 0x0a, 0x14, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x74, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x12, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x6c, 0x75, 0x67, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x6c, 0x75, 0x67, - 0x22, 0x34, 0x0a, 0x0a, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x44, 0x12, 0x16, - 0x0a, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0xe5, 0x01, 0x0a, 0x13, 0x44, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x54, 0x79, 0x70, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x12, + 0x74, 0x6f, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x4b, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x03, 0x69, 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x6b, 0x65, 0x5f, 0x73, 0x6c, + 0x75, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x6b, 0x65, 0x53, 0x6c, + 0x75, 0x67, 0x22, 0x50, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x4d, 0x4d, 0x59, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x4d, 0x4d, 0x59, + 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x06, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x22, 0xb8, 0x01, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x4d, 0x4d, 0x59, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x6b, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6d, 0x61, 0x6b, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, + 0x79, 0x65, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x79, 0x65, 0x61, 0x72, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x30, 0x0a, 0x14, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x74, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, + 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, + 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x6c, 0x75, 0x67, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x6c, 0x75, 0x67, 0x22, + 0xe5, 0x01, 0x0a, 0x13, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x41, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, + 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xb9, 0x01, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, + 0x6b, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x61, 0x6b, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, + 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x79, 0x65, 0x61, 0x72, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x04, 0x79, 0x65, 0x61, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x75, 0x62, 0x5f, + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x73, 0x75, + 0x62, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x6b, 0x65, 0x5f, + 0x73, 0x6c, 0x75, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x6b, 0x65, + 0x53, 0x6c, 0x75, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x73, 0x6c, + 0x75, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x53, + 0x6c, 0x75, 0x67, 0x22, 0xeb, 0x02, 0x0a, 0x0b, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, + 0x79, 0x6c, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x73, 0x75, 0x62, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x34, 0x0a, 0x14, + 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x12, + 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, + 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x65, + 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x34, + 0x0a, 0x14, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, + 0x52, 0x12, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x74, 0x65, 0x49, 0x64, 0x12, 0x46, 0x0a, 0x11, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x19, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x10, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, + 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x22, 0x77, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, + 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x4d, 0x4d, 0x59, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x6b, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6d, 0x61, 0x6b, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x6b, 0x65, + 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x61, 0x6b, 0x65, 0x49, 0x44, + 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x79, 0x65, 0x61, 0x72, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x79, 0x65, 0x61, 0x72, 0x22, 0x4f, 0x0a, 0x16, 0x47, 0x65, + 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x69, + 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x83, 0x04, 0x0a, 0x0b, + 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x73, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x3c, 0x0a, + 0x1b, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x70, 0x69, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x17, 0x61, 0x75, 0x74, 0x6f, 0x50, 0x69, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, 0x69, 0x0a, 0x1b, 0x61, + 0x75, 0x74, 0x6f, 0x5f, 0x70, 0x69, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x74, 0x72, 0x61, 0x69, + 0x6e, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x50, 0x69, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x74, + 0x72, 0x61, 0x69, 0x6e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x18, 0x61, 0x75, + 0x74, 0x6f, 0x50, 0x69, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x54, 0x65, + 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, + 0x68, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x73, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x10, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x4c, 0x69, 0x6d, 0x69, 0x74, + 0x53, 0x65, 0x63, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x64, 0x12, + 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x6d, 0x61, 0x6e, 0x75, 0x66, + 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, + 0x75, 0x72, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x64, 0x1a, 0x64, 0x0a, 0x18, 0x41, + 0x75, 0x74, 0x6f, 0x50, 0x69, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x54, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x42, 0x45, 0x56, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x42, 0x45, 0x56, 0x12, 0x10, 0x0a, 0x03, 0x48, 0x45, 0x56, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x48, 0x45, 0x56, 0x12, 0x10, 0x0a, 0x03, 0x49, + 0x43, 0x45, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x49, 0x43, 0x45, 0x12, 0x12, 0x0a, + 0x04, 0x50, 0x48, 0x45, 0x56, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x50, 0x48, 0x45, + 0x56, 0x22, 0x1e, 0x0a, 0x0c, 0x42, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x22, 0xa0, 0x02, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, + 0x0a, 0x14, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, + 0x52, 0x12, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x78, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x79, + 0x6c, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, + 0x73, 0x75, 0x62, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x73, 0x75, 0x62, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x34, 0x0a, 0x14, 0x68, 0x61, 0x72, + 0x64, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x12, 0x68, 0x61, 0x72, + 0x64, 0x77, 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, + 0x23, 0x0a, 0x0d, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x27, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, + 0x1e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, + 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x19, 0x0a, 0x08, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x07, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x64, 0x22, 0x2b, 0x0a, 0x19, 0x47, 0x65, + 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x42, 0x79, 0x49, 0x44, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x29, 0x47, 0x65, 0x74, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x42, 0x79, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x64, 0x22, 0x50, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, + 0x0a, 0x0d, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x52, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x53, 0x74, 0x79, 0x6c, 0x65, 0x73, 0x22, 0x77, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, + 0x74, 0x79, 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x64, 0x22, + 0xb0, 0x02, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x53, 0x74, 0x79, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x34, 0x0a, 0x14, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, + 0x18, 0x01, 0x52, 0x12, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x79, 0x6c, 0x65, + 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x75, + 0x62, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, + 0x75, 0x62, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x34, 0x0a, 0x14, 0x68, 0x61, 0x72, 0x64, 0x77, + 0x61, 0x72, 0x65, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x12, 0x68, 0x61, 0x72, 0x64, 0x77, + 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, 0x23, 0x0a, + 0x0d, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x22, 0x98, 0x01, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x53, 0x74, 0x79, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, + 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x75, 0x62, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x22, 0x2a, 0x0a, + 0x18, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x79, + 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x15, 0x47, 0x65, + 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x41, 0x74, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x4b, 0x65, 0x79, 0x22, 0x5b, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x73, 0x22, 0x3d, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x22, 0x85, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x46, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x41, 0x74, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0a, 0x61, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x22, 0xdc, 0x01, 0x0a, 0x20, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x41, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, @@ -3141,515 +2473,149 @@ var file_pkg_grpc_device_definition_proto_rawDesc = []byte{ 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, 0x0a, 0x0b, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x46, - 0x0a, 0x1a, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x41, 0x74, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xb9, 0x01, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x6b, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x61, 0x6b, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x6f, - 0x64, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x79, 0x65, 0x61, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x04, 0x79, 0x65, 0x61, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x75, 0x62, 0x5f, 0x6d, - 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x73, 0x75, 0x62, - 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x6b, 0x65, 0x5f, 0x73, - 0x6c, 0x75, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x6b, 0x65, 0x53, - 0x6c, 0x75, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x73, 0x6c, 0x75, - 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x6c, - 0x75, 0x67, 0x22, 0xeb, 0x02, 0x0a, 0x0b, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, - 0x6c, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1b, - 0x0a, 0x09, 0x73, 0x75, 0x62, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x73, 0x75, 0x62, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x34, 0x0a, 0x14, 0x64, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x12, 0x64, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x74, - 0x79, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x65, 0x78, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x34, 0x0a, - 0x14, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, - 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, - 0x12, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 0x49, 0x64, 0x12, 0x46, 0x0a, 0x11, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x64, - 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x22, 0x77, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, - 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x4d, 0x4d, 0x59, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x6b, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6d, 0x61, 0x6b, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x6b, 0x65, 0x49, - 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x61, 0x6b, 0x65, 0x49, 0x44, 0x12, - 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x79, 0x65, 0x61, 0x72, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x04, 0x79, 0x65, 0x61, 0x72, 0x22, 0x4f, 0x0a, 0x16, 0x47, 0x65, 0x74, - 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x69, 0x6e, - 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x83, 0x04, 0x0a, 0x0b, 0x49, - 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, - 0x0a, 0x05, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, - 0x74, 0x79, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x3c, 0x0a, 0x1b, - 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x70, 0x69, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, - 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x17, 0x61, 0x75, 0x74, 0x6f, 0x50, 0x69, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, 0x69, 0x0a, 0x1b, 0x61, 0x75, - 0x74, 0x6f, 0x5f, 0x70, 0x69, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x74, 0x72, 0x61, 0x69, 0x6e, - 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x50, 0x69, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x74, 0x72, - 0x61, 0x69, 0x6e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x18, 0x61, 0x75, 0x74, - 0x6f, 0x50, 0x69, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x54, 0x65, 0x6d, - 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, - 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x10, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, - 0x65, 0x63, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x64, 0x12, 0x16, - 0x0a, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, - 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, - 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, - 0x72, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x64, 0x1a, 0x64, 0x0a, 0x18, 0x41, 0x75, - 0x74, 0x6f, 0x50, 0x69, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x54, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x42, 0x45, 0x56, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x03, 0x42, 0x45, 0x56, 0x12, 0x10, 0x0a, 0x03, 0x48, 0x45, 0x56, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x48, 0x45, 0x56, 0x12, 0x10, 0x0a, 0x03, 0x49, 0x43, - 0x45, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x49, 0x43, 0x45, 0x12, 0x12, 0x0a, 0x04, - 0x50, 0x48, 0x45, 0x56, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x50, 0x48, 0x45, 0x56, - 0x22, 0xb8, 0x02, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x6b, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6d, 0x61, 0x6b, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, - 0x79, 0x65, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x79, 0x65, 0x61, 0x72, - 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x64, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x64, 0x12, 0x4d, - 0x0a, 0x11, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, - 0x62, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x10, 0x64, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x30, 0x0a, - 0x14, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, - 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x68, 0x61, 0x72, - 0x64, 0x77, 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, - 0x1a, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x22, 0x1e, 0x0a, 0x0c, 0x42, - 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x4d, 0x0a, 0x1e, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, - 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x6c, 0x75, 0x67, 0x22, 0xc9, 0x07, 0x0a, 0x1d, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x14, - 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x64, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1a, - 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, - 0x18, 0x01, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x6d, - 0x61, 0x67, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, - 0x6d, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x1e, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, - 0x69, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x08, 0x76, - 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x12, 0x0a, - 0x04, 0x79, 0x65, 0x61, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x79, 0x65, 0x61, - 0x72, 0x12, 0x28, 0x0a, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x61, 0x6b, 0x65, - 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0c, 0x64, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x6b, 0x65, 0x49, 0x64, 0x12, 0x55, 0x0a, 0x0d, 0x64, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, - 0x79, 0x6c, 0x65, 0x73, 0x52, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, - 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, - 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x65, 0x78, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x64, 0x12, 0x4d, 0x0a, - 0x11, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x10, 0x64, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0c, - 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0e, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x49, 0x44, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x49, 0x64, 0x73, 0x12, 0x34, 0x0a, 0x14, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, - 0x65, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0f, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x12, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, - 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x6d, - 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, - 0x75, 0x72, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0xbb, 0x02, 0x0a, 0x0c, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, - 0x11, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, - 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, - 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x5f, 0x6d, - 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x75, 0x62, 0x4d, - 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x30, 0x0a, 0x14, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, - 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x12, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, - 0x6c, 0x61, 0x74, 0x65, 0x49, 0x64, 0x22, 0xf0, 0x02, 0x0a, 0x1d, 0x46, 0x69, 0x6c, 0x74, 0x65, - 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x07, 0x6d, 0x61, 0x6b, 0x65, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x06, 0x6d, - 0x61, 0x6b, 0x65, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, - 0x01, 0x52, 0x0d, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x12, 0x33, 0x0a, 0x13, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, - 0x01, 0x52, 0x12, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x79, 0x65, 0x61, 0x72, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x04, 0x79, 0x65, 0x61, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, - 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, - 0x2a, 0x0a, 0x11, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x76, 0x69, 0x6e, 0x5f, - 0x6c, 0x69, 0x73, 0x74, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x76, 0x65, 0x72, 0x69, - 0x66, 0x69, 0x65, 0x64, 0x56, 0x69, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, - 0x61, 0x67, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x09, 0x70, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, - 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, - 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x6b, 0x65, 0x5f, - 0x73, 0x6c, 0x75, 0x67, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x6b, 0x65, - 0x53, 0x6c, 0x75, 0x67, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x64, 0x65, 0x66, - 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x62, 0x0a, 0x24, 0x47, 0x65, 0x74, - 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, - 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x3a, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x24, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x44, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x65, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0xb5, 0x03, - 0x0a, 0x1e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, - 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x79, 0x65, 0x61, 0x72, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x79, 0x65, 0x61, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x6d, - 0x61, 0x67, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, - 0x6d, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x12, 0x1a, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1a, 0x0a, - 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x08, 0x65, 0x78, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, - 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x12, 0x24, 0x0a, 0x0e, 0x64, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x61, 0x6b, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x6b, 0x65, 0x49, 0x64, 0x12, - 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x6b, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, - 0x61, 0x6b, 0x65, 0x12, 0x33, 0x0a, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, - 0x69, 0x64, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x44, 0x52, 0x0b, 0x65, 0x78, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, - 0x5f, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x61, 0x6d, - 0x65, 0x53, 0x6c, 0x75, 0x67, 0x22, 0xa0, 0x02, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x34, 0x0a, 0x14, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x66, - 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x02, 0x18, 0x01, 0x52, 0x12, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, - 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x11, - 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x69, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x75, 0x62, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x34, 0x0a, - 0x14, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, - 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, - 0x12, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x69, - 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x27, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x49, - 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x22, 0x3b, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x64, 0x22, 0x2b, - 0x0a, 0x19, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, - 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x29, 0x47, - 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x42, 0x79, 0x44, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x50, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x44, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x36, 0x0a, 0x0d, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x73, 0x74, 0x79, - 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x52, 0x0c, 0x64, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x73, 0x22, 0x77, 0x0a, 0x18, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x12, - 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x49, 0x64, 0x22, 0xb0, 0x02, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x34, 0x0a, 0x14, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x64, - 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x12, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, - 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x78, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, - 0x74, 0x79, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1b, - 0x0a, 0x09, 0x73, 0x75, 0x62, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x73, 0x75, 0x62, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x34, 0x0a, 0x14, 0x68, - 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, - 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x12, 0x68, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x29, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x22, 0x67, 0x0a, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, + 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x69, + 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x63, 0x0a, 0x2f, + 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x30, 0x0a, 0x14, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x74, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, - 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x98, 0x01, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x44, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x64, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x5f, 0x6d, 0x6f, 0x64, 0x65, - 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x75, 0x62, 0x4d, 0x6f, 0x64, 0x65, - 0x6c, 0x22, 0x2a, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, - 0x70, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x99, 0x01, - 0x0a, 0x15, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x61, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x19, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4b, 0x65, 0x79, 0x22, 0x5b, 0x0a, 0x19, 0x47, 0x65, 0x74, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x22, 0x3d, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x22, 0xdc, 0x01, - 0x0a, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, - 0x70, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, - 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x29, 0x0a, 0x17, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x67, 0x0a, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x61, - 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x42, 0x79, - 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x74, - 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0d, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x22, 0x63, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, - 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x54, - 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x5f, - 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x12, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x49, 0x64, 0x22, 0xc9, 0x01, 0x0a, 0x0b, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x34, 0x0a, 0x14, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, - 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x12, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, - 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x69, - 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x69, 0x6d, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, - 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, - 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, - 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x0d, - 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x22, 0x44, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6d, - 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x06, - 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, - 0x06, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x22, 0x2a, 0x0a, 0x10, 0x53, 0x79, 0x6e, 0x63, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x22, 0x7c, 0x0a, 0x2c, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x4d, 0x61, 0x6b, 0x65, - 0x41, 0x6e, 0x64, 0x59, 0x65, 0x61, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x6b, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6d, 0x61, 0x6b, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x5f, 0x79, 0x65, 0x61, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x59, 0x65, 0x61, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x79, 0x65, - 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x59, 0x65, 0x61, - 0x72, 0x32, 0xd3, 0x0d, 0x0a, 0x17, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, - 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x47, 0x0a, - 0x0f, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x64, 0x22, 0xc9, 0x01, 0x0a, 0x0b, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6d, 0x61, 0x67, + 0x65, 0x12, 0x34, 0x0a, 0x14, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, + 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x02, 0x18, 0x01, 0x52, 0x12, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, + 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6d, 0x61, 0x67, + 0x65, 0x55, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, 0x66, 0x69, + 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x44, 0x0a, + 0x17, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x06, 0x69, 0x6d, 0x61, 0x67, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x06, 0x69, 0x6d, 0x61, + 0x67, 0x65, 0x73, 0x22, 0x2a, 0x0a, 0x10, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, + 0x7c, 0x0a, 0x2c, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, + 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x4d, 0x61, 0x6b, 0x65, 0x41, 0x6e, 0x64, 0x59, + 0x65, 0x61, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x6b, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, + 0x61, 0x6b, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x79, 0x65, 0x61, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x59, 0x65, + 0x61, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x79, 0x65, 0x61, 0x72, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x59, 0x65, 0x61, 0x72, 0x32, 0xab, 0x0b, + 0x0a, 0x17, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x47, 0x0a, 0x0f, 0x47, 0x65, 0x74, + 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, + 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x44, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x49, 0x44, 0x12, 0x1b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, - 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x49, 0x44, 0x12, 0x1b, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x63, 0x0a, 0x16, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, - 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x67, 0x72, - 0x70, 0x63, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, - 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x47, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x1e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x52, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x74, + 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x1e, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x47, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, - 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x11, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x1e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, - 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x67, 0x72, 0x70, - 0x63, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x42, 0x79, 0x49, 0x44, 0x12, 0x1f, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, - 0x6c, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, - 0x12, 0x50, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, - 0x6c, 0x65, 0x42, 0x79, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x44, 0x12, 0x1f, + 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x12, 0x47, 0x65, + 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x42, 0x79, 0x49, 0x44, + 0x12, 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, + 0x74, 0x79, 0x6c, 0x65, 0x12, 0x50, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x42, 0x79, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x49, 0x44, 0x12, 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x74, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x73, 0x42, 0x79, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x2f, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, + 0x79, 0x6c, 0x65, 0x42, 0x79, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, - 0x74, 0x79, 0x6c, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, - 0x6c, 0x65, 0x12, 0x74, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, - 0x74, 0x79, 0x6c, 0x65, 0x73, 0x42, 0x79, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, - 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x2f, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x42, - 0x79, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x72, 0x70, + 0x74, 0x79, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x17, + 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x73, 0x42, + 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x21, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, + 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x46, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x44, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x73, 0x42, 0x79, 0x46, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x12, 0x21, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, - 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x1e, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, - 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x42, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, - 0x12, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x42, - 0x79, 0x49, 0x44, 0x12, 0x1e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x49, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1f, 0x2e, 0x67, 0x72, 0x70, - 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x10, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x1d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x45, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x73, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x10, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x96, 0x01, 0x0a, 0x27, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, - 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, - 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x44, 0x12, 0x34, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, - 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x54, - 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x72, - 0x64, 0x77, 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, - 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x26, 0x53, 0x79, 0x6e, - 0x63, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x57, 0x69, 0x74, 0x68, 0x45, 0x6c, 0x61, 0x73, 0x74, 0x69, 0x63, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x72, - 0x70, 0x63, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x12, 0x52, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x44, 0x12, 0x24, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x44, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x74, 0x65, - 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x39, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x49, 0x4d, 0x4f, 0x2d, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2d, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2d, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x72, - 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x1e, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x51, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x73, 0x42, 0x79, 0x49, 0x44, 0x12, 0x1e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, + 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x79, 0x49, 0x44, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, + 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1f, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x45, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x1d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x42, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, + 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x1d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x96, 0x01, 0x0a, 0x27, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x72, 0x64, + 0x77, 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x44, + 0x12, 0x34, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x72, 0x64, 0x77, + 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, + 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, + 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, + 0x26, 0x53, 0x79, 0x6e, 0x63, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x66, 0x69, 0x6e, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x57, 0x69, 0x74, 0x68, 0x45, 0x6c, 0x61, 0x73, 0x74, 0x69, + 0x63, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x16, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x52, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x49, 0x6e, + 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x49, 0x44, 0x12, 0x24, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, + 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, + 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x39, 0x5a, 0x37, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x49, 0x4d, 0x4f, 0x2d, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2d, 0x64, 0x65, + 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2d, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6b, + 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -3664,116 +2630,92 @@ func file_pkg_grpc_device_definition_proto_rawDescGZIP() []byte { return file_pkg_grpc_device_definition_proto_rawDescData } -var file_pkg_grpc_device_definition_proto_msgTypes = make([]protoimpl.MessageInfo, 42) +var file_pkg_grpc_device_definition_proto_msgTypes = make([]protoimpl.MessageInfo, 33) var file_pkg_grpc_device_definition_proto_goTypes = []interface{}{ (*GetDeviceDefinitionRequest)(nil), // 0: grpc.GetDeviceDefinitionRequest (*GetDevicesMMYResponse)(nil), // 1: grpc.GetDevicesMMYResponse (*GetDevicesMMYItemResponse)(nil), // 2: grpc.GetDevicesMMYItemResponse - (*ExternalID)(nil), // 3: grpc.ExternalID - (*DeviceTypeAttribute)(nil), // 4: grpc.DeviceTypeAttribute - (*DeviceTypeAttributeRequest)(nil), // 5: grpc.DeviceTypeAttributeRequest - (*DeviceType)(nil), // 6: grpc.DeviceType - (*DeviceStyle)(nil), // 7: grpc.DeviceStyle - (*GetDeviceDefinitionByMMYRequest)(nil), // 8: grpc.GetDeviceDefinitionByMMYRequest - (*GetIntegrationResponse)(nil), // 9: grpc.GetIntegrationResponse - (*Integration)(nil), // 10: grpc.Integration - (*CreateDeviceDefinitionRequest)(nil), // 11: grpc.CreateDeviceDefinitionRequest - (*BaseResponse)(nil), // 12: grpc.BaseResponse - (*CreateDeviceDefinitionResponse)(nil), // 13: grpc.CreateDeviceDefinitionResponse - (*UpdateDeviceDefinitionRequest)(nil), // 14: grpc.UpdateDeviceDefinitionRequest - (*FilterDeviceDefinitionRequest)(nil), // 15: grpc.FilterDeviceDefinitionRequest - (*GetFilteredDeviceDefinitionsResponse)(nil), // 16: grpc.GetFilteredDeviceDefinitionsResponse - (*FilterDeviceDefinitionsReponse)(nil), // 17: grpc.FilterDeviceDefinitionsReponse - (*CreateDeviceStyleRequest)(nil), // 18: grpc.CreateDeviceStyleRequest - (*GetIntegrationRequest)(nil), // 19: grpc.GetIntegrationRequest - (*GetIntegrationByTokenIDRequest)(nil), // 20: grpc.GetIntegrationByTokenIDRequest - (*GetDeviceStyleByIDRequest)(nil), // 21: grpc.GetDeviceStyleByIDRequest - (*GetDeviceStyleByDeviceDefinitionIDRequest)(nil), // 22: grpc.GetDeviceStyleByDeviceDefinitionIDRequest - (*GetDeviceStyleResponse)(nil), // 23: grpc.GetDeviceStyleResponse - (*CreateIntegrationRequest)(nil), // 24: grpc.CreateIntegrationRequest - (*UpdateDeviceStyleRequest)(nil), // 25: grpc.UpdateDeviceStyleRequest - (*GetDeviceStyleFilterRequest)(nil), // 26: grpc.GetDeviceStyleFilterRequest - (*GetDeviceTypeByIDRequest)(nil), // 27: grpc.GetDeviceTypeByIDRequest - (*GetDeviceTypeResponse)(nil), // 28: grpc.GetDeviceTypeResponse - (*GetDeviceTypeListResponse)(nil), // 29: grpc.GetDeviceTypeListResponse - (*CreateDeviceTypeRequest)(nil), // 30: grpc.CreateDeviceTypeRequest - (*UpdateDeviceTypeRequest)(nil), // 31: grpc.UpdateDeviceTypeRequest - (*CreateDeviceTypeAttributeRequest)(nil), // 32: grpc.CreateDeviceTypeAttributeRequest - (*DeleteDeviceTypeRequest)(nil), // 33: grpc.DeleteDeviceTypeRequest - (*GetDeviceDefinitionHardwareTemplateByIDRequest)(nil), // 34: grpc.GetDeviceDefinitionHardwareTemplateByIDRequest - (*GetDeviceDefinitionHardwareTemplateByIDResponse)(nil), // 35: grpc.GetDeviceDefinitionHardwareTemplateByIDResponse - (*DeviceImage)(nil), // 36: grpc.DeviceImage - (*GetDeviceImagesResponse)(nil), // 37: grpc.GetDeviceImagesResponse - (*SyncStatusResult)(nil), // 38: grpc.SyncStatusResult - (*GetDeviceDefinitionByMakeAndYearRangeRequest)(nil), // 39: grpc.GetDeviceDefinitionByMakeAndYearRangeRequest - (*Integration_AutoPiPowertrainTemplate)(nil), // 40: grpc.Integration.AutoPiPowertrainTemplate - (*UpdateDeviceDefinitionRequest_DeviceStyles)(nil), // 41: grpc.UpdateDeviceDefinitionRequest.DeviceStyles - (*timestamppb.Timestamp)(nil), // 42: google.protobuf.Timestamp - (*emptypb.Empty)(nil), // 43: google.protobuf.Empty + (*DeviceTypeAttribute)(nil), // 3: grpc.DeviceTypeAttribute + (*DeviceType)(nil), // 4: grpc.DeviceType + (*DeviceStyle)(nil), // 5: grpc.DeviceStyle + (*GetDeviceDefinitionByMMYRequest)(nil), // 6: grpc.GetDeviceDefinitionByMMYRequest + (*GetIntegrationResponse)(nil), // 7: grpc.GetIntegrationResponse + (*Integration)(nil), // 8: grpc.Integration + (*BaseResponse)(nil), // 9: grpc.BaseResponse + (*CreateDeviceStyleRequest)(nil), // 10: grpc.CreateDeviceStyleRequest + (*GetIntegrationRequest)(nil), // 11: grpc.GetIntegrationRequest + (*GetIntegrationByTokenIDRequest)(nil), // 12: grpc.GetIntegrationByTokenIDRequest + (*GetDeviceStyleByIDRequest)(nil), // 13: grpc.GetDeviceStyleByIDRequest + (*GetDeviceStyleByDeviceDefinitionIDRequest)(nil), // 14: grpc.GetDeviceStyleByDeviceDefinitionIDRequest + (*GetDeviceStyleResponse)(nil), // 15: grpc.GetDeviceStyleResponse + (*CreateIntegrationRequest)(nil), // 16: grpc.CreateIntegrationRequest + (*UpdateDeviceStyleRequest)(nil), // 17: grpc.UpdateDeviceStyleRequest + (*GetDeviceStyleFilterRequest)(nil), // 18: grpc.GetDeviceStyleFilterRequest + (*GetDeviceTypeByIDRequest)(nil), // 19: grpc.GetDeviceTypeByIDRequest + (*GetDeviceTypeResponse)(nil), // 20: grpc.GetDeviceTypeResponse + (*GetDeviceTypeListResponse)(nil), // 21: grpc.GetDeviceTypeListResponse + (*CreateDeviceTypeRequest)(nil), // 22: grpc.CreateDeviceTypeRequest + (*UpdateDeviceTypeRequest)(nil), // 23: grpc.UpdateDeviceTypeRequest + (*CreateDeviceTypeAttributeRequest)(nil), // 24: grpc.CreateDeviceTypeAttributeRequest + (*DeleteDeviceTypeRequest)(nil), // 25: grpc.DeleteDeviceTypeRequest + (*GetDeviceDefinitionHardwareTemplateByIDRequest)(nil), // 26: grpc.GetDeviceDefinitionHardwareTemplateByIDRequest + (*GetDeviceDefinitionHardwareTemplateByIDResponse)(nil), // 27: grpc.GetDeviceDefinitionHardwareTemplateByIDResponse + (*DeviceImage)(nil), // 28: grpc.DeviceImage + (*GetDeviceImagesResponse)(nil), // 29: grpc.GetDeviceImagesResponse + (*SyncStatusResult)(nil), // 30: grpc.SyncStatusResult + (*GetDeviceDefinitionByMakeAndYearRangeRequest)(nil), // 31: grpc.GetDeviceDefinitionByMakeAndYearRangeRequest + (*Integration_AutoPiPowertrainTemplate)(nil), // 32: grpc.Integration.AutoPiPowertrainTemplate + (*emptypb.Empty)(nil), // 33: google.protobuf.Empty } var file_pkg_grpc_device_definition_proto_depIdxs = []int32{ 2, // 0: grpc.GetDevicesMMYResponse.device:type_name -> grpc.GetDevicesMMYItemResponse - 4, // 1: grpc.DeviceStyle.device_attributes:type_name -> grpc.DeviceTypeAttribute - 10, // 2: grpc.GetIntegrationResponse.integrations:type_name -> grpc.Integration - 40, // 3: grpc.Integration.auto_pi_powertrain_template:type_name -> grpc.Integration.AutoPiPowertrainTemplate - 5, // 4: grpc.CreateDeviceDefinitionRequest.device_attributes:type_name -> grpc.DeviceTypeAttributeRequest - 41, // 5: grpc.UpdateDeviceDefinitionRequest.device_styles:type_name -> grpc.UpdateDeviceDefinitionRequest.DeviceStyles - 5, // 6: grpc.UpdateDeviceDefinitionRequest.device_attributes:type_name -> grpc.DeviceTypeAttributeRequest - 3, // 7: grpc.UpdateDeviceDefinitionRequest.external_ids:type_name -> grpc.ExternalID - 17, // 8: grpc.GetFilteredDeviceDefinitionsResponse.items:type_name -> grpc.FilterDeviceDefinitionsReponse - 3, // 9: grpc.FilterDeviceDefinitionsReponse.external_ids:type_name -> grpc.ExternalID - 7, // 10: grpc.GetDeviceStyleResponse.device_styles:type_name -> grpc.DeviceStyle - 4, // 11: grpc.GetDeviceTypeResponse.attributes:type_name -> grpc.DeviceTypeAttribute - 28, // 12: grpc.GetDeviceTypeListResponse.device_types:type_name -> grpc.GetDeviceTypeResponse - 32, // 13: grpc.UpdateDeviceTypeRequest.attributes:type_name -> grpc.CreateDeviceTypeAttributeRequest - 36, // 14: grpc.GetDeviceImagesResponse.images:type_name -> grpc.DeviceImage - 42, // 15: grpc.UpdateDeviceDefinitionRequest.DeviceStyles.created_at:type_name -> google.protobuf.Timestamp - 42, // 16: grpc.UpdateDeviceDefinitionRequest.DeviceStyles.updated_at:type_name -> google.protobuf.Timestamp - 43, // 17: grpc.DeviceDefinitionService.GetIntegrations:input_type -> google.protobuf.Empty - 19, // 18: grpc.DeviceDefinitionService.GetIntegrationByID:input_type -> grpc.GetIntegrationRequest - 11, // 19: grpc.DeviceDefinitionService.CreateDeviceDefinition:input_type -> grpc.CreateDeviceDefinitionRequest - 18, // 20: grpc.DeviceDefinitionService.CreateDeviceStyle:input_type -> grpc.CreateDeviceStyleRequest - 24, // 21: grpc.DeviceDefinitionService.CreateIntegration:input_type -> grpc.CreateIntegrationRequest - 14, // 22: grpc.DeviceDefinitionService.UpdateDeviceDefinition:input_type -> grpc.UpdateDeviceDefinitionRequest - 15, // 23: grpc.DeviceDefinitionService.GetFilteredDeviceDefinition:input_type -> grpc.FilterDeviceDefinitionRequest - 21, // 24: grpc.DeviceDefinitionService.GetDeviceStyleByID:input_type -> grpc.GetDeviceStyleByIDRequest - 21, // 25: grpc.DeviceDefinitionService.GetDeviceStyleByExternalID:input_type -> grpc.GetDeviceStyleByIDRequest - 22, // 26: grpc.DeviceDefinitionService.GetDeviceStylesByDeviceDefinitionID:input_type -> grpc.GetDeviceStyleByDeviceDefinitionIDRequest - 26, // 27: grpc.DeviceDefinitionService.GetDeviceStylesByFilter:input_type -> grpc.GetDeviceStyleFilterRequest - 25, // 28: grpc.DeviceDefinitionService.UpdateDeviceStyle:input_type -> grpc.UpdateDeviceStyleRequest - 27, // 29: grpc.DeviceDefinitionService.GetDeviceTypesByID:input_type -> grpc.GetDeviceTypeByIDRequest - 43, // 30: grpc.DeviceDefinitionService.GetDeviceTypes:input_type -> google.protobuf.Empty - 30, // 31: grpc.DeviceDefinitionService.CreateDeviceType:input_type -> grpc.CreateDeviceTypeRequest - 31, // 32: grpc.DeviceDefinitionService.UpdateDeviceType:input_type -> grpc.UpdateDeviceTypeRequest - 33, // 33: grpc.DeviceDefinitionService.DeleteDeviceType:input_type -> grpc.DeleteDeviceTypeRequest - 34, // 34: grpc.DeviceDefinitionService.GetDeviceDefinitionHardwareTemplateByID:input_type -> grpc.GetDeviceDefinitionHardwareTemplateByIDRequest - 43, // 35: grpc.DeviceDefinitionService.SyncDeviceDefinitionsWithElasticSearch:input_type -> google.protobuf.Empty - 20, // 36: grpc.DeviceDefinitionService.GetIntegrationByTokenID:input_type -> grpc.GetIntegrationByTokenIDRequest - 9, // 37: grpc.DeviceDefinitionService.GetIntegrations:output_type -> grpc.GetIntegrationResponse - 10, // 38: grpc.DeviceDefinitionService.GetIntegrationByID:output_type -> grpc.Integration - 13, // 39: grpc.DeviceDefinitionService.CreateDeviceDefinition:output_type -> grpc.CreateDeviceDefinitionResponse - 12, // 40: grpc.DeviceDefinitionService.CreateDeviceStyle:output_type -> grpc.BaseResponse - 12, // 41: grpc.DeviceDefinitionService.CreateIntegration:output_type -> grpc.BaseResponse - 12, // 42: grpc.DeviceDefinitionService.UpdateDeviceDefinition:output_type -> grpc.BaseResponse - 16, // 43: grpc.DeviceDefinitionService.GetFilteredDeviceDefinition:output_type -> grpc.GetFilteredDeviceDefinitionsResponse - 7, // 44: grpc.DeviceDefinitionService.GetDeviceStyleByID:output_type -> grpc.DeviceStyle - 7, // 45: grpc.DeviceDefinitionService.GetDeviceStyleByExternalID:output_type -> grpc.DeviceStyle - 23, // 46: grpc.DeviceDefinitionService.GetDeviceStylesByDeviceDefinitionID:output_type -> grpc.GetDeviceStyleResponse - 23, // 47: grpc.DeviceDefinitionService.GetDeviceStylesByFilter:output_type -> grpc.GetDeviceStyleResponse - 12, // 48: grpc.DeviceDefinitionService.UpdateDeviceStyle:output_type -> grpc.BaseResponse - 28, // 49: grpc.DeviceDefinitionService.GetDeviceTypesByID:output_type -> grpc.GetDeviceTypeResponse - 29, // 50: grpc.DeviceDefinitionService.GetDeviceTypes:output_type -> grpc.GetDeviceTypeListResponse - 12, // 51: grpc.DeviceDefinitionService.CreateDeviceType:output_type -> grpc.BaseResponse - 12, // 52: grpc.DeviceDefinitionService.UpdateDeviceType:output_type -> grpc.BaseResponse - 12, // 53: grpc.DeviceDefinitionService.DeleteDeviceType:output_type -> grpc.BaseResponse - 35, // 54: grpc.DeviceDefinitionService.GetDeviceDefinitionHardwareTemplateByID:output_type -> grpc.GetDeviceDefinitionHardwareTemplateByIDResponse - 38, // 55: grpc.DeviceDefinitionService.SyncDeviceDefinitionsWithElasticSearch:output_type -> grpc.SyncStatusResult - 10, // 56: grpc.DeviceDefinitionService.GetIntegrationByTokenID:output_type -> grpc.Integration - 37, // [37:57] is the sub-list for method output_type - 17, // [17:37] is the sub-list for method input_type - 17, // [17:17] is the sub-list for extension type_name - 17, // [17:17] is the sub-list for extension extendee - 0, // [0:17] is the sub-list for field type_name + 3, // 1: grpc.DeviceStyle.device_attributes:type_name -> grpc.DeviceTypeAttribute + 8, // 2: grpc.GetIntegrationResponse.integrations:type_name -> grpc.Integration + 32, // 3: grpc.Integration.auto_pi_powertrain_template:type_name -> grpc.Integration.AutoPiPowertrainTemplate + 5, // 4: grpc.GetDeviceStyleResponse.device_styles:type_name -> grpc.DeviceStyle + 3, // 5: grpc.GetDeviceTypeResponse.attributes:type_name -> grpc.DeviceTypeAttribute + 20, // 6: grpc.GetDeviceTypeListResponse.device_types:type_name -> grpc.GetDeviceTypeResponse + 24, // 7: grpc.UpdateDeviceTypeRequest.attributes:type_name -> grpc.CreateDeviceTypeAttributeRequest + 28, // 8: grpc.GetDeviceImagesResponse.images:type_name -> grpc.DeviceImage + 33, // 9: grpc.DeviceDefinitionService.GetIntegrations:input_type -> google.protobuf.Empty + 11, // 10: grpc.DeviceDefinitionService.GetIntegrationByID:input_type -> grpc.GetIntegrationRequest + 10, // 11: grpc.DeviceDefinitionService.CreateDeviceStyle:input_type -> grpc.CreateDeviceStyleRequest + 16, // 12: grpc.DeviceDefinitionService.CreateIntegration:input_type -> grpc.CreateIntegrationRequest + 13, // 13: grpc.DeviceDefinitionService.GetDeviceStyleByID:input_type -> grpc.GetDeviceStyleByIDRequest + 13, // 14: grpc.DeviceDefinitionService.GetDeviceStyleByExternalID:input_type -> grpc.GetDeviceStyleByIDRequest + 14, // 15: grpc.DeviceDefinitionService.GetDeviceStylesByDeviceDefinitionID:input_type -> grpc.GetDeviceStyleByDeviceDefinitionIDRequest + 18, // 16: grpc.DeviceDefinitionService.GetDeviceStylesByFilter:input_type -> grpc.GetDeviceStyleFilterRequest + 17, // 17: grpc.DeviceDefinitionService.UpdateDeviceStyle:input_type -> grpc.UpdateDeviceStyleRequest + 19, // 18: grpc.DeviceDefinitionService.GetDeviceTypesByID:input_type -> grpc.GetDeviceTypeByIDRequest + 33, // 19: grpc.DeviceDefinitionService.GetDeviceTypes:input_type -> google.protobuf.Empty + 22, // 20: grpc.DeviceDefinitionService.CreateDeviceType:input_type -> grpc.CreateDeviceTypeRequest + 23, // 21: grpc.DeviceDefinitionService.UpdateDeviceType:input_type -> grpc.UpdateDeviceTypeRequest + 25, // 22: grpc.DeviceDefinitionService.DeleteDeviceType:input_type -> grpc.DeleteDeviceTypeRequest + 26, // 23: grpc.DeviceDefinitionService.GetDeviceDefinitionHardwareTemplateByID:input_type -> grpc.GetDeviceDefinitionHardwareTemplateByIDRequest + 33, // 24: grpc.DeviceDefinitionService.SyncDeviceDefinitionsWithElasticSearch:input_type -> google.protobuf.Empty + 12, // 25: grpc.DeviceDefinitionService.GetIntegrationByTokenID:input_type -> grpc.GetIntegrationByTokenIDRequest + 7, // 26: grpc.DeviceDefinitionService.GetIntegrations:output_type -> grpc.GetIntegrationResponse + 8, // 27: grpc.DeviceDefinitionService.GetIntegrationByID:output_type -> grpc.Integration + 9, // 28: grpc.DeviceDefinitionService.CreateDeviceStyle:output_type -> grpc.BaseResponse + 9, // 29: grpc.DeviceDefinitionService.CreateIntegration:output_type -> grpc.BaseResponse + 5, // 30: grpc.DeviceDefinitionService.GetDeviceStyleByID:output_type -> grpc.DeviceStyle + 5, // 31: grpc.DeviceDefinitionService.GetDeviceStyleByExternalID:output_type -> grpc.DeviceStyle + 15, // 32: grpc.DeviceDefinitionService.GetDeviceStylesByDeviceDefinitionID:output_type -> grpc.GetDeviceStyleResponse + 15, // 33: grpc.DeviceDefinitionService.GetDeviceStylesByFilter:output_type -> grpc.GetDeviceStyleResponse + 9, // 34: grpc.DeviceDefinitionService.UpdateDeviceStyle:output_type -> grpc.BaseResponse + 20, // 35: grpc.DeviceDefinitionService.GetDeviceTypesByID:output_type -> grpc.GetDeviceTypeResponse + 21, // 36: grpc.DeviceDefinitionService.GetDeviceTypes:output_type -> grpc.GetDeviceTypeListResponse + 9, // 37: grpc.DeviceDefinitionService.CreateDeviceType:output_type -> grpc.BaseResponse + 9, // 38: grpc.DeviceDefinitionService.UpdateDeviceType:output_type -> grpc.BaseResponse + 9, // 39: grpc.DeviceDefinitionService.DeleteDeviceType:output_type -> grpc.BaseResponse + 27, // 40: grpc.DeviceDefinitionService.GetDeviceDefinitionHardwareTemplateByID:output_type -> grpc.GetDeviceDefinitionHardwareTemplateByIDResponse + 30, // 41: grpc.DeviceDefinitionService.SyncDeviceDefinitionsWithElasticSearch:output_type -> grpc.SyncStatusResult + 8, // 42: grpc.DeviceDefinitionService.GetIntegrationByTokenID:output_type -> grpc.Integration + 26, // [26:43] is the sub-list for method output_type + 9, // [9:26] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name } func init() { file_pkg_grpc_device_definition_proto_init() } @@ -3819,18 +2761,6 @@ func file_pkg_grpc_device_definition_proto_init() { } } file_pkg_grpc_device_definition_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExternalID); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_grpc_device_definition_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DeviceTypeAttribute); i { case 0: return &v.state @@ -3842,19 +2772,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeviceTypeAttributeRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_grpc_device_definition_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DeviceType); i { case 0: return &v.state @@ -3866,7 +2784,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DeviceStyle); i { case 0: return &v.state @@ -3878,7 +2796,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetDeviceDefinitionByMMYRequest); i { case 0: return &v.state @@ -3890,7 +2808,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetIntegrationResponse); i { case 0: return &v.state @@ -3902,7 +2820,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Integration); i { case 0: return &v.state @@ -3914,19 +2832,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateDeviceDefinitionRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_grpc_device_definition_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BaseResponse); i { case 0: return &v.state @@ -3938,67 +2844,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateDeviceDefinitionResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_grpc_device_definition_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateDeviceDefinitionRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_grpc_device_definition_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FilterDeviceDefinitionRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_grpc_device_definition_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetFilteredDeviceDefinitionsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_grpc_device_definition_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FilterDeviceDefinitionsReponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_grpc_device_definition_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreateDeviceStyleRequest); i { case 0: return &v.state @@ -4010,7 +2856,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetIntegrationRequest); i { case 0: return &v.state @@ -4022,7 +2868,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetIntegrationByTokenIDRequest); i { case 0: return &v.state @@ -4034,7 +2880,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetDeviceStyleByIDRequest); i { case 0: return &v.state @@ -4046,7 +2892,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetDeviceStyleByDeviceDefinitionIDRequest); i { case 0: return &v.state @@ -4058,7 +2904,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetDeviceStyleResponse); i { case 0: return &v.state @@ -4070,7 +2916,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreateIntegrationRequest); i { case 0: return &v.state @@ -4082,7 +2928,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*UpdateDeviceStyleRequest); i { case 0: return &v.state @@ -4094,7 +2940,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetDeviceStyleFilterRequest); i { case 0: return &v.state @@ -4106,7 +2952,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetDeviceTypeByIDRequest); i { case 0: return &v.state @@ -4118,7 +2964,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetDeviceTypeResponse); i { case 0: return &v.state @@ -4130,7 +2976,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetDeviceTypeListResponse); i { case 0: return &v.state @@ -4142,7 +2988,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreateDeviceTypeRequest); i { case 0: return &v.state @@ -4154,7 +3000,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*UpdateDeviceTypeRequest); i { case 0: return &v.state @@ -4166,7 +3012,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreateDeviceTypeAttributeRequest); i { case 0: return &v.state @@ -4178,7 +3024,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DeleteDeviceTypeRequest); i { case 0: return &v.state @@ -4190,7 +3036,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetDeviceDefinitionHardwareTemplateByIDRequest); i { case 0: return &v.state @@ -4202,7 +3048,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetDeviceDefinitionHardwareTemplateByIDResponse); i { case 0: return &v.state @@ -4214,7 +3060,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DeviceImage); i { case 0: return &v.state @@ -4226,7 +3072,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetDeviceImagesResponse); i { case 0: return &v.state @@ -4238,7 +3084,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SyncStatusResult); i { case 0: return &v.state @@ -4250,7 +3096,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetDeviceDefinitionByMakeAndYearRangeRequest); i { case 0: return &v.state @@ -4262,7 +3108,7 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + file_pkg_grpc_device_definition_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Integration_AutoPiPowertrainTemplate); i { case 0: return &v.state @@ -4274,18 +3120,6 @@ func file_pkg_grpc_device_definition_proto_init() { return nil } } - file_pkg_grpc_device_definition_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateDeviceDefinitionRequest_DeviceStyles); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } } type x struct{} out := protoimpl.TypeBuilder{ @@ -4293,7 +3127,7 @@ func file_pkg_grpc_device_definition_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_pkg_grpc_device_definition_proto_rawDesc, NumEnums: 0, - NumMessages: 42, + NumMessages: 33, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/grpc/device_definition.proto b/pkg/grpc/device_definition.proto index 9bef26d4..b8d592c3 100644 --- a/pkg/grpc/device_definition.proto +++ b/pkg/grpc/device_definition.proto @@ -1,6 +1,5 @@ syntax = "proto3"; -import "google/protobuf/timestamp.proto"; import "google/protobuf/empty.proto"; option go_package = "github.com/DIMO-Network/device-definitions-api/pkg/grpc"; @@ -25,11 +24,6 @@ message GetDevicesMMYItemResponse { string name_slug = 6; } -message ExternalID { - string vendor = 1; - string id = 2; -} - message DeviceTypeAttribute { string name = 1; string label = 2; @@ -41,11 +35,6 @@ message DeviceTypeAttribute { string description = 8; } -message DeviceTypeAttributeRequest { - string name = 1; - string value = 2; -} - message DeviceType { string type = 1; string make = 2; @@ -99,89 +88,10 @@ message Integration { uint64 manufacturer_token_id = 10; } -message CreateDeviceDefinitionRequest { - string make = 1; - string model = 2; - int32 year = 3; - string source = 4; - string device_type_id = 5; - repeated DeviceTypeAttributeRequest device_attributes = 6; - string hardware_template_id = 7; - bool verified = 8; -} - message BaseResponse { string id = 1; } -message CreateDeviceDefinitionResponse { - string id = 1; - string name_slug = 2; -} - -message UpdateDeviceDefinitionRequest { - // this is the name slug id now - string device_definition_id = 1; - string source = 3 [deprecated = true]; - string image_url = 4; - bool verified = 5 [deprecated = true]; - string model = 6; - int32 year = 7; - string device_make_id = 8 [deprecated = true]; - repeated DeviceStyles device_styles = 9; - string external_id = 11 [deprecated = true]; - string device_type_id = 12; - repeated DeviceTypeAttributeRequest device_attributes = 13; - repeated ExternalID external_ids = 14 [deprecated = true]; - string hardware_template_id = 15 [deprecated = true]; - string manufacturer_name = 16; - - message DeviceStyles { - string id = 1; - string name = 2; - string external_style_id = 3; - string source = 4; - google.protobuf.Timestamp created_at = 5; - google.protobuf.Timestamp updated_at = 6; - string sub_model = 7; - string hardware_template_id = 8; - } -} - -message FilterDeviceDefinitionRequest { - string make_id = 1 [deprecated=true]; - string integration_id = 2 [deprecated=true]; - string deviceDefinition_id = 3 [deprecated=true]; - int32 year = 4; - string model = 5; - repeated string verified_vin_list = 6; - int32 page_index = 7; - int32 page_size = 8; - string make_slug = 9; - string definition_id = 10; -} - -message GetFilteredDeviceDefinitionsResponse { - repeated FilterDeviceDefinitionsReponse items = 1; -} - -message FilterDeviceDefinitionsReponse { - string id = 1; - string model = 2; - int32 year = 3; - string image_url = 4; - int64 created_at = 5; - int64 updated_at = 6; - string metadata = 7; - string source = 8 [deprecated = true]; - bool verified = 9; - string external = 10 [deprecated = true]; - string device_make_id = 11; - string make = 12; - repeated ExternalID external_ids = 13; - string name_slug = 14; -} - message CreateDeviceStyleRequest { string device_definition_id = 1 [deprecated=true]; string name = 2; @@ -312,11 +222,8 @@ message GetDeviceDefinitionByMakeAndYearRangeRequest { service DeviceDefinitionService { rpc GetIntegrations(google.protobuf.Empty) returns (GetIntegrationResponse); rpc GetIntegrationByID(GetIntegrationRequest) returns (Integration); - rpc CreateDeviceDefinition(CreateDeviceDefinitionRequest) returns (CreateDeviceDefinitionResponse); rpc CreateDeviceStyle(CreateDeviceStyleRequest) returns (BaseResponse); rpc CreateIntegration(CreateIntegrationRequest) returns (BaseResponse); - rpc UpdateDeviceDefinition(UpdateDeviceDefinitionRequest) returns (BaseResponse); - rpc GetFilteredDeviceDefinition(FilterDeviceDefinitionRequest) returns (GetFilteredDeviceDefinitionsResponse); rpc GetDeviceStyleByID(GetDeviceStyleByIDRequest) returns (DeviceStyle); rpc GetDeviceStyleByExternalID(GetDeviceStyleByIDRequest) returns (DeviceStyle); rpc GetDeviceStylesByDeviceDefinitionID(GetDeviceStyleByDeviceDefinitionIDRequest) returns (GetDeviceStyleResponse); diff --git a/pkg/grpc/device_definition_grpc.pb.go b/pkg/grpc/device_definition_grpc.pb.go index 6598f1f0..4bc84c81 100644 --- a/pkg/grpc/device_definition_grpc.pb.go +++ b/pkg/grpc/device_definition_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v5.26.1 +// - protoc v7.36.1 // source: pkg/grpc/device_definition.proto package grpc @@ -22,11 +22,8 @@ const _ = grpc.SupportPackageIsVersion7 const ( DeviceDefinitionService_GetIntegrations_FullMethodName = "/grpc.DeviceDefinitionService/GetIntegrations" DeviceDefinitionService_GetIntegrationByID_FullMethodName = "/grpc.DeviceDefinitionService/GetIntegrationByID" - DeviceDefinitionService_CreateDeviceDefinition_FullMethodName = "/grpc.DeviceDefinitionService/CreateDeviceDefinition" DeviceDefinitionService_CreateDeviceStyle_FullMethodName = "/grpc.DeviceDefinitionService/CreateDeviceStyle" DeviceDefinitionService_CreateIntegration_FullMethodName = "/grpc.DeviceDefinitionService/CreateIntegration" - DeviceDefinitionService_UpdateDeviceDefinition_FullMethodName = "/grpc.DeviceDefinitionService/UpdateDeviceDefinition" - DeviceDefinitionService_GetFilteredDeviceDefinition_FullMethodName = "/grpc.DeviceDefinitionService/GetFilteredDeviceDefinition" DeviceDefinitionService_GetDeviceStyleByID_FullMethodName = "/grpc.DeviceDefinitionService/GetDeviceStyleByID" DeviceDefinitionService_GetDeviceStyleByExternalID_FullMethodName = "/grpc.DeviceDefinitionService/GetDeviceStyleByExternalID" DeviceDefinitionService_GetDeviceStylesByDeviceDefinitionID_FullMethodName = "/grpc.DeviceDefinitionService/GetDeviceStylesByDeviceDefinitionID" @@ -48,11 +45,8 @@ const ( type DeviceDefinitionServiceClient interface { GetIntegrations(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetIntegrationResponse, error) GetIntegrationByID(ctx context.Context, in *GetIntegrationRequest, opts ...grpc.CallOption) (*Integration, error) - CreateDeviceDefinition(ctx context.Context, in *CreateDeviceDefinitionRequest, opts ...grpc.CallOption) (*CreateDeviceDefinitionResponse, error) CreateDeviceStyle(ctx context.Context, in *CreateDeviceStyleRequest, opts ...grpc.CallOption) (*BaseResponse, error) CreateIntegration(ctx context.Context, in *CreateIntegrationRequest, opts ...grpc.CallOption) (*BaseResponse, error) - UpdateDeviceDefinition(ctx context.Context, in *UpdateDeviceDefinitionRequest, opts ...grpc.CallOption) (*BaseResponse, error) - GetFilteredDeviceDefinition(ctx context.Context, in *FilterDeviceDefinitionRequest, opts ...grpc.CallOption) (*GetFilteredDeviceDefinitionsResponse, error) GetDeviceStyleByID(ctx context.Context, in *GetDeviceStyleByIDRequest, opts ...grpc.CallOption) (*DeviceStyle, error) GetDeviceStyleByExternalID(ctx context.Context, in *GetDeviceStyleByIDRequest, opts ...grpc.CallOption) (*DeviceStyle, error) GetDeviceStylesByDeviceDefinitionID(ctx context.Context, in *GetDeviceStyleByDeviceDefinitionIDRequest, opts ...grpc.CallOption) (*GetDeviceStyleResponse, error) @@ -94,15 +88,6 @@ func (c *deviceDefinitionServiceClient) GetIntegrationByID(ctx context.Context, return out, nil } -func (c *deviceDefinitionServiceClient) CreateDeviceDefinition(ctx context.Context, in *CreateDeviceDefinitionRequest, opts ...grpc.CallOption) (*CreateDeviceDefinitionResponse, error) { - out := new(CreateDeviceDefinitionResponse) - err := c.cc.Invoke(ctx, DeviceDefinitionService_CreateDeviceDefinition_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *deviceDefinitionServiceClient) CreateDeviceStyle(ctx context.Context, in *CreateDeviceStyleRequest, opts ...grpc.CallOption) (*BaseResponse, error) { out := new(BaseResponse) err := c.cc.Invoke(ctx, DeviceDefinitionService_CreateDeviceStyle_FullMethodName, in, out, opts...) @@ -121,24 +106,6 @@ func (c *deviceDefinitionServiceClient) CreateIntegration(ctx context.Context, i return out, nil } -func (c *deviceDefinitionServiceClient) UpdateDeviceDefinition(ctx context.Context, in *UpdateDeviceDefinitionRequest, opts ...grpc.CallOption) (*BaseResponse, error) { - out := new(BaseResponse) - err := c.cc.Invoke(ctx, DeviceDefinitionService_UpdateDeviceDefinition_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *deviceDefinitionServiceClient) GetFilteredDeviceDefinition(ctx context.Context, in *FilterDeviceDefinitionRequest, opts ...grpc.CallOption) (*GetFilteredDeviceDefinitionsResponse, error) { - out := new(GetFilteredDeviceDefinitionsResponse) - err := c.cc.Invoke(ctx, DeviceDefinitionService_GetFilteredDeviceDefinition_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *deviceDefinitionServiceClient) GetDeviceStyleByID(ctx context.Context, in *GetDeviceStyleByIDRequest, opts ...grpc.CallOption) (*DeviceStyle, error) { out := new(DeviceStyle) err := c.cc.Invoke(ctx, DeviceDefinitionService_GetDeviceStyleByID_FullMethodName, in, out, opts...) @@ -262,11 +229,8 @@ func (c *deviceDefinitionServiceClient) GetIntegrationByTokenID(ctx context.Cont type DeviceDefinitionServiceServer interface { GetIntegrations(context.Context, *emptypb.Empty) (*GetIntegrationResponse, error) GetIntegrationByID(context.Context, *GetIntegrationRequest) (*Integration, error) - CreateDeviceDefinition(context.Context, *CreateDeviceDefinitionRequest) (*CreateDeviceDefinitionResponse, error) CreateDeviceStyle(context.Context, *CreateDeviceStyleRequest) (*BaseResponse, error) CreateIntegration(context.Context, *CreateIntegrationRequest) (*BaseResponse, error) - UpdateDeviceDefinition(context.Context, *UpdateDeviceDefinitionRequest) (*BaseResponse, error) - GetFilteredDeviceDefinition(context.Context, *FilterDeviceDefinitionRequest) (*GetFilteredDeviceDefinitionsResponse, error) GetDeviceStyleByID(context.Context, *GetDeviceStyleByIDRequest) (*DeviceStyle, error) GetDeviceStyleByExternalID(context.Context, *GetDeviceStyleByIDRequest) (*DeviceStyle, error) GetDeviceStylesByDeviceDefinitionID(context.Context, *GetDeviceStyleByDeviceDefinitionIDRequest) (*GetDeviceStyleResponse, error) @@ -293,21 +257,12 @@ func (UnimplementedDeviceDefinitionServiceServer) GetIntegrations(context.Contex func (UnimplementedDeviceDefinitionServiceServer) GetIntegrationByID(context.Context, *GetIntegrationRequest) (*Integration, error) { return nil, status.Errorf(codes.Unimplemented, "method GetIntegrationByID not implemented") } -func (UnimplementedDeviceDefinitionServiceServer) CreateDeviceDefinition(context.Context, *CreateDeviceDefinitionRequest) (*CreateDeviceDefinitionResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method CreateDeviceDefinition not implemented") -} func (UnimplementedDeviceDefinitionServiceServer) CreateDeviceStyle(context.Context, *CreateDeviceStyleRequest) (*BaseResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateDeviceStyle not implemented") } func (UnimplementedDeviceDefinitionServiceServer) CreateIntegration(context.Context, *CreateIntegrationRequest) (*BaseResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateIntegration not implemented") } -func (UnimplementedDeviceDefinitionServiceServer) UpdateDeviceDefinition(context.Context, *UpdateDeviceDefinitionRequest) (*BaseResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UpdateDeviceDefinition not implemented") -} -func (UnimplementedDeviceDefinitionServiceServer) GetFilteredDeviceDefinition(context.Context, *FilterDeviceDefinitionRequest) (*GetFilteredDeviceDefinitionsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetFilteredDeviceDefinition not implemented") -} func (UnimplementedDeviceDefinitionServiceServer) GetDeviceStyleByID(context.Context, *GetDeviceStyleByIDRequest) (*DeviceStyle, error) { return nil, status.Errorf(codes.Unimplemented, "method GetDeviceStyleByID not implemented") } @@ -397,24 +352,6 @@ func _DeviceDefinitionService_GetIntegrationByID_Handler(srv interface{}, ctx co return interceptor(ctx, in, info, handler) } -func _DeviceDefinitionService_CreateDeviceDefinition_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(CreateDeviceDefinitionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(DeviceDefinitionServiceServer).CreateDeviceDefinition(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: DeviceDefinitionService_CreateDeviceDefinition_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(DeviceDefinitionServiceServer).CreateDeviceDefinition(ctx, req.(*CreateDeviceDefinitionRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _DeviceDefinitionService_CreateDeviceStyle_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(CreateDeviceStyleRequest) if err := dec(in); err != nil { @@ -451,42 +388,6 @@ func _DeviceDefinitionService_CreateIntegration_Handler(srv interface{}, ctx con return interceptor(ctx, in, info, handler) } -func _DeviceDefinitionService_UpdateDeviceDefinition_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UpdateDeviceDefinitionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(DeviceDefinitionServiceServer).UpdateDeviceDefinition(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: DeviceDefinitionService_UpdateDeviceDefinition_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(DeviceDefinitionServiceServer).UpdateDeviceDefinition(ctx, req.(*UpdateDeviceDefinitionRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _DeviceDefinitionService_GetFilteredDeviceDefinition_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(FilterDeviceDefinitionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(DeviceDefinitionServiceServer).GetFilteredDeviceDefinition(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: DeviceDefinitionService_GetFilteredDeviceDefinition_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(DeviceDefinitionServiceServer).GetFilteredDeviceDefinition(ctx, req.(*FilterDeviceDefinitionRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _DeviceDefinitionService_GetDeviceStyleByID_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetDeviceStyleByIDRequest) if err := dec(in); err != nil { @@ -736,10 +637,6 @@ var DeviceDefinitionService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetIntegrationByID", Handler: _DeviceDefinitionService_GetIntegrationByID_Handler, }, - { - MethodName: "CreateDeviceDefinition", - Handler: _DeviceDefinitionService_CreateDeviceDefinition_Handler, - }, { MethodName: "CreateDeviceStyle", Handler: _DeviceDefinitionService_CreateDeviceStyle_Handler, @@ -748,14 +645,6 @@ var DeviceDefinitionService_ServiceDesc = grpc.ServiceDesc{ MethodName: "CreateIntegration", Handler: _DeviceDefinitionService_CreateIntegration_Handler, }, - { - MethodName: "UpdateDeviceDefinition", - Handler: _DeviceDefinitionService_UpdateDeviceDefinition_Handler, - }, - { - MethodName: "GetFilteredDeviceDefinition", - Handler: _DeviceDefinitionService_GetFilteredDeviceDefinition_Handler, - }, { MethodName: "GetDeviceStyleByID", Handler: _DeviceDefinitionService_GetDeviceStyleByID_Handler, diff --git a/settings.sample.yaml b/settings.sample.yaml index f377c957..eeab0a2b 100644 --- a/settings.sample.yaml +++ b/settings.sample.yaml @@ -42,17 +42,14 @@ DAT_GROUP_CUSTOMER_PASSWORD: xxx DAT_GROUP_INTERFACE_PARTNER_NUMBER: xxx DAT_GROUP_INTERFACE_PARTNER_SIGNATURE: xxx # Hardhat default port. -ETHEREUM_RPC_URL: http://127.0.0.1:8545 # Use the next variable. Never use this in production! -PRIVATE_KEY_MODE: true # localhost Private key for default Hardhat account 0. Well-known. -SENDER_PRIVATE_KEY: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 -ETHEREUM_REGISTRY_ADDRESS: 0xdc64a140aa3e981100a9beca4e685f962f0cf6c9 # Send transaction to etherum network -ETHEREUM_SEND_TRANSACTION: true -TABLELAND_API_GATEWAY: http://localhost:8080/ +DEFINITIONS_CATALOG_URL: https://definitions.dev.dimo.org +DEFINITIONS_WORKER_URL: "" +DEFINITIONS_WORKER_TOKEN: "" SEARCH_SERVICE_API_URL: http://localhost:8108/ SEARCH_SERVICE_API_KEY: xyz -SEARCH_SERVICE_DEVICE_DEFINITION_INDEX: definitions_dev +SEARCH_SERVICE_DEVICE_DEFINITION_INDEX: definitions_v2_dev JAPAN17_VIN_USER: '' JAPAN17_VIN_PASSWORD: '' \ No newline at end of file