package mongo import ( "context" "errors" "fmt" "fwh-toolbox-server/database" "fwh-toolbox-server/domain" "time" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) const ( CollectionName_AutoUpdateConfigOption = "AutoUpdateConfigOption" CollectionName_AutoUpdateConfig = "AutoUpdateConfig" CollectionName_AutoUpdateAPowerVersion = "AutoUpdateAPowerVersion" CollectionName_AutoUpdatePackages = "AutoUpdatePackages" ) /**************** 自动升级配置选项 ****************/ // 读取自动升级配置的选项 func GetAutoUpdateConfigOption() (*domain.AutoUpdateConfigOption, error) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdateConfigOption) update := bson.M{ "$setOnInsert": bson.M{ "_id": "options", "packages": domain.AutoUpdatePackagesOption{ System: []string{}, AGate: []string{}, SubDevice: []string{}, Others: []string{}, }, "aGateVersions": []string{}, }, } opts := options.FindOneAndUpdate(). SetUpsert(true). SetReturnDocument(options.After) var cfg domain.AutoUpdateConfigOption err := collection.FindOneAndUpdate(ctx, bson.M{"_id": "options"}, update, opts).Decode(&cfg) if err != nil { return nil, err } return &cfg, nil } func insertPackageInfoToOption(packageType string, fileName string) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdateConfigOption) var opt bson.M filter := bson.M{"_id": "options"} if err := collection.FindOne( ctx, filter, options.FindOne(). SetProjection(bson.M{"packages." + packageType: 1}), ).Decode(&opt); err != nil && err != mongo.ErrNoDocuments { // 没有匹配的文档 return err } newPackages := []string{} originalPackages, ok := opt["packages"].(bson.M) if ok { switch packageType { case "system": if packageList, ok := originalPackages["system"].([]string); ok { newPackages = append(packageList, fileName) } case "aGate": if packageList, ok := originalPackages["aGate"].([]string); ok { newPackages = append(packageList, fileName) } case "subDevice": if packageList, ok := originalPackages["subDevice"].([]string); ok { newPackages = append(packageList, fileName) } case "others": if packageList, ok := originalPackages["others"].([]string); ok { newPackages = append(packageList, fileName) } default: return fmt.Errorf("packageType unknown. packageType = %s", packageType) } } update := bson.M{ "$set": bson.M{ "packages." + packageType: newPackages, }, "$setOnInsert": bson.M{ "_id": "options", "aGateVersions": []string{}, }, } opts := options.Update().SetUpsert(true) _, err := collection.UpdateOne(ctx, filter, update, opts) return err } func deletePackageInfoByOption(packageType string, fileName string) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdateConfigOption) var opt bson.M filter := bson.M{"_id": "options"} if err := collection.FindOne( ctx, filter, options.FindOne(). SetProjection(bson.M{"packages." + packageType: 1}), ).Decode(&opt); err != nil && err != mongo.ErrNoDocuments { // 没有匹配的文档 return err } packages := []string{} originalPackages, ok := opt["packages"].(bson.M) if ok { switch packageType { case "system": if packageList, ok := originalPackages["system"].([]string); ok { packages = packageList } case "aGate": if packageList, ok := originalPackages["aGate"].([]string); ok { packages = packageList } case "subDevice": if packageList, ok := originalPackages["subDevice"].([]string); ok { packages = packageList } case "others": if packageList, ok := originalPackages["others"].([]string); ok { packages = packageList } default: return fmt.Errorf("packageType unknown. packageType = %s", packageType) } } newPackages := []string{} for _, file := range packages { if file == fileName { continue } newPackages = append(newPackages, file) } if len(packages) == len(newPackages) { return fmt.Errorf("package option delete failed. fileName = %s", fileName) } update := bson.M{ "$set": bson.M{ "packages." + packageType: newPackages, }, } _, err := collection.UpdateOne(ctx, filter, update) return err } func insertAGateVersionToOption(aGateVersion string) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdateConfigOption) var opt bson.M filter := bson.M{"_id": "options"} if err := collection.FindOne( ctx, filter, options.FindOne(). SetProjection(bson.M{"aGateVersions": 1}), ).Decode(&opt); err != nil && err != mongo.ErrNoDocuments { // 没有匹配的文档 return err } versionList, ok := opt["aGateVersions"].([]string) if !ok { versionList = []string{} } for _, s := range versionList { if s == aGateVersion { return fmt.Errorf("aGateVersion(%s) already exists", aGateVersion) } } versionList = append(versionList, aGateVersion) update := bson.M{ "$set": bson.M{ "aGateVersions": versionList, }, "$setOnInsert": bson.M{ "_id": "options", "packages": domain.AutoUpdatePackagesOption{ System: []string{}, AGate: []string{}, SubDevice: []string{}, Others: []string{}, }, }, } opts := options.Update().SetUpsert(true) _, err := collection.UpdateOne(ctx, filter, update, opts) return err } func deleteAGateVersionByOption(aGateVersion string) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdateConfigOption) var opt bson.M filter := bson.M{"_id": "options"} if err := collection.FindOne( ctx, filter, options.FindOne(). SetProjection(bson.M{"aGateVersions": 1}), ).Decode(&opt); err != nil && err != mongo.ErrNoDocuments { // 没有匹配的文档 return err } versionList, ok := opt["aGateVersions"].([]string) if !ok { return nil } newVersions := []string{} for _, ver := range versionList { if ver == aGateVersion { continue } newVersions = append(newVersions, ver) } if len(versionList) == len(newVersions) { return fmt.Errorf("package option delete failed. aGateVersion = %s", aGateVersion) } update := bson.M{ "$set": bson.M{ "aGateVersions": newVersions, }, } _, err := collection.UpdateOne(ctx, filter, update) return err } /**************** 自动升级包信息 ****************/ func GetAutoUpdatePackages(fileName string) (*domain.AutoUpdatePackages, error) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdatePackages) var cfg domain.AutoUpdatePackages err := collection.FindOne(ctx, bson.M{"_id": fileName}).Decode(&cfg) if err != nil { return nil, err } return &cfg, nil } func CreateAutoUpdatePackage(packageType string, info domain.AutoUpdatePackages) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdatePackages) // 依赖数据库唯一索引 if _, err := collection.InsertOne(ctx, &info); err != nil { if mongo.IsDuplicateKeyError(err) { return errors.New("user already exists") } return fmt.Errorf("insert failed: %w", err) } // 插入分类表 if err := insertPackageInfoToOption(packageType, info.Id); err != nil { // 插入失败,删除创建数据信息 if _, delErr := collection.DeleteOne(ctx, bson.M{"_id": info.Id}); delErr != nil { return fmt.Errorf("insert option failed: %w, delete failed: %w", err, delErr) } return fmt.Errorf("insert option failed: %w", err) } return nil } func UpdateAutoUpdatePackage(fileName string, info domain.AutoUpdatePackages) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdatePackages) res, err := collection.UpdateOne(ctx, bson.M{"_id": fileName}, bson.M{"$set": bson.M{ "title": info.Title, "invVersion": info.InvVersion, }}) if err != nil { return fmt.Errorf("update failed: %w", err) } if res.MatchedCount == 0 { return errors.New("file name not found, update rejected") } return nil } func DeleteAutoUpdatePackage(packageType string, fileName string) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdatePackages) // 删除分类表中的文件名 if err := deletePackageInfoByOption(packageType, fileName); err != nil { return fmt.Errorf("delete option failed: %w", err) } if _, err := collection.DeleteOne(ctx, bson.M{"_id": fileName}); err != nil { return fmt.Errorf("delete package info failed: %w", err) } return nil } /**************** 自动升级aPower版本信息 ****************/ func GetAutoUpdateAPowerVersion() (*[]domain.AutoUpdateAPowerVersion, error) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdateAPowerVersion) cursor, err := collection.Find(ctx, bson.M{}) if err != nil { return nil, err } defer cursor.Close(ctx) var versionList []domain.AutoUpdateAPowerVersion if err := cursor.All(ctx, &versionList); err != nil { return nil, err } if versionList == nil { versionList = []domain.AutoUpdateAPowerVersion{} } return &versionList, nil } func UpdateAutoUpdateAPowerVersion(version string, info domain.AutoUpdateAPowerVersion) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdateAPowerVersion) filter := bson.M{"_id": version} update := bson.M{ "$set": bson.M{ "name": info.Name, "remark": info.Remark, }, "$setOnInsert": bson.M{ "_id": version, }, } opts := options.Update().SetUpsert(true) _, err := collection.UpdateOne(ctx, filter, update, opts) if err != nil { return err } return nil } func DeleteAutoUpdateAPowerVersion(version string) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdateAPowerVersion) _, err := collection.DeleteOne(ctx, bson.M{"_id": version}) if err != nil { return err } return nil } /**************** 自动升级配置 ****************/ func GetAutoUpdateConfig(aGateVersions string) (*domain.AutoUpdateConfig, error) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdateConfig) var cfg domain.AutoUpdateConfig err := collection.FindOne(ctx, bson.M{"_id": aGateVersions}).Decode(&cfg) if err != nil { return nil, err } return &cfg, nil } func UpdateAutoUpdateConfig(aGateVersions string, config domain.AutoUpdateConfig) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdateConfig) filter := bson.M{"_id": aGateVersions} update := bson.M{ "$set": bson.M{ "config": config.Config, }, "$setOnInsert": bson.M{ "_id": aGateVersions, }, } opts := options.Update().SetUpsert(true) result, err := collection.UpdateOne(ctx, filter, update, opts) if err != nil { return err } if result.UpsertedCount > 0 { // 插入操作 // 添加aGate名到option表 if err := insertAGateVersionToOption(aGateVersions); err != nil { // 插入失败,删除创建数据信息 if _, delErr := collection.DeleteOne(ctx, filter); delErr != nil { return fmt.Errorf("insert option failed: %w, delete failed: %w", err, delErr) } return fmt.Errorf("insert option failed: %w", err) } } return nil } func DeleteAutoUpdateConfig(aGateVersions string) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdateConfig) // 删除分类表中的版本 if err := deleteAGateVersionByOption(aGateVersions); err != nil { return fmt.Errorf("delete option failed: %w", err) } _, err := collection.DeleteOne(ctx, bson.M{"_id": aGateVersions}) if err != nil { return err } return nil } func CreateAutoUpdateSpecialConfig(aGateVersions string, config domain.AutoUpdateSpecialTypeConfig) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdateConfig) filter := bson.M{"_id": aGateVersions} item := bson.M{ "id": primitive.NewObjectID().Hex(), "title": config.Title, "emsVersions": config.EmsVersions, "aPowerVersions": config.APowerVersions, "specialUpdateOrder": config.SpecialUpdateOrder, "useDefaultUpdate": config.UseDefaultUpdate, } update := bson.M{ "$push": bson.M{ "config.specialType": item, }, } _, err := collection.UpdateOne(ctx, filter, update) if err != nil { return err } return nil } func DeleteAutoUpdateSpecialConfig(aGateVersions string, id string) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() collection := database.GetCollection(CollectionName_AutoUpdateConfig) filter := bson.M{"_id": aGateVersions} update := bson.M{ "$pull": bson.M{ "config.specialType": bson.M{ "id": id, }, }, } _, err := collection.UpdateOne(ctx, filter, update) if err != nil { return err } return nil }