|
|
package msg_handler
|
|
|
|
|
|
import (
|
|
|
"fmt"
|
|
|
"git.noahlan.cn/northlan/ntools-go/kafka"
|
|
|
"git.noahlan.cn/northlan/ntools-go/logger"
|
|
|
jsoniter "github.com/json-iterator/go"
|
|
|
"io"
|
|
|
"live-gateway/config"
|
|
|
"live-gateway/douyu/stt"
|
|
|
kfk "live-gateway/pkg/kafka"
|
|
|
"net/http"
|
|
|
"strconv"
|
|
|
)
|
|
|
|
|
|
const (
|
|
|
giftTypeYuChi = "YUCHI"
|
|
|
giftTypeYuWan = "YUWAN"
|
|
|
)
|
|
|
|
|
|
type (
|
|
|
MsgGift struct {
|
|
|
RoomId int64 `stt:"rid"` // 房间ID
|
|
|
GiftId int64 `stt:"gfid"` // 礼物ID
|
|
|
GiftStyle string `stt:"gs"` // 礼物显示样式(不确定数字类型?用string避免错误)
|
|
|
UID int64 `stt:"uid"` // 用户ID
|
|
|
Nickname string `stt:"nn"` // 用户昵称
|
|
|
Avatar string `stt:"ic"` // 用户头像
|
|
|
|
|
|
// ... ignore eid & eic
|
|
|
|
|
|
Level int32 `stt:"level"` // 用户等级
|
|
|
Dw int64 `stt:"dw"` // 主播体重
|
|
|
GiftCount int64 `stt:"gfcnt"` // 礼物个数:默认值 1(表示 1 个礼物)
|
|
|
Hits int32 `stt:"hits"` // 礼物连击次数:默认值 1(表示 1 连击)
|
|
|
|
|
|
// ... ingore bcnd & bst & ct & el & cm &
|
|
|
|
|
|
FansMedal // 粉丝勋章
|
|
|
|
|
|
Sahf string `stt:"sahf"` // 扩展字段,一般不使用,可忽略
|
|
|
Fc int64 `stt:"fc"` // 攻击道具的攻击力
|
|
|
|
|
|
// ... ignore gpf & pid & bnid & bnl
|
|
|
|
|
|
ReceiveUID int64 `stt:"receive_uid"` // 接收礼物用户ID
|
|
|
ReceiveNickname string `stt:"receive_nn"` // 接收礼物用户昵称
|
|
|
|
|
|
// ... ignore from & pfm & pma & mss & bcst
|
|
|
|
|
|
//GroupId int64 `stt:"gid"` // 弹幕分组ID
|
|
|
//BigGift int32 `stt:"bg"` // 大礼物标识:默认值为 0(表示是小礼物)
|
|
|
//Dlv int32 `stt:"dlv"` // 酬勤头衔:默认值 0(表示没有酬勤)
|
|
|
//Dc int32 `stt:"dc"` // 酬勤个数:默认值 0(表示没有酬勤数量)
|
|
|
//Bdl int32 `stt:"bdl"` // 全站最高酬勤等级:默认值 0(表示全站都没有酬勤)
|
|
|
//Rg int32 `stt:"rg"` // 房间身份组:默认值 1(表示普通权限用户)5:UP
|
|
|
//Pg int32 `stt:"pg"` // 平台身份组:默认值 1(表示普通权限用户)
|
|
|
//Nl int32 `stt:"nl"` // 贵族等级:默认值 0(表示不是贵族)
|
|
|
}
|
|
|
MsgGiftHandler struct {
|
|
|
producer *kafka.Producer
|
|
|
liveRoomId int64
|
|
|
giftMap map[int64]GiftConfig
|
|
|
}
|
|
|
GiftConfig struct {
|
|
|
ID int64 `json:"id"` // 礼物ID
|
|
|
Name string `json:"name"` // 礼物名
|
|
|
Price int64 `json:"price"` // 价格 收费礼物则是 鱼翅*10,免费礼物则是 鱼丸
|
|
|
IsPaid bool `json:"-"` // 是否收费礼物
|
|
|
}
|
|
|
)
|
|
|
|
|
|
func NewMsgGiftHandler(liveRoomId int64) *MsgGiftHandler {
|
|
|
cfg := config.Config.Kafka.Gift
|
|
|
ret := &MsgGiftHandler{
|
|
|
producer: kafka.NewKafkaProducer(kfk.DefaultProducerConfig, cfg.Addr, cfg.Topic),
|
|
|
liveRoomId: liveRoomId,
|
|
|
giftMap: map[int64]GiftConfig{},
|
|
|
}
|
|
|
|
|
|
ret.setupGiftConfig()
|
|
|
return ret
|
|
|
}
|
|
|
|
|
|
func (m *MsgGiftHandler) setupGiftConfig() {
|
|
|
logger.SLog.Info("初始化 Douyu 礼物配置...")
|
|
|
// bagGiftData
|
|
|
{
|
|
|
httpResp, err := http.Get("https://webconf.douyucdn.cn/resource/common/prop_gift_list/prop_gift_config.json")
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
httpBodyResp, err := io.ReadAll(httpResp.Body)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
httpBodyResp = httpBodyResp[len("DYConfigCallback("):]
|
|
|
httpBodyResp = httpBodyResp[:len(httpBodyResp)-2]
|
|
|
|
|
|
var gf struct {
|
|
|
Data map[string]struct {
|
|
|
Name string `json:"name"`
|
|
|
Price int64 `json:"pc"`
|
|
|
} `json:"data"`
|
|
|
}
|
|
|
err = jsoniter.Unmarshal(httpBodyResp, &gf)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
for id, g := range gf.Data {
|
|
|
idInt, err := strconv.ParseInt(id, 10, 64)
|
|
|
if err != nil {
|
|
|
continue
|
|
|
}
|
|
|
gfCfg := GiftConfig{
|
|
|
ID: idInt,
|
|
|
Name: g.Name,
|
|
|
IsPaid: true,
|
|
|
Price: g.Price,
|
|
|
}
|
|
|
m.giftMap[gfCfg.ID] = gfCfg
|
|
|
}
|
|
|
}
|
|
|
// roomGiftData
|
|
|
{
|
|
|
httpResp, err := http.Get(fmt.Sprintf("https://gift.douyucdn.cn/api/gift/v3/web/list?rid=%d", m.liveRoomId))
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
httpBodyResp, err := io.ReadAll(httpResp.Body)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
type GiftPriceInfo struct {
|
|
|
Price int64 `json:"price"`
|
|
|
PriceType string `json:"priceType"`
|
|
|
}
|
|
|
var gf struct {
|
|
|
Data struct {
|
|
|
GiftList []struct {
|
|
|
ID int64 `json:"id"` // 礼物ID
|
|
|
Name string `json:"name"` // 礼物名
|
|
|
GiftPriceInfo `json:"priceInfo"` // 价格参数
|
|
|
} `json:"giftList"`
|
|
|
} `json:"data"`
|
|
|
}
|
|
|
err = jsoniter.Unmarshal(httpBodyResp, &gf)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
for _, g := range gf.Data.GiftList {
|
|
|
gfCfg := GiftConfig{
|
|
|
ID: g.ID,
|
|
|
Name: g.Name,
|
|
|
IsPaid: false,
|
|
|
Price: g.Price,
|
|
|
}
|
|
|
// 处理价格
|
|
|
if g.PriceType == giftTypeYuChi {
|
|
|
gfCfg.IsPaid = true
|
|
|
}
|
|
|
m.giftMap[gfCfg.ID] = gfCfg
|
|
|
}
|
|
|
}
|
|
|
|
|
|
logger.SLog.Infof("Douyu 礼物配置读取成功 num:%d", len(m.giftMap))
|
|
|
}
|
|
|
|
|
|
func (m *MsgGiftHandler) DataType() string {
|
|
|
return "dgb"
|
|
|
}
|
|
|
|
|
|
func (m *MsgGiftHandler) HandlerMessage(data []byte) {
|
|
|
var ret MsgGift
|
|
|
err := stt.Unmarshal(data, &ret)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if len(m.giftMap) == 0 {
|
|
|
m.setupGiftConfig()
|
|
|
}
|
|
|
|
|
|
giftConfig := m.giftMap[ret.GiftId]
|
|
|
logger.SLog.Debugf("%s 赠送: %+vx%d", ret.Nickname, giftConfig, ret.GiftCount)
|
|
|
|
|
|
//dmMsg := &pbMq.MqGift{
|
|
|
// Platform: pbVars.Platform_name[int32(pbVars.Platform_Douyu)],
|
|
|
// LiveRoomId: m.liveRoomId,
|
|
|
// MsgId: "",
|
|
|
// Timestamp: time.Now().UnixMicro(),
|
|
|
// Uid: ret.UID,
|
|
|
// Uname: ret.Nickname,
|
|
|
// Avatar: "https://apic.douyucdn.cn/upload/" + ret.Avatar, // TODO 暂时组合,应该保留原始,然后客户端配置
|
|
|
// NobilityLevel: 0,
|
|
|
// GiftId: ret.GiftId,
|
|
|
// GiftName: giftConfig.Name,
|
|
|
// GiftNum: ret.GiftCount,
|
|
|
// Price: giftConfig.Price,
|
|
|
// IsPaid: giftConfig.IsPaid,
|
|
|
// Type: pbMq.MqGift_NORMAL,
|
|
|
// PackGift: nil,
|
|
|
//
|
|
|
// FansMedalWearingStatus: ret.FansMedal.MedalRoomId == m.liveRoomId,
|
|
|
// FansMedalName: ret.FansMedal.MedalName,
|
|
|
// FansMedalLevel: ret.FansMedal.MedalLevel,
|
|
|
//}
|
|
|
//_ = m.producer.SendMessageAsync(dmMsg, strconv.FormatInt(dmMsg.Uid, 10))
|
|
|
}
|