package gift import ( "bet24.com/log" "bet24.com/servers/common" coreClient "bet24.com/servers/coreservice/client" badge "bet24.com/servers/micros/badge/proto" pb "bet24.com/servers/micros/giftservice/proto" item "bet24.com/servers/micros/item_inventory/proto" money "bet24.com/servers/micros/money/proto" notification "bet24.com/servers/micros/notification/proto" user "bet24.com/servers/micros/userservices/proto" "encoding/json" "sync" "time" ) var mgr *giftmanager func getGiftManager() *giftmanager { if mgr == nil { mgr = new(giftmanager) } return mgr } type chargeInfo struct { userId int toUserId int productId string } type giftmanager struct { giftlist []pb.Gift lastConfigString string penddingChargeList []pendingcharge lock *sync.RWMutex } func (gm *giftmanager) run() { log.Debug("giftmanager.run()") gm.lock = &sync.RWMutex{} gm.loadConfig() gm.checkPendingCharge() } func (gm *giftmanager) checkPendingCharge() { time.AfterFunc(1*time.Minute, gm.checkPendingCharge) gm.lock.Lock() defer gm.lock.Unlock() for i := 0; i < len(gm.penddingChargeList); { v := gm.penddingChargeList[i] if v.isTimeout() { log.Release("giftmanager.checkPendingCharge removing [%d->%d][%s]", v.userId, v.toUserId, v.productId) gm.penddingChargeList = append(gm.penddingChargeList[:i], gm.penddingChargeList[i+1:]...) } else { i++ } } } func (gm *giftmanager) dump(cmd, param1 string) { switch cmd { case "sys": gm.dumpSys() case "pending": gm.dumpPendingCharge() default: log.Release("giftmanager.dump unhandled cmd %s %s", cmd, param1) } } func (gm *giftmanager) dumpSys() { log.Release("-------------------------------") log.Release("giftmanager.dumpSys gift count[%d]", len(gm.giftlist)) defer func() { log.Release("+++++++++++++++++++++++++++++++") log.Release("") }() for _, v := range gm.giftlist { log.Release(" Id[%d]Name[%s]Price[%.1f]Charm[%d->%d]Items%v", v.GiftId, v.Name, v.Price, v.SenderCharm, v.ReceiverCharm, v.Items) } } func (gm *giftmanager) dumpPendingCharge() { gm.lock.RLock() defer gm.lock.RUnlock() log.Release("-------------------------------") log.Release("giftmanager.dumpPendingCharge gift count[%d]", len(gm.penddingChargeList)) defer func() { log.Release("+++++++++++++++++++++++++++++++") log.Release("") }() now := time.Now().Unix() for _, v := range gm.penddingChargeList { log.Release(" Id[%d]ToUserId[%d]ProductId[%s]Created[%d]", v.userId, v.toUserId, v.productId, now-v.createTime) } } func (gm *giftmanager) getGiftList(userId int) []pb.Gift { if len(gm.giftlist) == 0 { return nil } return gm.giftlist } func (gm *giftmanager) getGiftListString(userId int) string { list := gm.getGiftList(userId) if list == nil { return "" } d, _ := json.Marshal(list) return string(d) } func (gm *giftmanager) getGift(giftId int, userId int) *pb.Gift { if len(gm.giftlist) == 0 { return nil } for _, v := range gm.giftlist { if v.GiftId != giftId { continue } ret := v return &ret } return nil } func (gm *giftmanager) getGiftByProductId(productId string) *pb.Gift { if len(gm.giftlist) == 0 { return nil } for _, v := range gm.giftlist { if v.ProductId != productId { continue } ret := v return &ret } return nil } func (gm *giftmanager) sendGift(userId int, toUserId int, giftId int) (int, string) { if userId == 0 || toUserId == 0 || userId == toUserId { log.Release("giftmanager.sendGift UserId[%d->%d] GiftId[%d] invalid userId", userId, toUserId, giftId) return pb.SendGiftRet_Failed, "invalid userId " } g := gm.getGift(giftId, userId) if g == nil { log.Release("giftmanager.sendGift UserId[%d->%d] GiftId[%d] not found", userId, toUserId, giftId) return pb.SendGiftRet_Failed, "invalid giftId" } // 如果是赠送需要充值的物品,先记录,等充值完毕后再查询进行赠送 if g.PayType == pb.PayType_RMB { gm.addChargeList(userId, toUserId, g.ProductId) return pb.SendGiftRet_Charge, g.ProductId } if g.PayType == pb.PayType_Diamond { // 扣钻石 if money.ReduceChip(userId, int(g.Price), common.LOGTYPE_GIFT_SEND, "giftservice", "sendGift", "") != 1 { return pb.SendGiftRet_Failed, "not enough diamond" } } else { // 扣金币 if !money.ReduceMoney(userId, int(g.Price), common.LOGTYPE_GIFT_SEND, "giftservice", "sendGift", "") { return pb.SendGiftRet_Failed, "not enough gold" } // 徽章进度 go badge.DoAction(userId, badge.Action_PropConsumeGold, int(g.Price), badge.Scope{}) } gm.doSendGift(userId, toUserId, g) return pb.SendGiftRet_OK, "" } // 赠送礼物,没有需要充值的物品 func (gm *giftmanager) sendGiftBulk(userId int, toUserIds []int, giftId, num int) (int, string, *pb.Gift) { if userId == 0 || len(toUserIds) == 0 || num <= 0 { log.Release("giftmanager.sendGiftBulk UserId[%d->%+v] GiftId[%d] num[%d] invalid userId", userId, toUserIds, giftId, num) return pb.SendGiftRet_Failed, "invalid userId ", nil } g := gm.getGift(giftId, userId) if g == nil { log.Release("giftmanager.sendGiftBulk UserId[%d->%+v] GiftId[%d] num[%d] not found", userId, toUserIds, giftId, num) return pb.SendGiftRet_Failed, "invalid giftId", nil } items := make([]item.ItemPack, len(g.Items)) copy(items, g.Items) oneGift := &pb.Gift{ GiftId: g.GiftId, GiftType: g.GiftType, Name: g.Name, Desc: g.Name, Price: g.Price, PayType: g.PayType, ProductId: g.ProductId, SenderCharm: g.SenderCharm, ReceiverCharm: g.ReceiverCharm, Icon: g.Icon, Items: items, AnimationType: g.AnimationType, UserType: g.UserType, IsBottom: g.IsBottom, } // 计算总价(总价=单价*礼物数量*人数) totalPrice := int(oneGift.Price * float64(num*len(toUserIds))) // 多个礼物,计算总额 if num > 1 { for i := 0; i < len(oneGift.Items); i++ { oneGift.Items[i].Count = oneGift.Items[i].Count * num } } if oneGift.PayType == pb.PayType_Diamond { // 扣钻石 if money.ReduceChip(userId, totalPrice, common.LOGTYPE_GIFT_SEND, "giftservice", "sendGift", "") != 1 { return pb.SendGiftRet_Failed, "not enough diamond", nil } } else { // 扣金币 if !money.ReduceMoney(userId, totalPrice, common.LOGTYPE_GIFT_SEND, "giftservice", "sendGift", "") { return pb.SendGiftRet_Failed, "not enough gold", nil } } for _, toUserId := range toUserIds { gm.doSendGift(userId, toUserId, oneGift) } return pb.SendGiftRet_OK, "", oneGift } func (gm *giftmanager) addChargeList(userId, toUserId int, productId string) { // 去重 idx := gm.getChargeIndex(userId, toUserId, productId) if idx == -1 { gm.lock.Lock() gm.penddingChargeList = append(gm.penddingChargeList, pendingcharge{userId: userId, toUserId: toUserId, productId: productId}) gm.lock.Unlock() } } func (gm *giftmanager) getChargeIndex(userId, toUserId int, productId string) int { gm.lock.RLock() defer gm.lock.RUnlock() for k, v := range gm.penddingChargeList { if v.isSame(userId, toUserId, productId) { return k } } return -1 } func (gm *giftmanager) removeChargeInfo(userId, toUserId int, productId string) { gm.lock.Lock() defer gm.lock.Unlock() for i := 0; i < len(gm.penddingChargeList); { if gm.penddingChargeList[i].isSame(userId, toUserId, productId) { gm.penddingChargeList = append(gm.penddingChargeList[:i], gm.penddingChargeList[i+1:]...) } else { i++ } } } func (gm *giftmanager) getAndRemovePendingCharge(userId int, productId string) *pendingcharge { var ret *pendingcharge gm.lock.Lock() defer gm.lock.Unlock() for i := 0; i < len(gm.penddingChargeList); { if gm.penddingChargeList[i].isSame(userId, 0, productId) { ret = &pendingcharge{ userId: userId, productId: productId, toUserId: gm.penddingChargeList[i].toUserId, } gm.penddingChargeList = append(gm.penddingChargeList[:i], gm.penddingChargeList[i+1:]...) } else { i++ } } return ret } // 充值成功后看下是否为赠送 func (gm *giftmanager) checkGiftCharge(userId int, productId string) bool { pc := gm.getAndRemovePendingCharge(userId, productId) // 找不到 if pc == nil { return false } // 给对方发物品 g := gm.getGiftByProductId(productId) if g == nil { log.Release("giftmanager.checkGiftCharge [%d] [%s] not found", userId, productId) return false } return gm.doSendGift(userId, pc.toUserId, g) } func (gm *giftmanager) doSendGift(userId, toUserId int, g *pb.Gift) bool { // 成功了,给对方加道具 d, _ := json.Marshal(g.Items) ug := pb.UserGift{ Sender: userId, Receiver: toUserId, GiftId: g.GiftId, Items: string(d), SendTime: int(time.Now().Unix()), } ug.Rid = addUserGift(ug, g.GiftType) // 加魅力值 go user.AddUserCharm(userId, g.SenderCharm) go user.AddUserCharm(toUserId, g.ReceiverCharm) // 发送私聊信息 // 语音房不发私聊 ugData, _ := json.Marshal(ug) if pb.GiftType_AudioRoom != g.GiftType { coreClient.SendGiftMessage(userId, toUserId, string(ugData)) } // 发通知给对方 notification.AddNotification(userId, notification.Notification_GiftSent, string(ugData)) if g.AnimationType == pb.AnimationType_Global { notification.AddNotification(-1, notification.Notification_ReceiveGift, string(ugData)) } else { notification.AddNotification(toUserId, notification.Notification_ReceiveGift, string(ugData)) } // 潜在好友 go coreClient.FriendAddPotential(userId, toUserId, "send gift") go coreClient.FriendAddPotential(toUserId, userId, "receive gift") return true } func (gm *giftmanager) getUnclaimedGifts(userId int) []pb.UserGift { return getUnclaimedGifts(userId) } func (gm *giftmanager) claimGift(userId, rid int) string { itemString := claimUserGift(userId, rid, int(time.Now().Unix())) log.Debug("giftmanager.claimGift [%d][%d] returns %s", userId, rid, itemString) type tmpItems struct { Items string } var retItems []tmpItems err := json.Unmarshal([]byte(itemString), &retItems) if err != nil { log.Release("giftmanager.claimGift Unmarshal1 failed %s", itemString) return "" } if len(retItems) == 0 { return "" } var itms []item.ItemPack err = json.Unmarshal([]byte(retItems[0].Items), &itms) if err == nil && len(itms) > 0 { item.AddItems(userId, itms, "claim gift", common.LOGTYPE_GIFT_RECEIVE) } else { log.Release("giftmanager.claimGift Unmarshal2 failed %s", itemString) } return retItems[0].Items } func (gm *giftmanager) getReceivedGiftRecord(userId int) string { //log.Debug("giftmanager.getReceivedGiftRecord userId[%d]", userId) ret := getReceivedGiftHistory(userId, pb.GiftType_Nomal, 6) type tmpItems struct { GiftID int Items string } var itms []tmpItems err := json.Unmarshal([]byte(ret), &itms) if err != nil { log.Release("giftmanager.getReceivedGiftRecord Unmarshal failed %s", ret) return "" } //log.Debug("giftmanager.getReceivedGiftRecord userId[%d] itms[%s] ", userId, ret) type giftAndItems struct { GiftId int Items []item.ItemPack } var retItems []giftAndItems for _, v := range itms { var oneItems []item.ItemPack err := json.Unmarshal([]byte(v.Items), &oneItems) if err == nil { retItems = append(retItems, giftAndItems{GiftId: v.GiftID, Items: oneItems}) } else { log.Debug("giftmanager.getReceivedGiftRecord userId[%d] Unmarshal failed[%s]", userId, v.Items) } } d, _ := json.Marshal(retItems) log.Debug("giftmanager.getReceivedGiftRecord userId[%d] ret[%s] ", userId, string(d)) return string(d) }