bgm_charge.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. package charge
  2. import (
  3. "bytes"
  4. "context"
  5. "fmt"
  6. "math"
  7. "math/big"
  8. "strconv"
  9. "strings"
  10. "time"
  11. model "go-common/app/job/main/growup/model/charge"
  12. "go-common/library/log"
  13. xtime "go-common/library/time"
  14. "golang.org/x/sync/errgroup"
  15. )
  16. func (s *Service) handleBgm(c context.Context, date time.Time,
  17. dailyChannel chan []*model.BgmCharge) (weekly, monthly map[string]*model.BgmCharge, statis map[string]*model.BgmStatis, err error) {
  18. var eg errgroup.Group
  19. weekly = make(map[string]*model.BgmCharge)
  20. monthly = make(map[string]*model.BgmCharge)
  21. statis = make(map[string]*model.BgmStatis)
  22. eg.Go(func() (err error) {
  23. weekly, err = s.getBgmCharge(c, getStartWeeklyDate(date), "bgm_weekly_charge")
  24. if err != nil {
  25. log.Error("s.GetBgmCharge(bgm_weekly_charge) error(%v)", err)
  26. return
  27. }
  28. return
  29. })
  30. eg.Go(func() (err error) {
  31. monthly, err = s.getBgmCharge(c, getStartMonthlyDate(date), "bgm_monthly_charge")
  32. if err != nil {
  33. log.Error("s.GetBgmCharge(bgm_monthly_charge) error(%v)", err)
  34. return
  35. }
  36. return
  37. })
  38. eg.Go(func() (err error) {
  39. statis, err = s.getBgmStatis(c)
  40. if err != nil {
  41. log.Error("s.getBgmStatisMap error(%v)", err)
  42. }
  43. return
  44. })
  45. if err = eg.Wait(); err != nil {
  46. log.Error("handleBgm eg.Wait error(%v)", err)
  47. return
  48. }
  49. s.calBgms(date, weekly, monthly, statis, dailyChannel)
  50. return
  51. }
  52. func (s *Service) calBgms(date time.Time, weeklyMap, monthlyMap map[string]*model.BgmCharge, statisMap map[string]*model.BgmStatis, dailyChannel chan []*model.BgmCharge) {
  53. for daily := range dailyChannel {
  54. s.calBgm(date, daily, weeklyMap, monthlyMap, statisMap)
  55. }
  56. }
  57. func (s *Service) calBgm(date time.Time, daily []*model.BgmCharge, weeklyMap, monthlyMap map[string]*model.BgmCharge, statisMap map[string]*model.BgmStatis) {
  58. for _, charge := range daily {
  59. key := fmt.Sprintf("%d+%d", charge.SID, charge.AID)
  60. if weekly, ok := weeklyMap[key]; ok {
  61. updateBgmCharge(weekly, charge)
  62. } else {
  63. weeklyMap[key] = addBgmCharge(charge, startWeeklyDate)
  64. }
  65. if monthly, ok := monthlyMap[key]; ok {
  66. updateBgmCharge(monthly, charge)
  67. } else {
  68. monthlyMap[key] = addBgmCharge(charge, startMonthlyDate)
  69. }
  70. if statis, ok := statisMap[key]; ok {
  71. updateBgmStatis(statis, charge)
  72. } else {
  73. statisMap[key] = addBgmStatis(charge)
  74. }
  75. }
  76. }
  77. func addBgmCharge(daily *model.BgmCharge, fixDate time.Time) *model.BgmCharge {
  78. return &model.BgmCharge{
  79. SID: daily.SID,
  80. AID: daily.AID,
  81. MID: daily.MID,
  82. CID: daily.CID,
  83. JoinAt: daily.JoinAt,
  84. Title: daily.Title,
  85. IncCharge: daily.IncCharge,
  86. Date: xtime.Time(fixDate.Unix()),
  87. DBState: _dbInsert,
  88. }
  89. }
  90. func updateBgmCharge(origin, daily *model.BgmCharge) {
  91. origin.IncCharge += daily.IncCharge
  92. origin.DBState = _dbUpdate
  93. }
  94. func addBgmStatis(daily *model.BgmCharge) *model.BgmStatis {
  95. return &model.BgmStatis{
  96. SID: daily.SID,
  97. AID: daily.AID,
  98. MID: daily.MID,
  99. CID: daily.CID,
  100. JoinAt: daily.JoinAt,
  101. Title: daily.Title,
  102. TotalCharge: daily.IncCharge,
  103. DBState: _dbInsert,
  104. }
  105. }
  106. func updateBgmStatis(statis *model.BgmStatis, daily *model.BgmCharge) {
  107. statis.TotalCharge += daily.IncCharge
  108. statis.DBState = _dbUpdate
  109. }
  110. func (s *Service) getBgmCharge(c context.Context, date time.Time, table string) (bgms map[string]*model.BgmCharge, err error) {
  111. bgms = make(map[string]*model.BgmCharge)
  112. var id int64
  113. for {
  114. var bgm []*model.BgmCharge
  115. bgm, err = s.dao.BgmCharge(c, date, id, _limitSize, table)
  116. if err != nil {
  117. return
  118. }
  119. for _, b := range bgm {
  120. key := fmt.Sprintf("%d+%d", b.SID, b.AID)
  121. bgms[key] = b
  122. }
  123. if len(bgm) < _limitSize {
  124. break
  125. }
  126. id = bgm[len(bgm)-1].ID
  127. }
  128. return
  129. }
  130. func (s *Service) getBgmStatis(c context.Context) (bgms map[string]*model.BgmStatis, err error) {
  131. bgms = make(map[string]*model.BgmStatis)
  132. var id int64
  133. for {
  134. var bgm []*model.BgmStatis
  135. bgm, err = s.dao.BgmStatis(c, id, _limitSize)
  136. if err != nil {
  137. return
  138. }
  139. for _, b := range bgm {
  140. key := fmt.Sprintf("%d+%d", b.SID, b.AID)
  141. bgms[key] = b
  142. }
  143. if len(bgm) < _limitSize {
  144. break
  145. }
  146. id = bgm[len(bgm)-1].ID
  147. }
  148. return
  149. }
  150. func (s *Service) bgmCharges(c context.Context, date time.Time, ch chan []*model.BgmCharge, avBgmCharge chan []*model.AvCharge) (dailyMap map[string]*model.BgmCharge, err error) {
  151. dailyMap = make(map[string]*model.BgmCharge)
  152. bgms, err := s.GetBgms(c, int64(_limitSize))
  153. if err != nil {
  154. log.Error("s.GetBgms error(%v)", err)
  155. return
  156. }
  157. defer func() {
  158. close(ch)
  159. }()
  160. for avs := range avBgmCharge {
  161. for _, av := range avs {
  162. bgm, ok := bgms[av.AvID]
  163. if !ok {
  164. continue
  165. }
  166. incCharge := int64(round(div(mul(float64(av.IncCharge), float64(0.3)), float64(len(bgm))), 0))
  167. if incCharge == 0 {
  168. continue
  169. }
  170. charges := make([]*model.BgmCharge, 0, len(bgm))
  171. for _, b := range bgm {
  172. if b.MID == av.MID {
  173. continue
  174. }
  175. c := &model.BgmCharge{
  176. SID: b.SID,
  177. MID: b.MID,
  178. AID: b.AID,
  179. CID: b.CID,
  180. IncCharge: incCharge,
  181. JoinAt: b.JoinAt,
  182. Date: av.Date,
  183. Title: b.Title,
  184. DBState: _dbInsert,
  185. }
  186. dailyMap[fmt.Sprintf("%d+%d", c.SID, c.AID)] = c
  187. charges = append(charges, c)
  188. }
  189. ch <- charges
  190. }
  191. }
  192. return
  193. }
  194. // GetBgms map[av_id][]*model.Bgm
  195. func (s *Service) GetBgms(c context.Context, limit int64) (bm map[int64][]*model.Bgm, err error) {
  196. var id int64
  197. bm = make(map[int64][]*model.Bgm)
  198. for {
  199. var bs []*model.Bgm
  200. bs, id, err = s.dao.GetBgm(c, id, limit)
  201. if err != nil {
  202. return
  203. }
  204. if len(bs) == 0 {
  205. break
  206. }
  207. for _, b := range bs {
  208. if _, ok := bm[b.AID]; ok {
  209. bm[b.AID] = append(bm[b.AID], b)
  210. } else {
  211. bm[b.AID] = []*model.Bgm{b}
  212. }
  213. }
  214. }
  215. return
  216. }
  217. func round(val float64, places int) float64 {
  218. var round float64
  219. pow := math.Pow(10, float64(places))
  220. digit := pow * val
  221. _, div := math.Modf(digit)
  222. if div >= 0.5 {
  223. round = math.Ceil(digit)
  224. } else {
  225. round = math.Floor(digit)
  226. }
  227. return round / pow
  228. }
  229. func div(x, y float64) float64 {
  230. a := big.NewFloat(x)
  231. b := big.NewFloat(y)
  232. c := new(big.Float).Quo(a, b)
  233. d, _ := c.Float64()
  234. return d
  235. }
  236. func mul(x, y float64) float64 {
  237. a := big.NewFloat(x)
  238. b := big.NewFloat(y)
  239. c := new(big.Float).Mul(a, b)
  240. d, _ := c.Float64()
  241. return d
  242. }
  243. func (s *Service) bgmDBStore(c context.Context, table string, bgmMap map[string]*model.BgmCharge) error {
  244. insert, update := make([]*model.BgmCharge, _batchSize), make([]*model.BgmCharge, _batchSize)
  245. insertIndex, updateIndex := 0, 0
  246. for _, charge := range bgmMap {
  247. if charge.DBState == _dbInsert {
  248. insert[insertIndex] = charge
  249. insertIndex++
  250. } else if charge.DBState == _dbUpdate {
  251. update[updateIndex] = charge
  252. updateIndex++
  253. }
  254. if insertIndex >= _batchSize {
  255. _, err := s.bgmBatchInsert(c, insert[:insertIndex], table)
  256. if err != nil {
  257. log.Error("s.bgmBatchInsert error(%v)", err)
  258. return err
  259. }
  260. insertIndex = 0
  261. }
  262. if updateIndex >= _batchSize {
  263. _, err := s.bgmBatchInsert(c, update[:updateIndex], table)
  264. if err != nil {
  265. log.Error("s.bgmBatchInsert error(%v)", err)
  266. return err
  267. }
  268. updateIndex = 0
  269. }
  270. }
  271. if insertIndex > 0 {
  272. _, err := s.bgmBatchInsert(c, insert[:insertIndex], table)
  273. if err != nil {
  274. log.Error("s.bgmBatchInsert error(%v)", err)
  275. return err
  276. }
  277. }
  278. if updateIndex > 0 {
  279. _, err := s.bgmBatchInsert(c, update[:updateIndex], table)
  280. if err != nil {
  281. log.Error("s.bgmBatchInsert error(%v)", err)
  282. return err
  283. }
  284. }
  285. return nil
  286. }
  287. func assembleBgmCharge(charges []*model.BgmCharge) (vals string) {
  288. var buf bytes.Buffer
  289. for _, row := range charges {
  290. buf.WriteString("(")
  291. buf.WriteString(strconv.FormatInt(row.SID, 10))
  292. buf.WriteByte(',')
  293. buf.WriteString(strconv.FormatInt(row.AID, 10))
  294. buf.WriteByte(',')
  295. buf.WriteString(strconv.FormatInt(row.MID, 10))
  296. buf.WriteByte(',')
  297. buf.WriteString(strconv.FormatInt(row.CID, 10))
  298. buf.WriteByte(',')
  299. buf.WriteString("\"" + strings.Replace(row.Title, "\"", "\\\"", -1) + "\"")
  300. buf.WriteByte(',')
  301. buf.WriteString(strconv.FormatInt(row.IncCharge, 10))
  302. buf.WriteByte(',')
  303. buf.WriteString("'" + row.Date.Time().Format(_layout) + "'")
  304. buf.WriteByte(',')
  305. buf.WriteString("'" + row.JoinAt.Time().Format(_layoutSec) + "'")
  306. buf.WriteString(")")
  307. buf.WriteByte(',')
  308. }
  309. if buf.Len() > 0 {
  310. buf.Truncate(buf.Len() - 1)
  311. }
  312. vals = buf.String()
  313. buf.Reset()
  314. return
  315. }
  316. func (s *Service) bgmBatchInsert(c context.Context, charges []*model.BgmCharge, table string) (rows int64, err error) {
  317. vals := assembleBgmCharge(charges)
  318. rows, err = s.dao.InsertBgmChargeTable(c, vals, table)
  319. return
  320. }
  321. func (s *Service) bgmStatisDBStore(c context.Context, statisMap map[string]*model.BgmStatis) error {
  322. insert, update := make([]*model.BgmStatis, _batchSize), make([]*model.BgmStatis, _batchSize)
  323. insertIndex, updateIndex := 0, 0
  324. for _, charge := range statisMap {
  325. if charge.DBState == _dbInsert {
  326. insert[insertIndex] = charge
  327. insertIndex++
  328. } else if charge.DBState == _dbUpdate {
  329. update[updateIndex] = charge
  330. updateIndex++
  331. }
  332. if insertIndex >= _batchSize {
  333. _, err := s.bgmStatisBatchInsert(c, insert[:insertIndex])
  334. if err != nil {
  335. log.Error("s.bgmStatisBatchInsert error(%v)", err)
  336. return err
  337. }
  338. insertIndex = 0
  339. }
  340. if updateIndex >= _batchSize {
  341. _, err := s.bgmStatisBatchInsert(c, update[:updateIndex])
  342. if err != nil {
  343. log.Error("s.bgmStatisBatchInsert error(%v)", err)
  344. return err
  345. }
  346. updateIndex = 0
  347. }
  348. }
  349. if insertIndex > 0 {
  350. _, err := s.bgmStatisBatchInsert(c, insert[:insertIndex])
  351. if err != nil {
  352. log.Error("s.bgmStatisBatchInsert error(%v)", err)
  353. return err
  354. }
  355. }
  356. if updateIndex > 0 {
  357. _, err := s.bgmStatisBatchInsert(c, update[:updateIndex])
  358. if err != nil {
  359. log.Error("s.bgmStatisBatchInsert error(%v)", err)
  360. return err
  361. }
  362. }
  363. return nil
  364. }
  365. func assembleBgmStatis(statis []*model.BgmStatis) (vals string) {
  366. var buf bytes.Buffer
  367. for _, row := range statis {
  368. buf.WriteString("(")
  369. buf.WriteString(strconv.FormatInt(row.SID, 10))
  370. buf.WriteByte(',')
  371. buf.WriteString(strconv.FormatInt(row.AID, 10))
  372. buf.WriteByte(',')
  373. buf.WriteString(strconv.FormatInt(row.MID, 10))
  374. buf.WriteByte(',')
  375. buf.WriteString(strconv.FormatInt(row.CID, 10))
  376. buf.WriteByte(',')
  377. buf.WriteString("\"" + strings.Replace(row.Title, "\"", "\\\"", -1) + "\"")
  378. buf.WriteByte(',')
  379. buf.WriteString(strconv.FormatInt(row.TotalCharge, 10))
  380. buf.WriteByte(',')
  381. buf.WriteString("'" + row.JoinAt.Time().Format(_layoutSec) + "'")
  382. buf.WriteString(")")
  383. buf.WriteByte(',')
  384. }
  385. if buf.Len() > 0 {
  386. buf.Truncate(buf.Len() - 1)
  387. }
  388. vals = buf.String()
  389. buf.Reset()
  390. return
  391. }
  392. func (s *Service) bgmStatisBatchInsert(c context.Context, statis []*model.BgmStatis) (rows int64, err error) {
  393. vals := assembleBgmStatis(statis)
  394. rows, err = s.dao.InsertBgmStatisBatch(c, vals)
  395. return
  396. }