version.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. package service
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "sort"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "dsbqj-admin/app/task"
  11. "dsbqj-admin/model/mongo/abver"
  12. "dsbqj-admin/model/mongo/md5"
  13. "dsbqj-admin/model/mongo/version"
  14. "dsbqj-admin/tool"
  15. "github.com/kamva/mgm/v3"
  16. "go.mongodb.org/mongo-driver/bson"
  17. "go.mongodb.org/mongo-driver/bson/primitive"
  18. "go.mongodb.org/mongo-driver/mongo"
  19. "go.mongodb.org/mongo-driver/mongo/options"
  20. )
  21. const versionExternalReqTimeoutSec = 30 * 60
  22. type VersionReloadService struct {
  23. }
  24. func (service *VersionReloadService) Reload() error {
  25. task.VersionTask.Exec()
  26. return nil
  27. }
  28. type VersionServerService struct {
  29. Platform string `json:"platform"`
  30. LegacyChannel string `json:"channel"`
  31. }
  32. func (service *VersionServerService) Servers() ([]*version.Version, error) {
  33. platform := resolvePlatform(service.Platform, service.LegacyChannel)
  34. if platform == "" {
  35. return nil, errors.New("平台不能为空")
  36. }
  37. items := task.VersionTask.Servers(platform)
  38. result := make([]*version.Version, 0, len(items))
  39. for _, item := range items {
  40. result = append(result, versionWithConfig(item, platform, task.NormalizeEnvVersion(item.EnvVersion)))
  41. }
  42. return result, nil
  43. }
  44. type VersionCheckService struct {
  45. Version string `json:"version"`
  46. Platform string `json:"platform"`
  47. LegacyChannel string `json:"channel"`
  48. EnvVersion string `json:"envVersion"`
  49. }
  50. func (service *VersionCheckService) Check() (*version.Version, error) {
  51. platform := resolvePlatform(service.Platform, service.LegacyChannel)
  52. if platform == "" {
  53. return nil, errors.New("平台不能为空")
  54. }
  55. result := task.VersionTask.Check(service.Version, platform, service.EnvVersion)
  56. if result == nil {
  57. return nil, nil
  58. }
  59. return versionWithConfig(result, platform, task.NormalizeEnvVersion(result.EnvVersion)), nil
  60. }
  61. func versionWithConfig(item *version.Version, platform, env string) *version.Version {
  62. result := *item
  63. abVer := task.VersionConfigTask.GetAbVer(platform, env)
  64. md5 := task.VersionConfigTask.GetMD5(platform, env)
  65. result.AbVer, result.AbVerVersion = abVer.Value, abVer.Version
  66. result.MD5, result.MD5Version = md5.Value, md5.Version
  67. return &result
  68. }
  69. func resolvePlatform(platform, legacyChannel string) string {
  70. if value := strings.TrimSpace(platform); value != "" {
  71. return value
  72. }
  73. return strings.TrimSpace(legacyChannel)
  74. }
  75. type VersionShowService struct {
  76. CondPage
  77. Platform string `form:"platform" json:"platform"`
  78. EnvVersion string `form:"envVersion" json:"envVersion"`
  79. }
  80. func (service *VersionShowService) List() ([]version.Version, error) {
  81. versions := make([]version.Version, 0)
  82. var queryDoc = bson.M{}
  83. clauses := make([]bson.M, 0, 2)
  84. if service.Platform != "" {
  85. clauses = append(clauses, bson.M{"$or": []bson.M{{"platform": service.Platform}, {"platform": ""}, {"platform": bson.M{"$exists": false}}}})
  86. }
  87. if service.EnvVersion != "" {
  88. envVersion := task.NormalizeEnvVersion(service.EnvVersion)
  89. if envVersion == "release" {
  90. clauses = append(clauses, bson.M{"$or": []bson.M{
  91. {"envVersion": envVersion},
  92. {"envVersion": ""},
  93. {"envVersion": bson.M{"$exists": false}},
  94. }})
  95. } else {
  96. clauses = append(clauses, bson.M{"envVersion": envVersion})
  97. }
  98. }
  99. if len(clauses) > 0 {
  100. queryDoc["$and"] = clauses
  101. }
  102. err := mgm.Coll(&version.Version{}).SimpleFind(&versions, queryDoc)
  103. return versions, err
  104. }
  105. type VersionCreateService struct {
  106. Platform string `json:"platform" binding:"required"`
  107. EnvVersion string `json:"envVersion"`
  108. Version string `json:"version" binding:"required"`
  109. Name string `json:"name" binding:"required"`
  110. CDN string `json:"cdn" binding:"required"`
  111. Url string `json:"url" binding:"required"`
  112. }
  113. func (service *VersionCreateService) Create() error {
  114. envVersion := task.NormalizeEnvVersion(service.EnvVersion)
  115. var exists version.Version
  116. err := mgm.Coll(&version.Version{}).First(versionIdentityFilter(service.Platform, service.Version, envVersion), &exists)
  117. if err == nil {
  118. return errors.New("该平台、环境和版本号已存在")
  119. }
  120. if !errors.Is(err, mongo.ErrNoDocuments) {
  121. return err
  122. }
  123. version := new(version.Version)
  124. version.Platform = service.Platform
  125. version.EnvVersion = envVersion
  126. version.Name = service.Name
  127. version.Version = service.Version
  128. version.CDN = service.CDN
  129. version.Url = service.Url
  130. if err := mgm.Coll(version).Create(version); err != nil {
  131. return err
  132. }
  133. task.VersionTask.Exec()
  134. return nil
  135. }
  136. type VersionEditService struct {
  137. Id string `json:"id" binding:"required"`
  138. Platform *string `json:"platform"`
  139. EnvVersion *string `json:"envVersion"`
  140. Version *string `json:"version"`
  141. Name *string `json:"name"`
  142. CDN *string `json:"cdn"`
  143. Url *string `json:"url"`
  144. Default *bool `json:"default"`
  145. }
  146. func (service *VersionEditService) Edit() error {
  147. objectId, _ := primitive.ObjectIDFromHex(service.Id)
  148. coll := mgm.Coll(&version.Version{})
  149. var current version.Version
  150. if err := coll.FindByID(objectId, &current); err != nil {
  151. return err
  152. }
  153. platform, envVersion, versionNumber := current.Platform, task.NormalizeEnvVersion(current.EnvVersion), current.Version
  154. if service.Platform != nil {
  155. platform = strings.TrimSpace(*service.Platform)
  156. }
  157. if service.EnvVersion != nil {
  158. envVersion = task.NormalizeEnvVersion(*service.EnvVersion)
  159. }
  160. if service.Version != nil {
  161. versionNumber = *service.Version
  162. }
  163. var duplicate version.Version
  164. duplicateFilter := versionIdentityFilter(platform, versionNumber, envVersion)
  165. duplicateFilter["_id"] = bson.M{"$ne": objectId}
  166. if err := coll.First(duplicateFilter, &duplicate); err == nil {
  167. return errors.New("该平台、环境和版本号已存在")
  168. } else if !errors.Is(err, mongo.ErrNoDocuments) {
  169. return err
  170. }
  171. filterDoc := bson.M{"_id": objectId}
  172. updateDoc := bson.M{}
  173. if service.Platform != nil {
  174. updateDoc["platform"] = platform
  175. }
  176. if service.EnvVersion != nil {
  177. updateDoc["envVersion"] = task.NormalizeEnvVersion(*service.EnvVersion)
  178. }
  179. if service.Name != nil {
  180. updateDoc["name"] = *service.Name
  181. }
  182. if service.Version != nil {
  183. updateDoc["version"] = *service.Version
  184. }
  185. if service.CDN != nil {
  186. updateDoc["cdn"] = *service.CDN
  187. }
  188. if service.Url != nil {
  189. updateDoc["url"] = *service.Url
  190. }
  191. if service.Default != nil {
  192. updateDoc["default"] = *service.Default
  193. }
  194. _, err := coll.UpdateOne(context.Background(), filterDoc, bson.M{"$set": updateDoc})
  195. if err != nil {
  196. return err
  197. }
  198. task.VersionTask.Exec()
  199. return nil
  200. }
  201. func versionIdentityFilter(platform, versionNumber, envVersion string) bson.M {
  202. filter := bson.M{"platform": platform, "version": versionNumber}
  203. if task.NormalizeEnvVersion(envVersion) == "release" {
  204. filter["$or"] = []bson.M{{"envVersion": "release"}, {"envVersion": ""}, {"envVersion": bson.M{"$exists": false}}}
  205. } else {
  206. filter["envVersion"] = "trial"
  207. }
  208. return filter
  209. }
  210. type VersionProdService struct {
  211. Id string `json:"id" binding:"required"`
  212. IsProd bool `json:"isProd"`
  213. }
  214. func (service *VersionProdService) Update() error {
  215. objectId, err := primitive.ObjectIDFromHex(service.Id)
  216. if err != nil {
  217. return err
  218. }
  219. coll := mgm.Coll(&version.Version{})
  220. var current version.Version
  221. if err := coll.FindByID(objectId, &current); err != nil {
  222. return err
  223. }
  224. if service.IsProd {
  225. scope := versionIdentityFilter(current.Platform, "", current.EnvVersion)
  226. delete(scope, "version")
  227. scope["_id"] = bson.M{"$ne": objectId}
  228. if _, err := coll.UpdateMany(
  229. context.Background(),
  230. scope,
  231. bson.M{"$set": bson.M{"isProd": false}},
  232. ); err != nil {
  233. return err
  234. }
  235. }
  236. _, err = coll.UpdateOne(
  237. context.Background(),
  238. bson.M{"_id": objectId},
  239. bson.M{"$set": bson.M{"isProd": service.IsProd}},
  240. )
  241. return err
  242. }
  243. type VersionExternalConfigService struct {
  244. Platform string `form:"platform" json:"platform" binding:"required"`
  245. Version string `form:"version" json:"version" binding:"required"`
  246. AbVer *string `form:"abVer" json:"abVer"`
  247. MD5 *string `form:"md5" json:"md5"`
  248. TimeSec int64 `form:"timesec" json:"timesec" binding:"required"`
  249. Sign string `form:"sign" json:"sign" binding:"required"`
  250. }
  251. type VersionConfigUploadService struct {
  252. Platform string `form:"platform" json:"platform" binding:"required"`
  253. Version string `form:"version" json:"version" binding:"required"`
  254. Value string `form:"value" json:"value" binding:"required"`
  255. TimeSec int64 `form:"timesec" json:"timesec" binding:"required"`
  256. Sign string `form:"sign" json:"sign" binding:"required"`
  257. }
  258. type VersionConfigManageService struct {
  259. Type string `json:"type" form:"type" binding:"required"`
  260. ID string `json:"id"`
  261. PlatformFilter string `json:"-"`
  262. Version string `json:"version"`
  263. Value *string `json:"value"`
  264. EnvVersions *[]string `json:"envVersions"`
  265. External *bool `json:"external"`
  266. }
  267. func configCollection(configType string) interface{} {
  268. if configType == "md5" {
  269. return &md5.MD5{}
  270. }
  271. return &abver.AbVer{}
  272. }
  273. func (service *VersionConfigManageService) List() (interface{}, error) {
  274. items := make([]interface{}, 0)
  275. filter := bson.M{}
  276. if service.PlatformFilter != "" {
  277. filter["$or"] = []bson.M{{"platform": service.PlatformFilter}, {"platform": ""}, {"platform": bson.M{"$exists": false}}}
  278. }
  279. if service.Type == "md5" {
  280. result := make([]md5.MD5, 0)
  281. err := mgm.Coll(&md5.MD5{}).SimpleFind(&result, filter)
  282. sort.SliceStable(result, func(i, j int) bool {
  283. return task.CompareConfigVersion(result[i].Version, result[j].Version) > 0
  284. })
  285. for i := range result {
  286. items = append(items, result[i])
  287. }
  288. return items, err
  289. }
  290. result := make([]abver.AbVer, 0)
  291. err := mgm.Coll(&abver.AbVer{}).SimpleFind(&result, filter)
  292. sort.SliceStable(result, func(i, j int) bool {
  293. return task.CompareConfigVersion(result[i].Version, result[j].Version) > 0
  294. })
  295. for i := range result {
  296. items = append(items, result[i])
  297. }
  298. return items, err
  299. }
  300. func (service *VersionConfigManageService) Save() error {
  301. if service.ID == "" {
  302. return errors.New("配置记录编号不能为空")
  303. }
  304. id, err := primitive.ObjectIDFromHex(service.ID)
  305. if err != nil {
  306. return err
  307. }
  308. update := bson.M{}
  309. if service.Value != nil {
  310. update["value"] = *service.Value
  311. }
  312. if service.EnvVersions != nil {
  313. update["envVersions"] = *service.EnvVersions
  314. }
  315. if service.External != nil {
  316. update["external"] = *service.External
  317. }
  318. if len(update) == 0 {
  319. return errors.New("没有需要更新的内容")
  320. }
  321. if service.Type == "md5" {
  322. _, err = mgm.Coll(&md5.MD5{}).UpdateOne(context.Background(), bson.M{"_id": id}, bson.M{"$set": update})
  323. if err == nil {
  324. task.VersionConfigTask.Reload()
  325. }
  326. return err
  327. }
  328. _, err = mgm.Coll(&abver.AbVer{}).UpdateOne(context.Background(), bson.M{"_id": id}, bson.M{"$set": update})
  329. if err == nil {
  330. task.VersionConfigTask.Reload()
  331. }
  332. return err
  333. }
  334. func (service *VersionConfigUploadService) ValidateAuth() error {
  335. deltaTime := time.Now().Unix() - service.TimeSec
  336. if deltaTime < 0 {
  337. deltaTime = -deltaTime
  338. }
  339. if deltaTime > versionExternalReqTimeoutSec {
  340. return errors.New("时间戳已过期")
  341. }
  342. params := map[string]any{"platform": service.Platform, "version": service.Version, "value": service.Value, "timesec": strconv.FormatInt(service.TimeSec, 10)}
  343. if tool.GenSign(params) != service.Sign {
  344. return errors.New("签名错误")
  345. }
  346. return nil
  347. }
  348. func (service *VersionConfigUploadService) SaveAbVer() error {
  349. var exists abver.AbVer
  350. filter := bson.M{"platform": service.Platform, "version": service.Version}
  351. if err := mgm.Coll(&abver.AbVer{}).First(filter, &exists); err == nil {
  352. return errors.New("abVer 配置版本已存在,不能重复上报")
  353. }
  354. item := &abver.AbVer{Platform: service.Platform, Version: service.Version, Value: service.Value, External: false}
  355. _, err := mgm.Coll(item).UpdateOne(context.Background(), filter, bson.M{"$set": item}, options.Update().SetUpsert(true))
  356. if err == nil {
  357. task.VersionConfigTask.Reload()
  358. }
  359. return err
  360. }
  361. func (service *VersionConfigUploadService) SaveMD5() error {
  362. var exists md5.MD5
  363. filter := bson.M{"platform": service.Platform, "version": service.Version}
  364. if err := mgm.Coll(&md5.MD5{}).First(filter, &exists); err == nil {
  365. return errors.New("md5 配置版本已存在,不能重复上报")
  366. }
  367. item := &md5.MD5{Platform: service.Platform, Version: service.Version, Value: service.Value, External: false}
  368. _, err := mgm.Coll(item).UpdateOne(context.Background(), filter, bson.M{"$set": item}, options.Update().SetUpsert(true))
  369. if err == nil {
  370. task.VersionConfigTask.Reload()
  371. }
  372. return err
  373. }
  374. func (service *VersionExternalConfigService) Save() error {
  375. if service.AbVer == nil && service.MD5 == nil {
  376. return errors.New("abVer or md5 is required")
  377. }
  378. filterDoc := bson.M{
  379. "platform": service.Platform,
  380. "version": service.Version,
  381. }
  382. coll := mgm.Coll(&version.Version{})
  383. var current version.Version
  384. if err := coll.First(filterDoc, &current); err != nil {
  385. return errors.New("version not found")
  386. }
  387. updateDoc := bson.M{}
  388. if service.AbVer != nil {
  389. updateDoc["abVer"] = *service.AbVer
  390. }
  391. if service.MD5 != nil {
  392. updateDoc["md5"] = *service.MD5
  393. }
  394. _, err := coll.UpdateOne(
  395. context.Background(),
  396. bson.M{"_id": current.ID},
  397. bson.M{"$set": updateDoc},
  398. )
  399. return err
  400. }
  401. func (service *VersionExternalConfigService) ValidateAuth() error {
  402. deltaTime := time.Now().Unix() - service.TimeSec
  403. if deltaTime < 0 {
  404. deltaTime = -deltaTime
  405. }
  406. if deltaTime > versionExternalReqTimeoutSec {
  407. return fmt.Errorf("timesec timeout")
  408. }
  409. params := map[string]any{
  410. "platform": service.Platform,
  411. "version": service.Version,
  412. "timesec": strconv.FormatInt(service.TimeSec, 10),
  413. }
  414. if service.AbVer != nil {
  415. params["abVer"] = *service.AbVer
  416. }
  417. if service.MD5 != nil {
  418. params["md5"] = *service.MD5
  419. }
  420. sign := tool.GenSign(params)
  421. if sign != service.Sign {
  422. return fmt.Errorf("sign error")
  423. }
  424. return nil
  425. }
  426. type VersionDeleteService struct {
  427. Id string `json:"id" binding:"required"`
  428. }
  429. func (service *VersionDeleteService) Delete() error {
  430. version := new(version.Version)
  431. objectId, _ := primitive.ObjectIDFromHex(service.Id)
  432. filterDoc := bson.M{"_id": objectId}
  433. _, err := mgm.Coll(version).DeleteOne(context.Background(), filterDoc)
  434. if err != nil {
  435. return err
  436. }
  437. task.VersionTask.Exec()
  438. return nil
  439. }