package mongo import ( "context" "strconv" "strings" "sync" "time" "github.com/fiskerinc/cloud-services/pkg/common" "github.com/fiskerinc/cloud-services/pkg/logger" "github.com/pkg/errors" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" ) type DTCCollectionInterface interface { GetDTCDefinitionByHexString(troubleCodeHex string) (info common.DTCInformation, err error) GetLatestPDXVersions() (latestVersion PDXVersion, err error) } var ( pdxMongodbOnce sync.Once pdxMongodbInstance *DTCCollection ) type DTCCollection struct { CollectionInterface Client *mongo.Client DB *mongo.Database } func GetPDXMongoClient() (*DTCCollection, error) { var err error pdxMongodbOnce.Do(func() { logger.Info().Msg("init MongoDB instance") pdxMongodbInstance = &DTCCollection{} var cl *mongo.Client var db *mongo.Database cl, db, err = NewMongoConnection(ODXDB) pdxMongodbInstance.Client = cl pdxMongodbInstance.DB = db }) return pdxMongodbInstance, err } // Given a Hex String for 3 bytes, get the dtc information from mongo func (coll *DTCCollection) GetDTCDefinitionByHexString(troubleCodeHex string, ecuSource string) (info *common.DTCInformation, err error) { if replacement, exist := common.CarDTCLookupInverse[ecuSource]; exist { ecuSource = replacement } collect := coll.DB.Collection("dtc_lookup") //db.dtc_lookup.aggregate({"$match": {"ecuName": "ECU", "DtcUniqueId": "V2.6.0"}}, {"$unwind": "$dtcData.DtcList"}, {"$match": {"dtcData.DtcList.TroubleCodeHex":"800156"}}, {"$project":{"_id": 0, "Obj": "$dtcData.DtcList"}}) pdxVersion, err := coll.GetLatestPDXVersions() if err != nil { return } a := bson.D{} if ecuSource == "AMP" { a = bson.D{{"$match", bson.D{{"ecuName", bson.M{"$in": []string{"AMPSO", "AMPHA"}}}, {"DtcUniqueId", pdxVersion.PDXVersion}}}} } else { a = bson.D{{"$match", bson.D{{"ecuName", ecuSource}, {"DtcUniqueId", pdxVersion.PDXVersion}}}} } b := bson.D{{"$unwind", "$dtcData.DtcList"}} c := bson.D{{"$match", bson.D{{"dtcData.DtcList.TroubleCodeHex", troubleCodeHex}}}} d := bson.D{{"$project", bson.D{{"_id", 0}, {"Obj", "$dtcData.DtcList"}}}} cursor, err := collect.Aggregate(context.Background(), mongo.Pipeline{a, b, c, d}) if err != nil { err = errors.WithStack(err) logger.Err(err).Msg("Failed to call aggregate in GetDTCDefinitionByHexString") return } var obj DTCOuterObj for cursor.Next(context.Background()) { err = cursor.Decode(&obj) if err != nil { err = errors.WithStack(err) logger.Err(err).Msg("Failed to decode mongo object into DTCInformation") return } info = &obj.DTCInformation } return } // This value should be cached for a period of time func (coll *DTCCollection) GetLatestPDXVersions() (latestVersion PDXVersion, err error) { //db.vod_lookup.aggregate({"$project": {"VodUniqueId": 1, "createDate": 1, "updateDate": 1}}) collect := coll.DB.Collection("vod_lookup") a := bson.D{{"$project", bson.D{{"VodUniqueId", 1}, {"createDate", 1}, {"updateDate", 1}, {"_id", 0}}}} cursor, err := collect.Aggregate(context.Background(), mongo.Pipeline{a}) if err != nil { err = errors.WithStack(err) logger.Err(err).Msg("") return } // Need to determine the latest version for cursor.Next(context.Background()) { var ag PDXVersion err = cursor.Decode(&ag) if err != nil { err = errors.WithStack(err) logger.Err(err).Msg("") return } if isVersionNewer(latestVersion.PDXVersion, ag.PDXVersion) { latestVersion = ag } } return } // Give the one we have as the newest, and then the new value to compare to func isVersionNewer(lastNewest, newPossibleNewest string) (isNewer bool) { // Better algorithm, turn V1.3.2.1 => 1321 and add any 0's on the end if the other number is longer if lastNewest == "" { return true } // Remove the V lastNewest = lastNewest[1:] newPossibleNewest = newPossibleNewest[1:] last := strings.Split(lastNewest, ".") new := strings.Split(newPossibleNewest, ".") for x := 0; x < len(last); x++ { // We have gotten to the end of the second string without being less, so we are greater, like a hotfix if x >= len(new) { return false } l, _ := strconv.Atoi(last[x]) n, _ := strconv.Atoi(new[x]) if n > l { return true } else if l > n { return false } } return len(new) > len(last) } type DTCOuterObj struct { common.DTCInformation `bson:"Obj"` } type PDXVersion struct { PDXVersion string `bson:"VodUniqueId"` CreatedTime time.Time `bson:"createDate"` UpdatedTime time.Time `bson:"updateDate"` }