add_ver.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. package service
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "go-common/app/admin/main/appstatic/model"
  6. "go-common/library/log"
  7. "github.com/jinzhu/gorm"
  8. )
  9. const (
  10. // file type
  11. _fullPackage = 0
  12. _diffPackge = 1
  13. // diff file name format
  14. _diffFormat = "Mod_%d/V_%d-V_%d.bspatch"
  15. // limit column
  16. deviceCol = "device"
  17. mobiAppCol = "mobi_app"
  18. platCol = "plat"
  19. buildCol = "build"
  20. sysverCol = "sysver"
  21. scaleCol = "scale"
  22. levelCol = "level"
  23. archCol = "arch"
  24. // condition column
  25. _bk = "bk"
  26. _wt = "wt"
  27. buildLtCdt = "lt"
  28. buildGtCdt = "gt"
  29. buildLeCdt = "le"
  30. buildGeCdt = "ge"
  31. _valid = 1
  32. )
  33. // GenerateVer generates a new version ( resource ) and cover the diff logic
  34. func (s *Service) GenerateVer(resName string, limitData *model.Limit, fInfo *model.FileInfo, pool *model.ResourcePool, defPkg int) (resID int, version int, err error) {
  35. // create a new version
  36. var tx = s.DB.Begin()
  37. var resource = tx.Create(transResource(resName, pool.ID))
  38. if err = resource.Error; err != nil {
  39. log.Error("GenerateVer DBCreate Resource Error(%v)", err)
  40. tx.Rollback()
  41. return
  42. }
  43. resID = int(resource.Value.(*model.Resource).ID)
  44. log.Info("Resource Generated: ID = %d", resID)
  45. // create the full package in File Table
  46. if err = tx.Create(transFile(fInfo, resID)).Error; err != nil {
  47. log.Error("GenerateVer DBCreate ResourceFile Error(%v)", err)
  48. tx.Rollback()
  49. return
  50. }
  51. // create the resource config
  52. var config = tx.Create(transConfig(int64(resID), limitData))
  53. if err = config.Error; err != nil {
  54. log.Error("GenerateVer DBCreate ResoureConfig Error(%v)", err)
  55. tx.Rollback()
  56. return
  57. }
  58. configID := int64(config.Value.(*model.ResourceConfig).ID)
  59. log.Info("Resource Config Generated: ID = %d", configID)
  60. // create the resource limits
  61. limits := createLimit(configID, limitData)
  62. if len(limits) != 0 {
  63. for _, v := range limits {
  64. if err = tx.Create(v).Error; err != nil {
  65. log.Error("GenerateVer DCreate ResourceLimit (%v) Error(%v)", v, err)
  66. tx.Rollback()
  67. return
  68. }
  69. }
  70. } else {
  71. log.Error("[GenerateVer]-[createLimit]-No limit to create")
  72. }
  73. // commit the transaction
  74. tx.Commit()
  75. log.Info("Transaction Committed, ResID: %d", resID)
  76. // treat the default package setting
  77. if defPkg == 1 {
  78. if err = s.DefaultPkg(resID, pool.ID, configID); err != nil {
  79. log.Error("defaultPkg Error (%v)", err)
  80. return
  81. }
  82. }
  83. // defines the version of this resource
  84. if version, err = s.defineVer(resID, pool.ID); err != nil {
  85. log.Error("defineVer Error (%v)", err)
  86. return
  87. }
  88. // create diff records
  89. if err = s.createDiff(resID); err != nil {
  90. log.Error("[GenerateVer]-[createDiff]-Error(%v)", err)
  91. return
  92. }
  93. return
  94. }
  95. // DefaultPkg sets the resID's config as default package, and resets the other resources' config
  96. func (s *Service) DefaultPkg(resID int, poolID int64, confID int64) (err error) {
  97. var (
  98. tx = s.DB.Begin()
  99. rows *sql.Rows
  100. rid int // resource id
  101. )
  102. // find out all the resources under the same pool, and put them as non-default pkg
  103. if rows, err = s.DB.Model(&model.Resource{}).Where("pool_id = ?", poolID).Select("id").Rows(); err != nil {
  104. return
  105. }
  106. for rows.Next() {
  107. if err = rows.Scan(&rid); err != nil {
  108. tx.Rollback()
  109. return
  110. }
  111. if err = tx.Model(&model.ResourceConfig{}).Where("resource_id = ?", rid).Update("default_package", 0).Error; err != nil {
  112. tx.Rollback()
  113. return
  114. }
  115. }
  116. // defines the new package as the default pkg
  117. if err = tx.Model(&model.ResourceConfig{}).Where("id = ?", confID).Update("default_package", 1).Error; err != nil {
  118. tx.Rollback()
  119. return
  120. }
  121. tx.Commit()
  122. return
  123. }
  124. // defines the version of the resource after the transaction commited
  125. func (s *Service) defineVer(resID int, poolID int64) (version int, err error) {
  126. var maxVer = model.Resource{}
  127. if err = s.DB.Where("id < ?", resID).Where("pool_id = ?", poolID).Order("version desc").First(&maxVer).Error; err == gorm.ErrRecordNotFound {
  128. err = nil
  129. }
  130. if err != nil {
  131. log.Error("GenerateVer DBFind ResourceVer (%d) Error(%v)", resID, err)
  132. return
  133. }
  134. version = int(maxVer.Version) + 1
  135. if err = s.DB.Model(&model.Resource{}).Where("id = ?", resID).Update("version", version).Error; err != nil {
  136. log.Error("GenerateVer DBUpdate ResourceVer (%d)-(%d) Error(%v)", resID, maxVer.Version+1, err)
  137. return
  138. }
  139. return
  140. }
  141. // create diff packages for the latest version with the history versions
  142. func (s *Service) createDiff(resID int) (err error) {
  143. var (
  144. prodVers, testVers []int64
  145. currRes *model.Resource
  146. )
  147. // pick history versions to calculate diff
  148. if prodVers, testVers, currRes, err = s.pickDiff(resID); err != nil {
  149. return
  150. }
  151. // put diff packages in our DB
  152. if err = s.putDiff(resID, mergeSlice(prodVers, testVers), currRes); err != nil {
  153. return
  154. }
  155. return
  156. }
  157. // pick history versions to calculate diff
  158. func (s *Service) pickDiff(resID int) (prodVers []int64, testVers []int64, currRes *model.Resource, err error) {
  159. var (
  160. VersProd = []*model.Resource{} // prod
  161. VersTest = []*model.Resource{} // test
  162. res = model.Resource{}
  163. )
  164. if err = s.DB.Where("id = ?", resID).First(&res).Error; err != nil {
  165. log.Error("[createDiff]-[FindCurrentRes]-Error(%v)", err)
  166. return
  167. }
  168. currRes = &res
  169. poolID := currRes.PoolID
  170. // calculate prod diffs
  171. if err = s.DB.Joins("LEFT JOIN resource_config ON resource.id = resource_config.resource_id").
  172. Where("resource.pool_id = ?", poolID).
  173. Where("resource.id < ?", resID).
  174. Where("resource_config.valid = ?", _valid).
  175. Order("resource.version desc").Limit(s.c.Cfg.HistoryVer).
  176. Select("resource.*").
  177. Find(&VersProd).Error; err != nil {
  178. log.Error("[createDiff]-[FindHistoryVers]-Error(%v)", err)
  179. return
  180. }
  181. log.Info("Get Prod History Versions: %d", len(VersProd))
  182. // calculate test diffs
  183. if err = s.DB.Joins("LEFT JOIN resource_config ON resource.id = resource_config.resource_id").
  184. Where("resource.pool_id = ?", poolID).
  185. Where("resource.id < ?", resID).
  186. Where("resource_config.valid != ?", _valid).
  187. Where("resource_config.valid_test = ?", _valid).
  188. Order("resource.version desc").Limit(s.c.Cfg.HistoryVer).
  189. Select("resource.*").
  190. Find(&VersTest).Error; err != nil {
  191. log.Error("[createDiff]-[FindHistoryVers]-Error(%v)", err)
  192. return
  193. }
  194. log.Info("Get Test History Versions: %d", len(VersTest))
  195. // merge slices
  196. prodVers = pickVersion(VersProd)
  197. testVers = pickVersion(VersTest)
  198. return
  199. }
  200. // put diff package in our DB
  201. func (s *Service) putDiff(resID int, historyVers []int64, currRes *model.Resource) (err error) {
  202. for _, v := range historyVers {
  203. var diffPkg = &model.ResourceFile{
  204. Name: fmt.Sprintf(_diffFormat, currRes.PoolID, v, currRes.Version),
  205. FromVer: v,
  206. ResourceID: resID,
  207. FileType: _diffPackge,
  208. }
  209. if err = s.DB.Create(diffPkg).Error; err != nil {
  210. log.Error("[createDiff]-[createDiffPkg]-Error(%v)", err)
  211. return
  212. }
  213. }
  214. log.Info("[createDiff]-Create (%d) Diff Pkg for ResID:(%d)", len(historyVers), resID)
  215. return
  216. }
  217. // pick resource version
  218. func pickVersion(s1 []*model.Resource) (res []int64) {
  219. if len(s1) > 0 {
  220. for _, v := range s1 {
  221. res = append(res, v.Version)
  222. }
  223. }
  224. return
  225. }
  226. // merge int64 slices
  227. func mergeSlice(s1 []int64, s2 []int64) []int64 {
  228. slice := make([]int64, len(s1)+len(s2))
  229. copy(slice, s1)
  230. copy(slice[len(s1):], s2)
  231. return slice
  232. }
  233. // transform to Resource struct
  234. func transResource(resMame string, id int64) *model.Resource {
  235. return &model.Resource{
  236. Name: resMame,
  237. Version: 0, // will be updated after the transaction commits
  238. PoolID: id,
  239. }
  240. }
  241. // transform to File struct
  242. func transFile(fInfo *model.FileInfo, resID int) *model.ResourceFile {
  243. return &model.ResourceFile{
  244. Name: fInfo.Name,
  245. Type: fInfo.Type,
  246. Md5: fInfo.Md5,
  247. Size: int(fInfo.Size),
  248. URL: fInfo.URL,
  249. ResourceID: resID,
  250. FileType: _fullPackage,
  251. }
  252. }
  253. // transform to Config struct
  254. func transConfig(resID int64, limitData *model.Limit) *model.ResourceConfig {
  255. var cfg = &model.ResourceConfig{
  256. ResourceID: resID,
  257. Valid: 0,
  258. IsDeleted: 0,
  259. IsWifi: limitData.IsWifi,
  260. }
  261. if limitData.TimeRange != nil {
  262. cfg.Etime = limitData.TimeRange.Etime
  263. cfg.Stime = limitData.TimeRange.Stime
  264. }
  265. return cfg
  266. }
  267. // createLimit
  268. func createLimit(configID int64, limitData *model.Limit) (res []*model.ResourceLimit) {
  269. // create device limit
  270. if len(limitData.Device) != 0 {
  271. generateDevice(limitData.Device, &res, configID, deviceCol, _bk)
  272. }
  273. // create plat limit
  274. if len(limitData.Plat) != 0 {
  275. generateDevice(limitData.Plat, &res, configID, platCol, _wt)
  276. }
  277. // create mobi_app limit
  278. if len(limitData.MobiApp) != 0 {
  279. generateDevice(limitData.MobiApp, &res, configID, mobiAppCol, _wt)
  280. }
  281. // scale, level, arch
  282. if len(limitData.Level) != 0 {
  283. generateDevice(limitData.Level, &res, configID, levelCol, _wt)
  284. }
  285. if len(limitData.Scale) != 0 {
  286. generateDevice(limitData.Scale, &res, configID, scaleCol, _wt)
  287. }
  288. if len(limitData.Arch) != 0 {
  289. generateDevice(limitData.Arch, &res, configID, archCol, _wt)
  290. }
  291. // create build & sysver limit
  292. if build := limitData.Build; build != nil {
  293. generateBuild(build, configID, &res, buildCol)
  294. }
  295. if sysver := limitData.Sysver; sysver != nil {
  296. generateBuild(sysver, configID, &res, sysverCol)
  297. }
  298. log.Info("createLimit creates %d limits", len(res))
  299. return
  300. }
  301. // generate build-like limits data (json, range), insert them into the slice 'res'
  302. func generateBuild(build *model.Build, configID int64, res *[]*model.ResourceLimit, column string) {
  303. if build.GT != 0 {
  304. *res = append(*res, transBuild(buildGtCdt, configID, build.GT, column))
  305. }
  306. if build.LT != 0 {
  307. *res = append(*res, transBuild(buildLtCdt, configID, build.LT, column))
  308. }
  309. if build.GE != 0 {
  310. *res = append(*res, transBuild(buildGeCdt, configID, build.GE, column))
  311. }
  312. if build.LE != 0 {
  313. *res = append(*res, transBuild(buildLeCdt, configID, build.LE, column))
  314. }
  315. }
  316. // generate device-like limits data([]string), insert them into the slice 'res'
  317. func generateDevice(device []string, res *[]*model.ResourceLimit, configID int64, col string, cdt string) {
  318. for _, v := range device {
  319. *res = append(*res, &model.ResourceLimit{
  320. ConfigID: configID,
  321. Column: col,
  322. Condition: cdt,
  323. Value: v,
  324. IsDeleted: 0,
  325. })
  326. }
  327. }
  328. func transBuild(condition string, configID int64, value int, column string) *model.ResourceLimit {
  329. return &model.ResourceLimit{
  330. ConfigID: configID,
  331. Column: column,
  332. Condition: condition,
  333. Value: fmt.Sprintf("%d", value),
  334. IsDeleted: 0,
  335. }
  336. }