gift.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. package v1
  2. import (
  3. "context"
  4. v1pb "go-common/app/interface/live/app-room/api/http/v1"
  5. "go-common/app/interface/live/app-room/conf"
  6. "go-common/app/interface/live/app-room/dao"
  7. "go-common/app/interface/live/app-room/model"
  8. "go-common/app/service/live/gift/api/grpc/v1"
  9. "go-common/library/ecode"
  10. "go-common/library/log"
  11. "go-common/library/net/metadata"
  12. "go-common/library/sync/errgroup"
  13. "strconv"
  14. "time"
  15. )
  16. // GiftService struct
  17. type GiftService struct {
  18. conf *conf.Config
  19. // optionally add other properties here, such as dao
  20. // dao *dao.Dao
  21. client v1.GiftClient
  22. dao *dao.Dao
  23. }
  24. const (
  25. // HasShow 已经展示
  26. HasShow = 302
  27. // StopPush 停止推送
  28. StopPush = 403
  29. )
  30. //NewGiftService init
  31. func NewGiftService(c *conf.Config) (s *GiftService) {
  32. s = &GiftService{
  33. conf: c,
  34. dao: dao.New(c),
  35. }
  36. cli, err := v1.NewClient(conf.Conf.Warden)
  37. if err != nil {
  38. panic(err)
  39. }
  40. s.client = cli
  41. return s
  42. }
  43. // DailyBag implementation
  44. // `method:"GET" midware:"guest"`
  45. func (s *GiftService) DailyBag(ctx context.Context, req *v1pb.DailyBagReq) (resp *v1pb.DailyBagResp, err error) {
  46. resp = &v1pb.DailyBagResp{}
  47. mid, _ := metadata.Value(ctx, metadata.Mid).(int64)
  48. if mid <= 0 {
  49. err = ecode.NoLogin
  50. return
  51. }
  52. //mid = 88895029
  53. ret, err := s.client.DailyBag(ctx, &v1.DailyBagReq{
  54. Uid: mid,
  55. })
  56. if err != nil {
  57. err = ecode.Error(-1, "系统错误")
  58. return
  59. }
  60. resp = &v1pb.DailyBagResp{
  61. BagStatus: ret.BagStatus,
  62. BagExpireStatus: ret.BagExpireStatus,
  63. BagToast: &v1pb.DailyBagResp_BagToast{
  64. ToastStatus: ret.BagToast.ToastStatus,
  65. ToastMessage: ret.BagToast.ToastMessage,
  66. },
  67. BagList: make([]*v1pb.DailyBagResp_BagList, 0),
  68. }
  69. for _, v := range ret.BagList {
  70. s := &v1pb.DailyBagResp_BagList_Source{}
  71. if v.Source != nil {
  72. s = &v1pb.DailyBagResp_BagList_Source{
  73. MedalId: v.Source.MedalId,
  74. MedalName: v.Source.MedalName,
  75. Level: v.Source.Level,
  76. UserLevel: v.Source.UserLevel,
  77. }
  78. }
  79. tmp := &v1pb.DailyBagResp_BagList{
  80. Type: v.Type,
  81. BagName: v.BagName,
  82. Source: s,
  83. }
  84. for _, v2 := range v.GiftList {
  85. tmp.GiftList = append(tmp.GiftList, &v1pb.DailyBagResp_BagList_GiftList{
  86. GiftId: v2.GiftId,
  87. GiftNum: v2.GiftNum,
  88. ExpireAt: v2.ExpireAt,
  89. })
  90. }
  91. resp.BagList = append(resp.BagList, tmp)
  92. }
  93. return
  94. }
  95. // 实际充值的金瓜子数 最小单位是1000
  96. func realRechargeGold(gold int64) (realGold int64) {
  97. if gold%1000 == 0 {
  98. realGold = gold
  99. } else {
  100. realGold = gold + 1000 - gold%1000
  101. }
  102. return
  103. }
  104. func day(t time.Time) int {
  105. s := t.Format("2")
  106. d, _ := strconv.Atoi(s)
  107. return d
  108. }
  109. func yearMonthNum(t time.Time) int64 {
  110. yearMonth, _ := strconv.ParseInt(t.Format("200601"), 10, 64)
  111. return yearMonth
  112. }
  113. // 银瓜子是否提醒
  114. func (s *GiftService) silverNeedTipRecharge(ctx context.Context, mid int64, req *v1pb.NeedTipRechargeReq) (resp *v1pb.NeedTipRechargeResp, err error) {
  115. resp = &v1pb.NeedTipRechargeResp{}
  116. d := day(time.Now())
  117. dHit := false
  118. for _, v := range s.conf.Gift.RechargeTip.SilverTipDays {
  119. if v == d {
  120. dHit = true
  121. break
  122. }
  123. }
  124. if !dHit { // 日期
  125. log.Info("silver not show because day not hit %d mid:%d", d, mid)
  126. return
  127. }
  128. yearMonth := yearMonthNum(time.Now())
  129. defer func() {
  130. if resp.Show == 1 {
  131. s.dao.AsyncSetUserConf(ctx, mid, model.SilverTarget, yearMonth)
  132. }
  133. }()
  134. // 每月只推一次
  135. userConf, err := s.dao.GetUserConf(ctx, mid, model.SilverTarget, []int64{yearMonth, StopPush})
  136. if err != nil {
  137. err = ecode.ServerErr
  138. return
  139. }
  140. if userConf.IsSet(yearMonth) || userConf.IsSet(StopPush) {
  141. log.Info("silver not show because userConf yearMonth:%v stopPush:%v mid:%d", userConf.IsSet(yearMonth), userConf.IsSet(StopPush), mid)
  142. return
  143. }
  144. w, err := s.dao.PayCenterWallet(ctx, mid, req.Platform)
  145. if err != nil {
  146. return
  147. }
  148. if w.CouponBalance < 1 { // bp coupon >= 1
  149. log.Info("silver not show because couponBalance less than 1 %f mid:%d", w.CouponBalance, mid)
  150. return
  151. }
  152. resp.Bp = w.BcoinBalance
  153. resp.BpCoupon = w.CouponBalance
  154. resp.Show = 1
  155. resp.RechargeGold = 0
  156. log.Info("SilverShow mid:%d coupon:%f", mid, w.CouponBalance)
  157. return
  158. }
  159. // 金瓜子是否提醒
  160. func (s *GiftService) goldNeedTipRecharge(ctx context.Context, mid int64, req *v1pb.NeedTipRechargeReq) (resp *v1pb.NeedTipRechargeResp, err error) {
  161. resp = &v1pb.NeedTipRechargeResp{}
  162. defer func() {
  163. if resp.Show == 1 {
  164. s.dao.AsyncSetUserConf(ctx, mid, model.GoldTarget, HasShow) // 设置已经展示过
  165. }
  166. }()
  167. userConf, err := s.dao.GetUserConf(ctx, mid, model.GoldTarget, []int64{HasShow}) // 是否已经展示过
  168. if err != nil {
  169. err = ecode.ServerErr
  170. return
  171. }
  172. if userConf.IsSet(HasShow) {
  173. log.Info("gold not show because has show mid:%d", mid)
  174. return
  175. }
  176. eg, errCtx := errgroup.WithContext(ctx)
  177. var payCenterWallet *model.Wallet
  178. var liveWallet *model.LiveWallet
  179. eg.Go(func() error {
  180. var pErr error
  181. payCenterWallet, pErr = s.dao.PayCenterWallet(errCtx, mid, req.Platform)
  182. return pErr
  183. })
  184. eg.Go(func() error {
  185. var lErr error
  186. liveWallet, lErr = s.dao.LiveWallet(errCtx, mid, req.Platform)
  187. return lErr
  188. })
  189. err = eg.Wait()
  190. if err != nil {
  191. return
  192. }
  193. if liveWallet.GoldPayCnt > 0 { // 历史上没有消费过金瓜子
  194. log.Info("gold not show because gold pay cnt lt 0 %d mid:%d", liveWallet.GoldPayCnt, mid)
  195. return
  196. }
  197. if payCenterWallet.BcoinBalance < 1 { // bp余额大于1
  198. log.Info("gold not show because bcoin lt 1 %f mid:%d", payCenterWallet.BcoinBalance, mid)
  199. return
  200. }
  201. bpGold := int64(payCenterWallet.BcoinBalance * 1000)
  202. realRechargeGold := realRechargeGold(req.NeedGold)
  203. if bpGold < realRechargeGold { // 金瓜子差值
  204. log.Info("gold not show because bcoin lt gold bcoin:%f gold:%d mid:%d", payCenterWallet.BcoinBalance, realRechargeGold, mid)
  205. return
  206. }
  207. resp.Bp = payCenterWallet.BcoinBalance
  208. resp.BpCoupon = payCenterWallet.CouponBalance
  209. resp.Show = 1
  210. resp.RechargeGold = realRechargeGold
  211. log.Info("GoldShow mid:%d bp:%f goldPayCnt:%d needGold:%d", mid, payCenterWallet.BcoinBalance, liveWallet.GoldPayCnt, req.NeedGold)
  212. return
  213. }
  214. // NeedTipRecharge implementation
  215. //
  216. // `midware:"auth"`
  217. func (s *GiftService) NeedTipRecharge(ctx context.Context, req *v1pb.NeedTipRechargeReq) (resp *v1pb.NeedTipRechargeResp, err error) {
  218. mid := metadata.Value(ctx, metadata.Mid).(int64)
  219. if req.From == v1pb.From_Gold {
  220. return s.goldNeedTipRecharge(ctx, mid, req)
  221. } else if req.From == v1pb.From_Silver {
  222. return s.silverNeedTipRecharge(ctx, mid, req)
  223. }
  224. err = ecode.RequestErr
  225. resp = &v1pb.NeedTipRechargeResp{}
  226. return
  227. }
  228. // TipRechargeAction implementation
  229. //
  230. // `midware:"auth"`
  231. // `method:"post"`
  232. func (s *GiftService) TipRechargeAction(ctx context.Context, req *v1pb.TipRechargeActionReq) (resp *v1pb.TipRechargeActionResp, err error) {
  233. resp = &v1pb.TipRechargeActionResp{}
  234. mid := metadata.Value(ctx, metadata.Mid).(int64)
  235. if req.From == v1pb.From_Silver && req.Action == v1pb.UserAction_StopPush {
  236. err = s.dao.SetUserConf(ctx, mid, model.SilverTarget, StopPush)
  237. } else {
  238. err = ecode.RequestErr
  239. }
  240. return
  241. }
  242. // GiftConfig implementation
  243. func (s *GiftService) GiftConfig(ctx context.Context, req *v1pb.GiftConfigReq) (resp *v1pb.GiftConfigResp, err error) {
  244. resp = &v1pb.GiftConfigResp{
  245. List: make([]*v1pb.GiftConfigResp_Config, 0),
  246. }
  247. ret, err := s.client.GiftConfig(ctx, &v1.GiftConfigReq{
  248. Platform: req.Platform,
  249. Build: req.Build,
  250. })
  251. if err != nil {
  252. log.Error("get gift config err,%v", err)
  253. err = ecode.Error(-1, "系统错误")
  254. return
  255. }
  256. for _, v := range ret.Data {
  257. countMap := make([]*v1pb.GiftConfigResp_CountMap, 0)
  258. for _, c := range v.CountMap {
  259. tmp := &v1pb.GiftConfigResp_CountMap{
  260. Num: c.Num,
  261. Text: c.Text,
  262. }
  263. countMap = append(countMap, tmp)
  264. }
  265. d := &v1pb.GiftConfigResp_Config{
  266. Id: v.Id,
  267. Name: v.Name,
  268. Price: v.Price,
  269. Type: v.Type,
  270. CoinType: v.CoinType,
  271. BagGift: v.BagGift,
  272. Effect: v.Effect,
  273. CornerMark: v.CornerMark,
  274. Broadcast: v.Broadcast,
  275. Draw: v.Draw,
  276. StayTime: v.StayTime,
  277. AnimationFrameNum: v.AnimationFrameNum,
  278. Desc: v.Desc,
  279. Rule: v.Rule,
  280. Rights: v.Rights,
  281. PrivilegeRequired: v.PrivilegeRequired,
  282. CountMap: countMap,
  283. ImgBasic: v.ImgBasic,
  284. ImgDynamic: v.ImgDynamic,
  285. FrameAnimation: v.FrameAnimation,
  286. Gif: v.Gif,
  287. Webp: v.Webp,
  288. FullScWeb: v.FullScWeb,
  289. FullScHorizontal: v.FullScHorizontal,
  290. FullScVertical: v.FullScVertical,
  291. FullScHorizontalSvga: v.FullScHorizontalSvga,
  292. FullScVerticalSvga: v.FullScVerticalSvga,
  293. BulletHead: v.BulletHead,
  294. BulletTail: v.BulletTail,
  295. LimitInterval: v.LimitInterval,
  296. }
  297. resp.List = append(resp.List, d)
  298. }
  299. return
  300. }