/** * @author chengliang * @date 2026/1/12 21:55 * @brief * **/ package service import ( "dsbqj-admin/model/mongo/hotupdate" "dsbqj-admin/pkg/logger" "errors" "fmt" "strconv" "strings" "sync" ) type THotUpdateVerManager struct { mu sync.RWMutex versionMap map[string]map[string]*TGetVersionRsp // proj:os:versionInfo versionDB *hotupdate.TVersionDB } var ( verManager *THotUpdateVerManager once sync.Once ) func GetTHotUpdateVerManager() *THotUpdateVerManager { once.Do(func() { verManager = &THotUpdateVerManager{ versionMap: make(map[string]map[string]*TGetVersionRsp), versionDB: hotupdate.NewVersionService(), } }) return verManager } func (this *THotUpdateVerManager) Init() { _, err := this.GetMaxVerInfo("bzst", "ios") if err != nil { logger.Error(err.Error()) } _, err = this.GetMaxVerInfo("bzst", "android") if err != nil { logger.Error(err.Error()) } } func (this *THotUpdateVerManager) GetMaxVerInfo(proj, os string) (*TGetVersionRsp, error) { if proj == "" || os == "" { return nil, errors.New("project or os can't be empty") } if ver, err := this.getVersionMapBy(proj, os); err == nil { return ver, nil } else { versionRsp, err := this.findMaxVersion(proj, os) if err != nil { return nil, err } this.updateVersionMap(proj, os, versionRsp) return versionRsp, nil } } func (this *THotUpdateVerManager) AddVersion(req *TAddVersionReq) error { if !this.isInvalid(req) { return errors.New("version is invalid") } mVersion := &hotupdate.MVersionInfo{ Proj: req.Proj, Os: req.Os, Version: req.Version, PackageUrl: req.PackageUrl, RemoteVersionUrl: req.RemoteVersionUrl, RemoteManifestUrl: req.RemoteManifestUrl, } err := this.versionDB.Create(mVersion) if err != nil { return err } verRsp := &TGetVersionRsp{ Version: req.Version, PackageUrl: req.PackageUrl, RemoteVersionUrl: req.RemoteVersionUrl, RemoteManifestUrl: req.RemoteManifestUrl, } this.updateVersionMap(req.Proj, req.Os, verRsp) return nil } func (this *THotUpdateVerManager) getVersionMapBy(proj, os string) (*TGetVersionRsp, error) { this.mu.RLock() defer this.mu.RUnlock() if _, ok := this.versionMap[proj]; !ok { return nil, errors.New("project or os can't be empty") } if ver, ok := this.versionMap[proj][os]; ok { return ver, nil } else { return nil, errors.New("version not found") } } func (this *THotUpdateVerManager) updateVersionMap(proj, os string, versionRsp *TGetVersionRsp) { this.mu.Lock() defer this.mu.Unlock() logger.Info(fmt.Sprintf("updateVersionMap %s%s%s", proj, os, versionRsp.Version)) if _, ok := this.versionMap[proj]; !ok { this.versionMap[proj] = make(map[string]*TGetVersionRsp) } this.versionMap[proj][os] = versionRsp } // 版本号是递增的 func (this *THotUpdateVerManager) isInvalid(req *TAddVersionReq) bool { curVersion, err := this.GetMaxVerInfo(req.Proj, req.Os) if err != nil { // 默认只有系统初始化时 return true } logger.Info("curVersion:%s, remoteVersion:%s", curVersion, req.Version) return CompareVersion(req.Version, curVersion.Version) == 1 } func (this *THotUpdateVerManager) findMaxVersion(proj, os string) (*TGetVersionRsp, error) { if proj == "" || os == "" { return nil, errors.New("project or os can't be empty") } versions, num, err := this.versionDB.ListByProjectAndOS(proj, os, 1, 20) // 因为是按时间降序 潜规则最近一条的version最大 if err != nil { return nil, err } logger.Debug("versions:", num, versions) if num == 0 { return nil, errors.New(fmt.Sprintf("proj:%s os:%s not find", proj, os)) } versionObj := versions[0] versionRsp := &TGetVersionRsp{ Version: versionObj.Version, PackageUrl: versionObj.PackageUrl, RemoteManifestUrl: versionObj.RemoteManifestUrl, RemoteVersionUrl: versionObj.RemoteVersionUrl, } return versionRsp, nil } // CompareVersion 比较两个版本号 // 返回: -1(v1v2) func CompareVersion(v1, v2 string) int { // 将版本号按点号分割 parts1 := strings.Split(v1, ".") parts2 := strings.Split(v2, ".") // 获取最大长度 maxLen := len(parts1) if len(parts2) > maxLen { maxLen = len(parts2) } // 逐级比较 for i := 0; i < maxLen; i++ { // 获取当前级别的版本号,如果不存在则为0 num1 := 0 if i < len(parts1) { num1, _ = strconv.Atoi(parts1[i]) } num2 := 0 if i < len(parts2) { num2, _ = strconv.Atoi(parts2[i]) } // 比较当前级别 if num1 < num2 { return -1 } else if num1 > num2 { return 1 } // 如果相等,继续比较下一级 } return 0 }