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)) }