module.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. package module
  2. import (
  3. "context"
  4. "strconv"
  5. "strings"
  6. "time"
  7. "go-common/app/interface/main/app-resource/conf"
  8. moduledao "go-common/app/interface/main/app-resource/dao/module"
  9. "go-common/app/interface/main/app-resource/model/module"
  10. "go-common/library/ecode"
  11. "go-common/library/log"
  12. )
  13. var (
  14. _emptylist = []*module.ResourcePool{}
  15. )
  16. // Service module service.
  17. type Service struct {
  18. dao *moduledao.Dao
  19. tick time.Duration
  20. resourceCache map[string]*module.ResourcePool
  21. conditionsCache map[int]*module.Condition
  22. }
  23. // New new a module service.
  24. func New(c *conf.Config) (s *Service) {
  25. s = &Service{
  26. dao: moduledao.New(c),
  27. tick: time.Duration(c.Tick),
  28. resourceCache: map[string]*module.ResourcePool{},
  29. conditionsCache: make(map[int]*module.Condition),
  30. }
  31. s.loadCache()
  32. go s.loadproc()
  33. return
  34. }
  35. func (s *Service) FormCondition(versions []*module.Versions) (res map[string]map[string]int) {
  36. res = make(map[string]map[string]int)
  37. for _, pools := range versions {
  38. var (
  39. re map[string]int
  40. ok bool
  41. )
  42. for _, resource := range pools.Resource {
  43. if re, ok = res[pools.PoolName]; !ok {
  44. re = make(map[string]int)
  45. res[pools.PoolName] = re
  46. }
  47. var tmpVer int
  48. switch tmp := resource.Version.(type) {
  49. case string:
  50. tmpVer, _ = strconv.Atoi(tmp)
  51. case float64:
  52. tmpVer = int(tmp)
  53. }
  54. re[resource.ResourceName] = tmpVer
  55. }
  56. }
  57. return
  58. }
  59. // List get All or by poolname
  60. func (s *Service) List(c context.Context, mobiApp, device, platform, poolName, env string, build, sysver, level, scale, arch int,
  61. versions []*module.Versions, now time.Time) (res []*module.ResourcePool) {
  62. var (
  63. resTmp []*module.ResourcePool
  64. versionsMap = s.FormCondition(versions)
  65. )
  66. if poolName != "" {
  67. if pool, ok := s.resourceCache[poolName]; ok {
  68. resTmp = append(resTmp, pool)
  69. }
  70. } else {
  71. for _, l := range s.resourceCache {
  72. resTmp = append(resTmp, l)
  73. }
  74. }
  75. if len(resTmp) == 0 {
  76. res = _emptylist
  77. return
  78. }
  79. for _, resPool := range resTmp {
  80. var (
  81. existRes = map[string]*module.Resource{}
  82. existResTotal = map[string]struct{}{}
  83. resPoolTmp = &module.ResourcePool{Name: resPool.Name}
  84. ok bool
  85. )
  86. for _, re := range resPool.Resources {
  87. if re == nil {
  88. continue
  89. }
  90. if !s.checkCondition(c, mobiApp, device, platform, env, build, sysver, level, scale, arch, re.Condition, now) {
  91. continue
  92. }
  93. var t *module.Resource
  94. if _, ok = existResTotal[re.Name]; ok {
  95. continue
  96. }
  97. if t, ok = existRes[re.Name]; ok {
  98. if re.Increment == module.Total {
  99. tmp := &module.Resource{}
  100. *tmp = *t
  101. tmp.TotalMD5 = re.MD5
  102. existResTotal[tmp.Name] = struct{}{}
  103. resPoolTmp.Resources = append(resPoolTmp.Resources, tmp)
  104. continue
  105. }
  106. } else {
  107. var (
  108. resVer map[string]int
  109. ver int
  110. )
  111. if resVer, ok = versionsMap[resPool.Name]; ok {
  112. if ver, ok = resVer[re.Name]; ok {
  113. if re.Increment == module.Incremental && re.FromVer != ver {
  114. continue
  115. }
  116. } else if !ok && re.Increment == module.Incremental {
  117. continue
  118. }
  119. } else if !ok && re.Increment == module.Incremental {
  120. continue
  121. }
  122. tmp := &module.Resource{}
  123. *tmp = *re
  124. existRes[tmp.Name] = tmp
  125. if re.Increment == module.Total {
  126. tmp.TotalMD5 = re.MD5
  127. existResTotal[tmp.Name] = struct{}{}
  128. resPoolTmp.Resources = append(resPoolTmp.Resources, tmp)
  129. }
  130. }
  131. }
  132. if len(resPoolTmp.Resources) == 0 {
  133. continue
  134. }
  135. res = append(res, resPoolTmp)
  136. }
  137. return
  138. }
  139. // Resource get by poolname and resourcename
  140. func (s *Service) Resource(c context.Context, mobiApp, device, platform, poolName, resourceName, env string,
  141. ver, build, sysver, level, scale, arch int, now time.Time) (res *module.Resource, err error) {
  142. if resPoolTmp, ok := s.resourceCache[poolName]; ok {
  143. if resPoolTmp == nil {
  144. err = ecode.NothingFound
  145. return
  146. }
  147. var (
  148. resTmp *module.Resource
  149. existRes = map[string]struct{}{}
  150. )
  151. for _, resTmp = range resPoolTmp.Resources {
  152. if resTmp == nil {
  153. continue
  154. }
  155. if resTmp != nil && resTmp.Name == resourceName {
  156. if !s.checkCondition(c, mobiApp, device, platform, env, build, sysver, level, scale, arch, resTmp.Condition, now) {
  157. continue
  158. }
  159. if ver == 0 {
  160. if resTmp.Increment == module.Incremental {
  161. continue
  162. }
  163. } else {
  164. if resTmp.Increment == module.Incremental && resTmp.FromVer != ver {
  165. continue
  166. }
  167. }
  168. if resTmp.Increment == module.Total && resTmp.Version == ver {
  169. err = ecode.NotModified
  170. break
  171. }
  172. if _, ok := existRes[resTmp.Name]; !ok {
  173. res = &module.Resource{}
  174. *res = *resTmp
  175. existRes[resTmp.Name] = struct{}{}
  176. }
  177. if resTmp.Increment == module.Total && res != nil {
  178. res.TotalMD5 = resTmp.MD5
  179. break
  180. }
  181. }
  182. }
  183. }
  184. if err != nil {
  185. return
  186. }
  187. if res == nil {
  188. err = ecode.NothingFound
  189. }
  190. return
  191. }
  192. func (s *Service) checkCondition(c context.Context, mobiApp, device, platform, env string, build, sysver, level, scale, arch int, condition *module.Condition, now time.Time) bool {
  193. if condition == nil {
  194. return true
  195. }
  196. if env == module.EnvRelease && condition.Valid == 0 {
  197. return false
  198. } else if env == module.EnvTest && condition.ValidTest == 0 {
  199. return false
  200. } else if env == module.EnvDefault && condition.Default != 1 {
  201. return false
  202. }
  203. if !condition.STime.Time().IsZero() && now.Unix() < int64(condition.STime) {
  204. return false
  205. }
  206. if !condition.ETime.Time().IsZero() && now.Unix() > int64(condition.ETime) {
  207. return false
  208. }
  209. NETX:
  210. for column, cv := range condition.Columns {
  211. switch column {
  212. case "plat": // whith list
  213. for _, v := range cv {
  214. if strings.TrimSpace(v.Value) == platform {
  215. continue NETX
  216. }
  217. }
  218. return false
  219. case "mobi_app": // whith list
  220. for _, v := range cv {
  221. if strings.TrimSpace(v.Value) == mobiApp {
  222. continue NETX
  223. }
  224. }
  225. return false
  226. case "device": // blace list
  227. for _, v := range cv {
  228. if strings.TrimSpace(v.Value) == device {
  229. return false
  230. }
  231. }
  232. case "build": // build < lt gt > build ge >= build, le <= build
  233. for _, v := range cv {
  234. value, _ := strconv.Atoi(strings.TrimSpace(v.Value))
  235. if invalidModelBuild(build, value, v.Condition) {
  236. return false
  237. }
  238. }
  239. case "sysver":
  240. if sysver > 0 {
  241. for _, v := range cv {
  242. value, _ := strconv.Atoi(strings.TrimSpace(v.Value))
  243. if invalidModelBuild(sysver, value, v.Condition) {
  244. return false
  245. }
  246. }
  247. }
  248. case "scale": // whith list
  249. if scale > 0 {
  250. for _, v := range cv {
  251. value, _ := strconv.Atoi(strings.TrimSpace(v.Value))
  252. if value == scale {
  253. continue NETX
  254. }
  255. }
  256. return false
  257. }
  258. case "arch": // whith list
  259. if arch > 0 {
  260. for _, v := range cv {
  261. value, _ := strconv.Atoi(strings.TrimSpace(v.Value))
  262. if value == arch {
  263. continue NETX
  264. }
  265. }
  266. return false
  267. }
  268. }
  269. }
  270. return true
  271. }
  272. // ModuleUpdateCache update module cache
  273. func (s *Service) ModuleUpdateCache() (err error) {
  274. err = s.loadCache()
  275. return
  276. }
  277. // load update cache
  278. func (s *Service) loadCache() (err error) {
  279. configsTmp, err := s.dao.ResourceConfig(context.TODO())
  280. if err != nil {
  281. log.Error("s.dao.ResourceConfig error(%v)", err)
  282. return
  283. }
  284. limitTmp, err := s.dao.ResourceLimit(context.TODO())
  285. if err != nil {
  286. log.Error("s.dao.ResourceLimit error(%v)", err)
  287. return
  288. }
  289. for _, config := range configsTmp {
  290. if limit, ok := limitTmp[config.ID]; ok {
  291. config.Columns = limit
  292. }
  293. }
  294. s.conditionsCache = configsTmp
  295. log.Info("module conditions success")
  296. tmpResourceDev, err := s.dao.ModuleDev(context.TODO())
  297. if err != nil {
  298. log.Error("s.dao.ModuleDev error(%v)", err)
  299. return
  300. }
  301. tmpResources, err := s.dao.ModuleAll(context.TODO())
  302. if err != nil {
  303. log.Error("s.dao.ModuleAll error(%v)", err)
  304. return
  305. }
  306. tmpResourcePoolCaches := map[string]*module.ResourcePool{}
  307. for _, resPool := range tmpResourceDev {
  308. if resPool == nil {
  309. continue
  310. }
  311. var tmpResourcePoolCache = &module.ResourcePool{ID: resPool.ID, Name: resPool.Name}
  312. for _, res := range resPool.Resources {
  313. if res == nil {
  314. continue
  315. }
  316. if re, ok := tmpResources[res.ID]; ok {
  317. var tmpre []*module.Resource
  318. for _, r := range re {
  319. if r.URL == "" || r.MD5 == "" {
  320. continue
  321. }
  322. if c, ok := s.conditionsCache[r.ResID]; ok {
  323. r.Condition = c
  324. // all level
  325. if c != nil {
  326. for column, cv := range c.Columns {
  327. switch column {
  328. case "level":
  329. for _, v := range cv {
  330. value, _ := strconv.Atoi(strings.TrimSpace(v.Value))
  331. r.Level = value
  332. }
  333. }
  334. }
  335. }
  336. r.IsWifi = c.IsWifi
  337. }
  338. tmpre = append(tmpre, r)
  339. }
  340. if len(tmpre) == 0 {
  341. continue
  342. }
  343. tmpResourcePoolCache.Resources = append(tmpResourcePoolCache.Resources, tmpre...)
  344. }
  345. }
  346. tmpResourcePoolCaches[resPool.Name] = tmpResourcePoolCache
  347. }
  348. s.resourceCache = tmpResourcePoolCaches
  349. log.Info("module resources success")
  350. return
  351. }
  352. // cacheproc load cache data
  353. func (s *Service) loadproc() {
  354. for {
  355. time.Sleep(s.tick)
  356. s.loadCache()
  357. }
  358. }
  359. // invalidModelBuild model build
  360. func invalidModelBuild(srcBuild, cfgBuild int, cfgCond string) bool {
  361. if cfgBuild != 0 && cfgCond != "" {
  362. switch cfgCond {
  363. case "lt":
  364. if cfgBuild <= srcBuild {
  365. return true
  366. }
  367. case "le":
  368. if cfgBuild < srcBuild {
  369. return true
  370. }
  371. case "ge":
  372. if cfgBuild > srcBuild {
  373. return true
  374. }
  375. case "gt":
  376. if cfgBuild >= srcBuild {
  377. return true
  378. }
  379. }
  380. }
  381. return false
  382. }