You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

210 lines
5.9 KiB
Go

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