You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
3.5 KiB
134 lines
3.5 KiB
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 |
|
}
|
|
|