|
|
@@ -4,16 +4,22 @@ import (
|
|
|
"context"
|
|
|
"errors"
|
|
|
"fmt"
|
|
|
+ "sort"
|
|
|
"strconv"
|
|
|
+ "strings"
|
|
|
"time"
|
|
|
|
|
|
"dsbqj-admin/app/task"
|
|
|
+ "dsbqj-admin/model/mongo/abver"
|
|
|
+ "dsbqj-admin/model/mongo/md5"
|
|
|
"dsbqj-admin/model/mongo/version"
|
|
|
"dsbqj-admin/tool"
|
|
|
|
|
|
"github.com/kamva/mgm/v3"
|
|
|
"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 versionExternalReqTimeoutSec = 30 * 60
|
|
|
@@ -27,54 +33,93 @@ func (service *VersionReloadService) Reload() error {
|
|
|
}
|
|
|
|
|
|
type VersionServerService struct {
|
|
|
- Channel string `json:"channel" binding:"required"`
|
|
|
+ Platform string `json:"platform"`
|
|
|
+ LegacyChannel string `json:"channel"`
|
|
|
}
|
|
|
|
|
|
func (service *VersionServerService) Servers() ([]*version.Version, error) {
|
|
|
- return task.VersionTask.Servers(service.Channel), nil
|
|
|
+ platform := resolvePlatform(service.Platform, service.LegacyChannel)
|
|
|
+ if platform == "" {
|
|
|
+ return nil, errors.New("平台不能为空")
|
|
|
+ }
|
|
|
+ items := task.VersionTask.Servers(platform)
|
|
|
+ result := make([]*version.Version, 0, len(items))
|
|
|
+ for _, item := range items {
|
|
|
+ result = append(result, versionWithConfig(item, platform, task.NormalizeEnvVersion(item.EnvVersion)))
|
|
|
+ }
|
|
|
+ return result, nil
|
|
|
}
|
|
|
|
|
|
type VersionCheckService struct {
|
|
|
- Version string `json:"version" binding:"required"`
|
|
|
- Channel string `json:"channel" binding:"required"`
|
|
|
- EnvVersion string `json:"envVersion"`
|
|
|
+ Version string `json:"version"`
|
|
|
+ Platform string `json:"platform"`
|
|
|
+ LegacyChannel string `json:"channel"`
|
|
|
+ EnvVersion string `json:"envVersion"`
|
|
|
}
|
|
|
|
|
|
func (service *VersionCheckService) Check() (*version.Version, error) {
|
|
|
- return task.VersionTask.Check(service.Version, service.Channel, service.EnvVersion), nil
|
|
|
+ platform := resolvePlatform(service.Platform, service.LegacyChannel)
|
|
|
+ if platform == "" {
|
|
|
+ return nil, errors.New("平台不能为空")
|
|
|
+ }
|
|
|
+ result := task.VersionTask.Check(service.Version, platform, service.EnvVersion)
|
|
|
+ if result == nil {
|
|
|
+ return nil, nil
|
|
|
+ }
|
|
|
+ return versionWithConfig(result, platform, task.NormalizeEnvVersion(result.EnvVersion)), nil
|
|
|
+}
|
|
|
+
|
|
|
+func versionWithConfig(item *version.Version, platform, env string) *version.Version {
|
|
|
+ result := *item
|
|
|
+ abVer := task.VersionConfigTask.GetAbVer(platform, env)
|
|
|
+ md5 := task.VersionConfigTask.GetMD5(platform, env)
|
|
|
+ result.AbVer, result.AbVerVersion = abVer.Value, abVer.Version
|
|
|
+ result.MD5, result.MD5Version = md5.Value, md5.Version
|
|
|
+ return &result
|
|
|
+}
|
|
|
+
|
|
|
+func resolvePlatform(platform, legacyChannel string) string {
|
|
|
+ if value := strings.TrimSpace(platform); value != "" {
|
|
|
+ return value
|
|
|
+ }
|
|
|
+ return strings.TrimSpace(legacyChannel)
|
|
|
}
|
|
|
|
|
|
type VersionShowService struct {
|
|
|
CondPage
|
|
|
- Channel string `form:"channel" json:"channel"`
|
|
|
+ Platform string `form:"platform" json:"platform"`
|
|
|
EnvVersion string `form:"envVersion" json:"envVersion"`
|
|
|
}
|
|
|
|
|
|
func (service *VersionShowService) List() ([]version.Version, error) {
|
|
|
versions := make([]version.Version, 0)
|
|
|
var queryDoc = bson.M{}
|
|
|
- if service.Channel != "" {
|
|
|
- queryDoc["channel"] = service.Channel
|
|
|
+ clauses := make([]bson.M, 0, 2)
|
|
|
+ if service.Platform != "" {
|
|
|
+ clauses = append(clauses, bson.M{"$or": []bson.M{{"platform": service.Platform}, {"platform": ""}, {"platform": bson.M{"$exists": false}}}})
|
|
|
}
|
|
|
if service.EnvVersion != "" {
|
|
|
envVersion := task.NormalizeEnvVersion(service.EnvVersion)
|
|
|
if envVersion == "release" {
|
|
|
- queryDoc["$or"] = []bson.M{
|
|
|
+ clauses = append(clauses, bson.M{"$or": []bson.M{
|
|
|
{"envVersion": envVersion},
|
|
|
{"envVersion": ""},
|
|
|
{"envVersion": bson.M{"$exists": false}},
|
|
|
- }
|
|
|
+ }})
|
|
|
} else {
|
|
|
- queryDoc["envVersion"] = envVersion
|
|
|
+ clauses = append(clauses, bson.M{"envVersion": envVersion})
|
|
|
}
|
|
|
}
|
|
|
+ if len(clauses) > 0 {
|
|
|
+ queryDoc["$and"] = clauses
|
|
|
+ }
|
|
|
|
|
|
err := mgm.Coll(&version.Version{}).SimpleFind(&versions, queryDoc)
|
|
|
return versions, err
|
|
|
}
|
|
|
|
|
|
type VersionCreateService struct {
|
|
|
- Channel string `json:"channel" binding:"required"`
|
|
|
+ Platform string `json:"platform" binding:"required"`
|
|
|
EnvVersion string `json:"envVersion"`
|
|
|
Version string `json:"version" binding:"required"`
|
|
|
Name string `json:"name" binding:"required"`
|
|
|
@@ -83,20 +128,33 @@ type VersionCreateService struct {
|
|
|
}
|
|
|
|
|
|
func (service *VersionCreateService) Create() error {
|
|
|
+ envVersion := task.NormalizeEnvVersion(service.EnvVersion)
|
|
|
+ var exists version.Version
|
|
|
+ err := mgm.Coll(&version.Version{}).First(versionIdentityFilter(service.Platform, service.Version, envVersion), &exists)
|
|
|
+ if err == nil {
|
|
|
+ return errors.New("该平台、环境和版本号已存在")
|
|
|
+ }
|
|
|
+ if !errors.Is(err, mongo.ErrNoDocuments) {
|
|
|
+ return err
|
|
|
+ }
|
|
|
version := new(version.Version)
|
|
|
- version.Channel = service.Channel
|
|
|
- version.EnvVersion = task.NormalizeEnvVersion(service.EnvVersion)
|
|
|
+ version.Platform = service.Platform
|
|
|
+ version.EnvVersion = envVersion
|
|
|
version.Name = service.Name
|
|
|
version.Version = service.Version
|
|
|
version.CDN = service.CDN
|
|
|
version.Url = service.Url
|
|
|
|
|
|
- return mgm.Coll(version).Create(version)
|
|
|
+ if err := mgm.Coll(version).Create(version); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ task.VersionTask.Exec()
|
|
|
+ return nil
|
|
|
}
|
|
|
|
|
|
type VersionEditService struct {
|
|
|
Id string `json:"id" binding:"required"`
|
|
|
- Channel *string `json:"channel"`
|
|
|
+ Platform *string `json:"platform"`
|
|
|
EnvVersion *string `json:"envVersion"`
|
|
|
Version *string `json:"version"`
|
|
|
Name *string `json:"name"`
|
|
|
@@ -106,36 +164,71 @@ type VersionEditService struct {
|
|
|
}
|
|
|
|
|
|
func (service *VersionEditService) Edit() error {
|
|
|
- version := new(version.Version)
|
|
|
-
|
|
|
objectId, _ := primitive.ObjectIDFromHex(service.Id)
|
|
|
+ coll := mgm.Coll(&version.Version{})
|
|
|
+ var current version.Version
|
|
|
+ if err := coll.FindByID(objectId, ¤t); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ platform, envVersion, versionNumber := current.Platform, task.NormalizeEnvVersion(current.EnvVersion), current.Version
|
|
|
+ if service.Platform != nil {
|
|
|
+ platform = strings.TrimSpace(*service.Platform)
|
|
|
+ }
|
|
|
+ if service.EnvVersion != nil {
|
|
|
+ envVersion = task.NormalizeEnvVersion(*service.EnvVersion)
|
|
|
+ }
|
|
|
+ if service.Version != nil {
|
|
|
+ versionNumber = *service.Version
|
|
|
+ }
|
|
|
+ var duplicate version.Version
|
|
|
+ duplicateFilter := versionIdentityFilter(platform, versionNumber, envVersion)
|
|
|
+ duplicateFilter["_id"] = bson.M{"$ne": objectId}
|
|
|
+ if err := coll.First(duplicateFilter, &duplicate); err == nil {
|
|
|
+ return errors.New("该平台、环境和版本号已存在")
|
|
|
+ } else if !errors.Is(err, mongo.ErrNoDocuments) {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
filterDoc := bson.M{"_id": objectId}
|
|
|
updateDoc := bson.M{}
|
|
|
- if service.Channel != nil {
|
|
|
- updateDoc["channel"] = service.Channel
|
|
|
+ if service.Platform != nil {
|
|
|
+ updateDoc["platform"] = platform
|
|
|
}
|
|
|
if service.EnvVersion != nil {
|
|
|
updateDoc["envVersion"] = task.NormalizeEnvVersion(*service.EnvVersion)
|
|
|
}
|
|
|
if service.Name != nil {
|
|
|
- updateDoc["name"] = service.Name
|
|
|
+ updateDoc["name"] = *service.Name
|
|
|
}
|
|
|
if service.Version != nil {
|
|
|
- updateDoc["version"] = service.Version
|
|
|
+ updateDoc["version"] = *service.Version
|
|
|
}
|
|
|
if service.CDN != nil {
|
|
|
- updateDoc["cdn"] = service.CDN
|
|
|
+ updateDoc["cdn"] = *service.CDN
|
|
|
}
|
|
|
if service.Url != nil {
|
|
|
- updateDoc["url"] = service.Url
|
|
|
+ updateDoc["url"] = *service.Url
|
|
|
}
|
|
|
if service.Default != nil {
|
|
|
- updateDoc["default"] = service.Default
|
|
|
+ updateDoc["default"] = *service.Default
|
|
|
}
|
|
|
|
|
|
- _, err := mgm.Coll(version).UpdateOne(context.Background(), filterDoc, bson.M{"$set": updateDoc})
|
|
|
+ _, err := coll.UpdateOne(context.Background(), filterDoc, bson.M{"$set": updateDoc})
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ task.VersionTask.Exec()
|
|
|
+ return nil
|
|
|
+}
|
|
|
|
|
|
- return err
|
|
|
+func versionIdentityFilter(platform, versionNumber, envVersion string) bson.M {
|
|
|
+ filter := bson.M{"platform": platform, "version": versionNumber}
|
|
|
+ if task.NormalizeEnvVersion(envVersion) == "release" {
|
|
|
+ filter["$or"] = []bson.M{{"envVersion": "release"}, {"envVersion": ""}, {"envVersion": bson.M{"$exists": false}}}
|
|
|
+ } else {
|
|
|
+ filter["envVersion"] = "trial"
|
|
|
+ }
|
|
|
+ return filter
|
|
|
}
|
|
|
|
|
|
type VersionProdService struct {
|
|
|
@@ -156,9 +249,12 @@ func (service *VersionProdService) Update() error {
|
|
|
}
|
|
|
|
|
|
if service.IsProd {
|
|
|
+ scope := versionIdentityFilter(current.Platform, "", current.EnvVersion)
|
|
|
+ delete(scope, "version")
|
|
|
+ scope["_id"] = bson.M{"$ne": objectId}
|
|
|
if _, err := coll.UpdateMany(
|
|
|
context.Background(),
|
|
|
- bson.M{"_id": bson.M{"$ne": objectId}},
|
|
|
+ scope,
|
|
|
bson.M{"$set": bson.M{"isProd": false}},
|
|
|
); err != nil {
|
|
|
return err
|
|
|
@@ -174,12 +270,143 @@ func (service *VersionProdService) Update() error {
|
|
|
}
|
|
|
|
|
|
type VersionExternalConfigService struct {
|
|
|
- Channel string `form:"channel" json:"channel" binding:"required"`
|
|
|
- Version string `form:"version" json:"version" binding:"required"`
|
|
|
- AbVer *string `form:"abVer" json:"abVer"`
|
|
|
- MD5 *string `form:"md5" json:"md5"`
|
|
|
- TimeSec int64 `form:"timesec" json:"timesec" binding:"required"`
|
|
|
- Sign string `form:"sign" json:"sign" binding:"required"`
|
|
|
+ Platform string `form:"platform" json:"platform" binding:"required"`
|
|
|
+ Version string `form:"version" json:"version" binding:"required"`
|
|
|
+ AbVer *string `form:"abVer" json:"abVer"`
|
|
|
+ MD5 *string `form:"md5" json:"md5"`
|
|
|
+ TimeSec int64 `form:"timesec" json:"timesec" binding:"required"`
|
|
|
+ Sign string `form:"sign" json:"sign" binding:"required"`
|
|
|
+}
|
|
|
+
|
|
|
+type VersionConfigUploadService struct {
|
|
|
+ Platform string `form:"platform" json:"platform" binding:"required"`
|
|
|
+ Version string `form:"version" json:"version" binding:"required"`
|
|
|
+ Value string `form:"value" json:"value" binding:"required"`
|
|
|
+ TimeSec int64 `form:"timesec" json:"timesec" binding:"required"`
|
|
|
+ Sign string `form:"sign" json:"sign" binding:"required"`
|
|
|
+}
|
|
|
+
|
|
|
+type VersionConfigManageService struct {
|
|
|
+ Type string `json:"type" form:"type" binding:"required"`
|
|
|
+ ID string `json:"id"`
|
|
|
+ PlatformFilter string `json:"-"`
|
|
|
+ Version string `json:"version"`
|
|
|
+ Value *string `json:"value"`
|
|
|
+ EnvVersions *[]string `json:"envVersions"`
|
|
|
+ External *bool `json:"external"`
|
|
|
+}
|
|
|
+
|
|
|
+func configCollection(configType string) interface{} {
|
|
|
+ if configType == "md5" {
|
|
|
+ return &md5.MD5{}
|
|
|
+ }
|
|
|
+ return &abver.AbVer{}
|
|
|
+}
|
|
|
+
|
|
|
+func (service *VersionConfigManageService) List() (interface{}, error) {
|
|
|
+ items := make([]interface{}, 0)
|
|
|
+ filter := bson.M{}
|
|
|
+ if service.PlatformFilter != "" {
|
|
|
+ filter["$or"] = []bson.M{{"platform": service.PlatformFilter}, {"platform": ""}, {"platform": bson.M{"$exists": false}}}
|
|
|
+ }
|
|
|
+ if service.Type == "md5" {
|
|
|
+ result := make([]md5.MD5, 0)
|
|
|
+ err := mgm.Coll(&md5.MD5{}).SimpleFind(&result, filter)
|
|
|
+ sort.SliceStable(result, func(i, j int) bool {
|
|
|
+ return task.CompareConfigVersion(result[i].Version, result[j].Version) > 0
|
|
|
+ })
|
|
|
+ for i := range result {
|
|
|
+ items = append(items, result[i])
|
|
|
+ }
|
|
|
+ return items, err
|
|
|
+ }
|
|
|
+ result := make([]abver.AbVer, 0)
|
|
|
+ err := mgm.Coll(&abver.AbVer{}).SimpleFind(&result, filter)
|
|
|
+ sort.SliceStable(result, func(i, j int) bool {
|
|
|
+ return task.CompareConfigVersion(result[i].Version, result[j].Version) > 0
|
|
|
+ })
|
|
|
+ for i := range result {
|
|
|
+ items = append(items, result[i])
|
|
|
+ }
|
|
|
+ return items, err
|
|
|
+}
|
|
|
+
|
|
|
+func (service *VersionConfigManageService) Save() error {
|
|
|
+ if service.ID == "" {
|
|
|
+ return errors.New("配置记录编号不能为空")
|
|
|
+ }
|
|
|
+ id, err := primitive.ObjectIDFromHex(service.ID)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ update := bson.M{}
|
|
|
+ if service.Value != nil {
|
|
|
+ update["value"] = *service.Value
|
|
|
+ }
|
|
|
+ if service.EnvVersions != nil {
|
|
|
+ update["envVersions"] = *service.EnvVersions
|
|
|
+ }
|
|
|
+ if service.External != nil {
|
|
|
+ update["external"] = *service.External
|
|
|
+ }
|
|
|
+ if len(update) == 0 {
|
|
|
+ return errors.New("没有需要更新的内容")
|
|
|
+ }
|
|
|
+ if service.Type == "md5" {
|
|
|
+ _, err = mgm.Coll(&md5.MD5{}).UpdateOne(context.Background(), bson.M{"_id": id}, bson.M{"$set": update})
|
|
|
+ if err == nil {
|
|
|
+ task.VersionConfigTask.Reload()
|
|
|
+ }
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ _, err = mgm.Coll(&abver.AbVer{}).UpdateOne(context.Background(), bson.M{"_id": id}, bson.M{"$set": update})
|
|
|
+ if err == nil {
|
|
|
+ task.VersionConfigTask.Reload()
|
|
|
+ }
|
|
|
+ return err
|
|
|
+}
|
|
|
+
|
|
|
+func (service *VersionConfigUploadService) ValidateAuth() error {
|
|
|
+ deltaTime := time.Now().Unix() - service.TimeSec
|
|
|
+ if deltaTime < 0 {
|
|
|
+ deltaTime = -deltaTime
|
|
|
+ }
|
|
|
+ if deltaTime > versionExternalReqTimeoutSec {
|
|
|
+ return errors.New("时间戳已过期")
|
|
|
+ }
|
|
|
+ params := map[string]any{"platform": service.Platform, "version": service.Version, "value": service.Value, "timesec": strconv.FormatInt(service.TimeSec, 10)}
|
|
|
+ if tool.GenSign(params) != service.Sign {
|
|
|
+ return errors.New("签名错误")
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (service *VersionConfigUploadService) SaveAbVer() error {
|
|
|
+ var exists abver.AbVer
|
|
|
+ filter := bson.M{"platform": service.Platform, "version": service.Version}
|
|
|
+ if err := mgm.Coll(&abver.AbVer{}).First(filter, &exists); err == nil {
|
|
|
+ return errors.New("abVer 配置版本已存在,不能重复上报")
|
|
|
+ }
|
|
|
+ item := &abver.AbVer{Platform: service.Platform, Version: service.Version, Value: service.Value, External: false}
|
|
|
+ _, err := mgm.Coll(item).UpdateOne(context.Background(), filter, bson.M{"$set": item}, options.Update().SetUpsert(true))
|
|
|
+ if err == nil {
|
|
|
+ task.VersionConfigTask.Reload()
|
|
|
+ }
|
|
|
+ return err
|
|
|
+}
|
|
|
+
|
|
|
+func (service *VersionConfigUploadService) SaveMD5() error {
|
|
|
+ var exists md5.MD5
|
|
|
+ filter := bson.M{"platform": service.Platform, "version": service.Version}
|
|
|
+ if err := mgm.Coll(&md5.MD5{}).First(filter, &exists); err == nil {
|
|
|
+ return errors.New("md5 配置版本已存在,不能重复上报")
|
|
|
+ }
|
|
|
+ item := &md5.MD5{Platform: service.Platform, Version: service.Version, Value: service.Value, External: false}
|
|
|
+ _, err := mgm.Coll(item).UpdateOne(context.Background(), filter, bson.M{"$set": item}, options.Update().SetUpsert(true))
|
|
|
+ if err == nil {
|
|
|
+ task.VersionConfigTask.Reload()
|
|
|
+ }
|
|
|
+ return err
|
|
|
}
|
|
|
|
|
|
func (service *VersionExternalConfigService) Save() error {
|
|
|
@@ -188,8 +415,8 @@ func (service *VersionExternalConfigService) Save() error {
|
|
|
}
|
|
|
|
|
|
filterDoc := bson.M{
|
|
|
- "channel": service.Channel,
|
|
|
- "version": service.Version,
|
|
|
+ "platform": service.Platform,
|
|
|
+ "version": service.Version,
|
|
|
}
|
|
|
|
|
|
coll := mgm.Coll(&version.Version{})
|
|
|
@@ -197,10 +424,6 @@ func (service *VersionExternalConfigService) Save() error {
|
|
|
if err := coll.First(filterDoc, ¤t); err != nil {
|
|
|
return errors.New("version not found")
|
|
|
}
|
|
|
- if current.IsProd {
|
|
|
- return errors.New("production version does not allow external upload")
|
|
|
- }
|
|
|
-
|
|
|
updateDoc := bson.M{}
|
|
|
if service.AbVer != nil {
|
|
|
updateDoc["abVer"] = *service.AbVer
|
|
|
@@ -227,9 +450,9 @@ func (service *VersionExternalConfigService) ValidateAuth() error {
|
|
|
}
|
|
|
|
|
|
params := map[string]any{
|
|
|
- "channel": service.Channel,
|
|
|
- "version": service.Version,
|
|
|
- "timesec": strconv.FormatInt(service.TimeSec, 10),
|
|
|
+ "platform": service.Platform,
|
|
|
+ "version": service.Version,
|
|
|
+ "timesec": strconv.FormatInt(service.TimeSec, 10),
|
|
|
}
|
|
|
if service.AbVer != nil {
|
|
|
params["abVer"] = *service.AbVer
|
|
|
@@ -255,5 +478,9 @@ func (service *VersionDeleteService) Delete() error {
|
|
|
filterDoc := bson.M{"_id": objectId}
|
|
|
|
|
|
_, err := mgm.Coll(version).DeleteOne(context.Background(), filterDoc)
|
|
|
- return err
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ task.VersionTask.Exec()
|
|
|
+ return nil
|
|
|
}
|