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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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