123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- package charge
- import (
- "bytes"
- "context"
- "fmt"
- "math"
- "math/big"
- "strconv"
- "strings"
- "time"
- model "go-common/app/job/main/growup/model/charge"
- "go-common/library/log"
- xtime "go-common/library/time"
- "golang.org/x/sync/errgroup"
- )
- func (s *Service) handleBgm(c context.Context, date time.Time,
- dailyChannel chan []*model.BgmCharge) (weekly, monthly map[string]*model.BgmCharge, statis map[string]*model.BgmStatis, err error) {
- var eg errgroup.Group
- weekly = make(map[string]*model.BgmCharge)
- monthly = make(map[string]*model.BgmCharge)
- statis = make(map[string]*model.BgmStatis)
- eg.Go(func() (err error) {
- weekly, err = s.getBgmCharge(c, getStartWeeklyDate(date), "bgm_weekly_charge")
- if err != nil {
- log.Error("s.GetBgmCharge(bgm_weekly_charge) error(%v)", err)
- return
- }
- return
- })
- eg.Go(func() (err error) {
- monthly, err = s.getBgmCharge(c, getStartMonthlyDate(date), "bgm_monthly_charge")
- if err != nil {
- log.Error("s.GetBgmCharge(bgm_monthly_charge) error(%v)", err)
- return
- }
- return
- })
- eg.Go(func() (err error) {
- statis, err = s.getBgmStatis(c)
- if err != nil {
- log.Error("s.getBgmStatisMap error(%v)", err)
- }
- return
- })
- if err = eg.Wait(); err != nil {
- log.Error("handleBgm eg.Wait error(%v)", err)
- return
- }
- s.calBgms(date, weekly, monthly, statis, dailyChannel)
- return
- }
- func (s *Service) calBgms(date time.Time, weeklyMap, monthlyMap map[string]*model.BgmCharge, statisMap map[string]*model.BgmStatis, dailyChannel chan []*model.BgmCharge) {
- for daily := range dailyChannel {
- s.calBgm(date, daily, weeklyMap, monthlyMap, statisMap)
- }
- }
- func (s *Service) calBgm(date time.Time, daily []*model.BgmCharge, weeklyMap, monthlyMap map[string]*model.BgmCharge, statisMap map[string]*model.BgmStatis) {
- for _, charge := range daily {
- key := fmt.Sprintf("%d+%d", charge.SID, charge.AID)
- if weekly, ok := weeklyMap[key]; ok {
- updateBgmCharge(weekly, charge)
- } else {
- weeklyMap[key] = addBgmCharge(charge, startWeeklyDate)
- }
- if monthly, ok := monthlyMap[key]; ok {
- updateBgmCharge(monthly, charge)
- } else {
- monthlyMap[key] = addBgmCharge(charge, startMonthlyDate)
- }
- if statis, ok := statisMap[key]; ok {
- updateBgmStatis(statis, charge)
- } else {
- statisMap[key] = addBgmStatis(charge)
- }
- }
- }
- func addBgmCharge(daily *model.BgmCharge, fixDate time.Time) *model.BgmCharge {
- return &model.BgmCharge{
- SID: daily.SID,
- AID: daily.AID,
- MID: daily.MID,
- CID: daily.CID,
- JoinAt: daily.JoinAt,
- Title: daily.Title,
- IncCharge: daily.IncCharge,
- Date: xtime.Time(fixDate.Unix()),
- DBState: _dbInsert,
- }
- }
- func updateBgmCharge(origin, daily *model.BgmCharge) {
- origin.IncCharge += daily.IncCharge
- origin.DBState = _dbUpdate
- }
- func addBgmStatis(daily *model.BgmCharge) *model.BgmStatis {
- return &model.BgmStatis{
- SID: daily.SID,
- AID: daily.AID,
- MID: daily.MID,
- CID: daily.CID,
- JoinAt: daily.JoinAt,
- Title: daily.Title,
- TotalCharge: daily.IncCharge,
- DBState: _dbInsert,
- }
- }
- func updateBgmStatis(statis *model.BgmStatis, daily *model.BgmCharge) {
- statis.TotalCharge += daily.IncCharge
- statis.DBState = _dbUpdate
- }
- func (s *Service) getBgmCharge(c context.Context, date time.Time, table string) (bgms map[string]*model.BgmCharge, err error) {
- bgms = make(map[string]*model.BgmCharge)
- var id int64
- for {
- var bgm []*model.BgmCharge
- bgm, err = s.dao.BgmCharge(c, date, id, _limitSize, table)
- if err != nil {
- return
- }
- for _, b := range bgm {
- key := fmt.Sprintf("%d+%d", b.SID, b.AID)
- bgms[key] = b
- }
- if len(bgm) < _limitSize {
- break
- }
- id = bgm[len(bgm)-1].ID
- }
- return
- }
- func (s *Service) getBgmStatis(c context.Context) (bgms map[string]*model.BgmStatis, err error) {
- bgms = make(map[string]*model.BgmStatis)
- var id int64
- for {
- var bgm []*model.BgmStatis
- bgm, err = s.dao.BgmStatis(c, id, _limitSize)
- if err != nil {
- return
- }
- for _, b := range bgm {
- key := fmt.Sprintf("%d+%d", b.SID, b.AID)
- bgms[key] = b
- }
- if len(bgm) < _limitSize {
- break
- }
- id = bgm[len(bgm)-1].ID
- }
- return
- }
- 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) {
- dailyMap = make(map[string]*model.BgmCharge)
- bgms, err := s.GetBgms(c, int64(_limitSize))
- if err != nil {
- log.Error("s.GetBgms error(%v)", err)
- return
- }
- defer func() {
- close(ch)
- }()
- for avs := range avBgmCharge {
- for _, av := range avs {
- bgm, ok := bgms[av.AvID]
- if !ok {
- continue
- }
- incCharge := int64(round(div(mul(float64(av.IncCharge), float64(0.3)), float64(len(bgm))), 0))
- if incCharge == 0 {
- continue
- }
- charges := make([]*model.BgmCharge, 0, len(bgm))
- for _, b := range bgm {
- if b.MID == av.MID {
- continue
- }
- c := &model.BgmCharge{
- SID: b.SID,
- MID: b.MID,
- AID: b.AID,
- CID: b.CID,
- IncCharge: incCharge,
- JoinAt: b.JoinAt,
- Date: av.Date,
- Title: b.Title,
- DBState: _dbInsert,
- }
- dailyMap[fmt.Sprintf("%d+%d", c.SID, c.AID)] = c
- charges = append(charges, c)
- }
- ch <- charges
- }
- }
- return
- }
- // GetBgms map[av_id][]*model.Bgm
- func (s *Service) GetBgms(c context.Context, limit int64) (bm map[int64][]*model.Bgm, err error) {
- var id int64
- bm = make(map[int64][]*model.Bgm)
- for {
- var bs []*model.Bgm
- bs, id, err = s.dao.GetBgm(c, id, limit)
- if err != nil {
- return
- }
- if len(bs) == 0 {
- break
- }
- for _, b := range bs {
- if _, ok := bm[b.AID]; ok {
- bm[b.AID] = append(bm[b.AID], b)
- } else {
- bm[b.AID] = []*model.Bgm{b}
- }
- }
- }
- return
- }
- func round(val float64, places int) float64 {
- var round float64
- pow := math.Pow(10, float64(places))
- digit := pow * val
- _, div := math.Modf(digit)
- if div >= 0.5 {
- round = math.Ceil(digit)
- } else {
- round = math.Floor(digit)
- }
- return round / pow
- }
- func div(x, y float64) float64 {
- a := big.NewFloat(x)
- b := big.NewFloat(y)
- c := new(big.Float).Quo(a, b)
- d, _ := c.Float64()
- return d
- }
- func mul(x, y float64) float64 {
- a := big.NewFloat(x)
- b := big.NewFloat(y)
- c := new(big.Float).Mul(a, b)
- d, _ := c.Float64()
- return d
- }
- func (s *Service) bgmDBStore(c context.Context, table string, bgmMap map[string]*model.BgmCharge) error {
- insert, update := make([]*model.BgmCharge, _batchSize), make([]*model.BgmCharge, _batchSize)
- insertIndex, updateIndex := 0, 0
- for _, charge := range bgmMap {
- if charge.DBState == _dbInsert {
- insert[insertIndex] = charge
- insertIndex++
- } else if charge.DBState == _dbUpdate {
- update[updateIndex] = charge
- updateIndex++
- }
- if insertIndex >= _batchSize {
- _, err := s.bgmBatchInsert(c, insert[:insertIndex], table)
- if err != nil {
- log.Error("s.bgmBatchInsert error(%v)", err)
- return err
- }
- insertIndex = 0
- }
- if updateIndex >= _batchSize {
- _, err := s.bgmBatchInsert(c, update[:updateIndex], table)
- if err != nil {
- log.Error("s.bgmBatchInsert error(%v)", err)
- return err
- }
- updateIndex = 0
- }
- }
- if insertIndex > 0 {
- _, err := s.bgmBatchInsert(c, insert[:insertIndex], table)
- if err != nil {
- log.Error("s.bgmBatchInsert error(%v)", err)
- return err
- }
- }
- if updateIndex > 0 {
- _, err := s.bgmBatchInsert(c, update[:updateIndex], table)
- if err != nil {
- log.Error("s.bgmBatchInsert error(%v)", err)
- return err
- }
- }
- return nil
- }
- func assembleBgmCharge(charges []*model.BgmCharge) (vals string) {
- var buf bytes.Buffer
- for _, row := range charges {
- buf.WriteString("(")
- buf.WriteString(strconv.FormatInt(row.SID, 10))
- buf.WriteByte(',')
- buf.WriteString(strconv.FormatInt(row.AID, 10))
- buf.WriteByte(',')
- buf.WriteString(strconv.FormatInt(row.MID, 10))
- buf.WriteByte(',')
- buf.WriteString(strconv.FormatInt(row.CID, 10))
- buf.WriteByte(',')
- buf.WriteString("\"" + strings.Replace(row.Title, "\"", "\\\"", -1) + "\"")
- buf.WriteByte(',')
- buf.WriteString(strconv.FormatInt(row.IncCharge, 10))
- buf.WriteByte(',')
- buf.WriteString("'" + row.Date.Time().Format(_layout) + "'")
- buf.WriteByte(',')
- buf.WriteString("'" + row.JoinAt.Time().Format(_layoutSec) + "'")
- buf.WriteString(")")
- buf.WriteByte(',')
- }
- if buf.Len() > 0 {
- buf.Truncate(buf.Len() - 1)
- }
- vals = buf.String()
- buf.Reset()
- return
- }
- func (s *Service) bgmBatchInsert(c context.Context, charges []*model.BgmCharge, table string) (rows int64, err error) {
- vals := assembleBgmCharge(charges)
- rows, err = s.dao.InsertBgmChargeTable(c, vals, table)
- return
- }
- func (s *Service) bgmStatisDBStore(c context.Context, statisMap map[string]*model.BgmStatis) error {
- insert, update := make([]*model.BgmStatis, _batchSize), make([]*model.BgmStatis, _batchSize)
- insertIndex, updateIndex := 0, 0
- for _, charge := range statisMap {
- if charge.DBState == _dbInsert {
- insert[insertIndex] = charge
- insertIndex++
- } else if charge.DBState == _dbUpdate {
- update[updateIndex] = charge
- updateIndex++
- }
- if insertIndex >= _batchSize {
- _, err := s.bgmStatisBatchInsert(c, insert[:insertIndex])
- if err != nil {
- log.Error("s.bgmStatisBatchInsert error(%v)", err)
- return err
- }
- insertIndex = 0
- }
- if updateIndex >= _batchSize {
- _, err := s.bgmStatisBatchInsert(c, update[:updateIndex])
- if err != nil {
- log.Error("s.bgmStatisBatchInsert error(%v)", err)
- return err
- }
- updateIndex = 0
- }
- }
- if insertIndex > 0 {
- _, err := s.bgmStatisBatchInsert(c, insert[:insertIndex])
- if err != nil {
- log.Error("s.bgmStatisBatchInsert error(%v)", err)
- return err
- }
- }
- if updateIndex > 0 {
- _, err := s.bgmStatisBatchInsert(c, update[:updateIndex])
- if err != nil {
- log.Error("s.bgmStatisBatchInsert error(%v)", err)
- return err
- }
- }
- return nil
- }
- func assembleBgmStatis(statis []*model.BgmStatis) (vals string) {
- var buf bytes.Buffer
- for _, row := range statis {
- buf.WriteString("(")
- buf.WriteString(strconv.FormatInt(row.SID, 10))
- buf.WriteByte(',')
- buf.WriteString(strconv.FormatInt(row.AID, 10))
- buf.WriteByte(',')
- buf.WriteString(strconv.FormatInt(row.MID, 10))
- buf.WriteByte(',')
- buf.WriteString(strconv.FormatInt(row.CID, 10))
- buf.WriteByte(',')
- buf.WriteString("\"" + strings.Replace(row.Title, "\"", "\\\"", -1) + "\"")
- buf.WriteByte(',')
- buf.WriteString(strconv.FormatInt(row.TotalCharge, 10))
- buf.WriteByte(',')
- buf.WriteString("'" + row.JoinAt.Time().Format(_layoutSec) + "'")
- buf.WriteString(")")
- buf.WriteByte(',')
- }
- if buf.Len() > 0 {
- buf.Truncate(buf.Len() - 1)
- }
- vals = buf.String()
- buf.Reset()
- return
- }
- func (s *Service) bgmStatisBatchInsert(c context.Context, statis []*model.BgmStatis) (rows int64, err error) {
- vals := assembleBgmStatis(statis)
- rows, err = s.dao.InsertBgmStatisBatch(c, vals)
- return
- }
|