135 lines
3.5 KiB
Go
135 lines
3.5 KiB
Go
|
package usersuit
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"sync"
|
||
|
"time"
|
||
|
|
||
|
"go-common/app/interface/main/account/model"
|
||
|
accmdl "go-common/app/service/main/account/model"
|
||
|
usmdl "go-common/app/service/main/usersuit/model"
|
||
|
"go-common/library/log"
|
||
|
"go-common/library/net/metadata"
|
||
|
"go-common/library/sync/errgroup"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
_batch = 20
|
||
|
_fetchInfoTimeout = time.Second * 10
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
_emptyRichInvites = make([]*model.RichInvite, 0)
|
||
|
_emptyInfoMap = make(map[int64]*accmdl.Info)
|
||
|
)
|
||
|
|
||
|
// Buy buy invite code.
|
||
|
func (s *Service) Buy(c context.Context, mid int64, num int64) (res []*model.RichInvite, err error) {
|
||
|
var invs []*usmdl.Invite
|
||
|
ip := metadata.String(c, metadata.RemoteIP)
|
||
|
arg := &usmdl.ArgBuy{Mid: mid, Num: num, IP: ip}
|
||
|
if invs, err = s.usRPC.Buy(c, arg); err != nil {
|
||
|
log.Error("service.userserviceRPC.Buy(%v) error(%v)", arg, err)
|
||
|
return
|
||
|
}
|
||
|
res = make([]*model.RichInvite, 0)
|
||
|
for _, inv := range invs {
|
||
|
res = append(res, model.NewRichInvite(inv, nil))
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Apply apply invite code.
|
||
|
func (s *Service) Apply(c context.Context, mid int64, code string, cookie string) (err error) {
|
||
|
ip := metadata.String(c, metadata.RemoteIP)
|
||
|
arg := &usmdl.ArgApply{Mid: mid, Code: code, Cookie: cookie, IP: ip}
|
||
|
if err = s.usRPC.Apply(c, arg); err != nil {
|
||
|
log.Error("service.userserviceRPC.Apply(%v) error(%v)", arg, err)
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Stat get user's invite code stat.
|
||
|
func (s *Service) Stat(c context.Context, mid int64) (res *model.RichInviteStat, err error) {
|
||
|
var st *usmdl.InviteStat
|
||
|
ip := metadata.String(c, metadata.RemoteIP)
|
||
|
arg := &usmdl.ArgStat{Mid: mid, IP: ip}
|
||
|
if st, err = s.usRPC.Stat(c, arg); err != nil {
|
||
|
log.Error("service.userserviceRPC.Stat(%v) error(%v)", arg, err)
|
||
|
return
|
||
|
}
|
||
|
res = &model.RichInviteStat{
|
||
|
Mid: st.Mid,
|
||
|
CurrentLimit: st.CurrentLimit,
|
||
|
CurrentBought: st.CurrentBought,
|
||
|
TotalBought: st.TotalBought,
|
||
|
TotalUsed: st.TotalUsed,
|
||
|
InviteCodes: s.fillInviteeInfo(c, st.InviteCodes, ip),
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (s *Service) fillInviteeInfo(c context.Context, invs []*usmdl.Invite, ip string) []*model.RichInvite {
|
||
|
if len(invs) == 0 {
|
||
|
return _emptyRichInvites
|
||
|
}
|
||
|
imidm := make(map[int64]int)
|
||
|
for _, inv := range invs {
|
||
|
if inv.Status == usmdl.StatusUsed {
|
||
|
imidm[inv.Imid] = 1
|
||
|
}
|
||
|
}
|
||
|
infom := _emptyInfoMap
|
||
|
if len(imidm) > 0 {
|
||
|
imids := make([]int64, 0, len(imidm))
|
||
|
for imid := range imidm {
|
||
|
imids = append(imids, imid)
|
||
|
}
|
||
|
var err1 error
|
||
|
if infom, err1 = s.fetchInfos(c, imids, ip, _fetchInfoTimeout); err1 != nil {
|
||
|
log.Error("service.fetchInfos(%v, %s, %v) error(%v)", imids, ip, _fetchInfoTimeout, err1)
|
||
|
}
|
||
|
}
|
||
|
rinvs := make([]*model.RichInvite, 0)
|
||
|
for _, inv := range invs {
|
||
|
rinvs = append(rinvs, model.NewRichInvite(inv, infom[inv.Imid]))
|
||
|
}
|
||
|
return rinvs
|
||
|
}
|
||
|
|
||
|
func (s *Service) fetchInfos(c context.Context, mids []int64, ip string, timeout time.Duration) (res map[int64]*accmdl.Info, err error) {
|
||
|
if len(mids) == 0 {
|
||
|
res = _emptyInfoMap
|
||
|
return
|
||
|
}
|
||
|
batches := len(mids)/_batch + 1
|
||
|
tc, cancel := context.WithTimeout(c, timeout)
|
||
|
defer cancel()
|
||
|
eg, errCtx := errgroup.WithContext(tc)
|
||
|
bms := make([]map[int64]*accmdl.Info, batches)
|
||
|
mu := sync.Mutex{}
|
||
|
for i := 0; i < batches; i++ {
|
||
|
idx := i
|
||
|
end := (idx + 1) * _batch
|
||
|
if idx == batches-1 {
|
||
|
end = len(mids)
|
||
|
}
|
||
|
ids := mids[idx*_batch : end]
|
||
|
eg.Go(func() error {
|
||
|
m, err1 := s.accRPC.Infos3(errCtx, &accmdl.ArgMids{Mids: ids})
|
||
|
mu.Lock()
|
||
|
bms[idx] = m
|
||
|
mu.Unlock()
|
||
|
return err1
|
||
|
})
|
||
|
}
|
||
|
err = eg.Wait()
|
||
|
res = make(map[int64]*accmdl.Info)
|
||
|
for _, bm := range bms {
|
||
|
for mid, info := range bm {
|
||
|
res[mid] = info
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|