From 76008c7098aeccdf702f15980adf73722506c6b0 Mon Sep 17 00:00:00 2001 From: NorthLan <6995syu@163.com> Date: Tue, 7 Jun 2022 01:07:52 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=8E=A5=E5=85=A5=E5=AE=98?= =?UTF-8?q?=E6=96=B9=E5=BC=B9=E5=B9=95API=EF=BC=8C=E5=90=8C=E6=97=B6?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E5=8E=9F=E9=87=8E=E7=94=9FAPI=E3=80=82?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E5=8D=8F=E8=AE=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bilibili/live.go | 233 ++++++++--- bilibili/message.go | 34 +- bilibili/msg_handler/common.go | 15 + bilibili/msg_handler/danmaku.go | 4 +- bilibili/msg_handler/danmaku_official.go | 77 ++++ bilibili/msg_handler/gift_official.go | 98 +++++ bilibili/msg_handler/guard_buy.go | 23 +- bilibili/msg_handler/guard_buy_official.go | 98 +++++ .../msg_handler/guard_buy_official_test.go | 14 + bilibili/msg_handler/send_gift.go | 44 +- bilibili/sign.go | 97 +++++ config-dev.yml | 10 +- config/config.go | 19 +- go.mod | 8 +- go.sum | 15 + main.go | 2 +- pb/mq.pb.go | 385 ++++++++++++------ pb/mq.proto | 62 ++- pkg/timex/expire.go | 28 ++ pkg/timex/parse.go | 22 + 20 files changed, 1045 insertions(+), 243 deletions(-) create mode 100644 bilibili/msg_handler/danmaku_official.go create mode 100644 bilibili/msg_handler/gift_official.go create mode 100644 bilibili/msg_handler/guard_buy_official.go create mode 100644 bilibili/msg_handler/guard_buy_official_test.go create mode 100644 bilibili/sign.go create mode 100644 pkg/timex/expire.go create mode 100644 pkg/timex/parse.go diff --git a/bilibili/live.go b/bilibili/live.go index 29bfe55..a21e8a7 100644 --- a/bilibili/live.go +++ b/bilibili/live.go @@ -4,12 +4,15 @@ import ( "encoding/json" "fmt" "git.noahlan.cn/northlan/ntools-go/logger" + "github.com/go-ping/ping" + "github.com/pkg/errors" "io/ioutil" "live-gateway/bilibili/msg_handler" "live-gateway/config" "live-gateway/live" "live-gateway/ws" "net/http" + "strconv" "strings" "time" ) @@ -22,30 +25,23 @@ type MsgHandler interface { // 实现 live.Handler 接口 var _ live.Handler = (*LiveBilibili)(nil) -type LiveBilibili struct { - Url string - GetRoomUrl string - RoomId int64 - UserId int64 - HeartbeatInterval time.Duration // 心跳间 +type ( + LiveBilibili struct { + *live.Live + sequenceId uint32 - RoomInfo *RoomInfo - Live *live.Live + roomInfo *RoomInfo // 房间信息 + webSocketInfo *WebsocketInfoResp // ws信息 - msgHandlerMapper map[string]MsgHandler - entered chan struct{} // 进入房间 -} + msgHandlerMapper map[string]MsgHandler + entered chan struct{} // 进入房间 + } +) -func NewLiveBilibili() *live.Live { - cfg := &config.Config.Bilibili +func NewLiveBilibili() *LiveBilibili { bl := &LiveBilibili{ - Url: cfg.Url, - GetRoomUrl: cfg.GetRoomUrl, - RoomId: cfg.RoomId, - UserId: cfg.UserId, - HeartbeatInterval: cfg.HeartbeatInterval * time.Second, - msgHandlerMapper: make(map[string]MsgHandler, 6), - entered: make(chan struct{}), + msgHandlerMapper: make(map[string]MsgHandler, 6), + entered: make(chan struct{}), } l := live.NewLive( @@ -53,36 +49,93 @@ func NewLiveBilibili() *live.Live { ws.WithPacker(NewPackBilibili()), ), ) + l.PreConnect(bl.preConnect) + l.Init(bl.Init) - l.PreConnect(bl.PreConnect) l.Handler(bl) bl.Live = l - return l + return bl } -func (l *LiveBilibili) AddMessageHandler(h ...MsgHandler) { +func (l *LiveBilibili) registerMessageHandler(h ...MsgHandler) { for _, handler := range h { l.msgHandlerMapper[handler.CMD()] = handler } } -func (l *LiveBilibili) PreConnect() (url string, err error) { - url = l.Url +func (l *LiveBilibili) preConnect() (url string, err error) { + cfg := config.Config.Bilibili + if err = l.initRoomInfo(); err != nil { + return "", err + } + switch cfg.Type { + case config.BilibiliTypeOfficial: + err = l.initWebsocketInfo() + if err != nil { + logger.SLog.Errorf("获取wss信息失败, err:%+v", err) + return "", err + } + if len(l.webSocketInfo.Ip) == 0 || len(l.webSocketInfo.WssPort) == 0 { + return "", errors.New("获取到的wss信息中地址或端口为空") + } + logger.SLog.Info("正在寻找连接最快的API地址...") + // 获取最快的地址 + var minDuration = 1 * time.Hour + var minIdx = 0 + for i, ip := range l.webSocketInfo.Host { + pinger, err := ping.NewPinger(ip) + if err != nil { + continue + } + pinger.SetPrivileged(true) + pinger.Count = 3 + pinger.Interval = 100 * time.Nanosecond // 100ns /time + pinger.Timeout = 200 * time.Millisecond // 200ms + err = pinger.Run() + if err != nil { + continue + } + stat := pinger.Statistics() + if stat.AvgRtt < minDuration { + minDuration = stat.AvgRtt + minIdx = i + } + } + url = fmt.Sprintf("wss://%s:%d/sub", l.webSocketInfo.Host[minIdx], l.webSocketInfo.WssPort[0]) + + logger.SLog.Info("找到当前最快的弹幕服务器地址 ", url, " 延迟:", minDuration) + l.registerMessageHandler( + msg_handler.NewDanmakuOfficialHandler(l.roomInfo.RoomId), + msg_handler.NewGuardBuyOfficialHandler(l.roomInfo.RoomId), + msg_handler.NewGiftOfficialHandler(l.roomInfo.RoomId), + ) + case config.BilibiliTypeCustom: + url = cfg.Custom.Url + l.registerMessageHandler( + msg_handler.NewDanmakuHandler(l.roomInfo.RoomId), + msg_handler.NewSendGiftHandler(l.roomInfo.RoomId), + msg_handler.NewGuardBuyHandler(l.roomInfo.RoomId), + //&msg_handler.InterActWordHandler{}, + ) + } + return +} + +func (l *LiveBilibili) initRoomInfo() error { // 避免重复请求接口 - if l.RoomInfo != nil && - (l.RoomId == l.RoomInfo.RoomId || l.RoomId == l.RoomInfo.ShortId) { - return + if l.roomInfo != nil { + return nil } + cfg := config.Config.Bilibili - fetchUrl := fmt.Sprintf(`%s%d`, l.GetRoomUrl, l.RoomId) - response, err := http.Get(fetchUrl) + response, err := http.Get(fmt.Sprintf(`%s%d`, cfg.GetRoomUrl, cfg.RoomId)) if err != nil { - return "", err + return err } res, err := ioutil.ReadAll(response.Body) if err != nil { - return "", err + return err } var getRoomInfoResp struct { Code int `json:"code"` @@ -92,32 +145,86 @@ func (l *LiveBilibili) PreConnect() (url string, err error) { } err = json.Unmarshal(res, &getRoomInfoResp) if err != nil { - return "", err + return err } - l.RoomInfo = getRoomInfoResp.Data - logger.SLog.Infof("获取房间数据: %+v\n", l.RoomInfo) - //log.With("获取房间数据", l.RoomInfo) + l.roomInfo = getRoomInfoResp.Data + logger.SLog.Infof("获取房间数据: %+v\n", l.roomInfo) - // 获取房间信息后再添加消息处理器 是因为需要房间号 - l.AddMessageHandler( - msg_handler.NewDanmakuHandler(l.RoomInfo.RoomId), - msg_handler.NewSendGiftHandler(l.RoomInfo.RoomId), - msg_handler.NewGuardBuyHandler(l.RoomInfo.RoomId), - //&msg_handler.InterActWordHandler{}, - ) - return + return nil +} + +func (l *LiveBilibili) initWebsocketInfo() error { + cfg := config.Config.Bilibili + + req := &WebsocketInfoReq{ + RoomId: l.roomInfo.RoomId, + } + content, _ := json.Marshal(req) + header := &CommonHeader{ + ContentType: JsonType, + ContentAcceptType: JsonType, + Timestamp: strconv.FormatInt(time.Now().Unix(), 10), + SignatureMethod: HmacSha256, + SignatureVersion: BiliVersion, + Authorization: "", + Nonce: strconv.FormatInt(time.Now().UnixNano(), 10), + AccessKeyId: cfg.Official.AkId, + ContentMD5: Md5(string(content)), + } + header.Authorization = CreateSignature(header, cfg.Official.AkSecret) + + request, err := http.NewRequest("POST", fmt.Sprintf("%s/v1/common/websocketInfo", cfg.Official.Api), strings.NewReader(string(content))) + if err != nil { + return err + } + for k, v := range header.ToMap() { + request.Header.Add(k, v) + } + response, err := http.DefaultClient.Do(request) + if err != nil { + return err + } + res, err := ioutil.ReadAll(response.Body) + if err != nil { + return err + } + var baseResp BaseResp + err = json.Unmarshal(res, &baseResp) + if err != nil { + return err + } + if baseResp.Code != 0 { + return errors.New(fmt.Sprintf("调用API失败, result: %+v", baseResp)) + } + var infoData WebsocketInfoResp + err = json.Unmarshal(baseResp.Data, &infoData) + if err != nil { + return err + } + l.webSocketInfo = &infoData + logger.SLog.Debugf("获取到wss信息为: %+v", infoData) + return nil } func (l *LiveBilibili) Init(conn *ws.NWebsocket) (err error) { - if err = l.joinRoom(conn); err != nil { - logger.SLog.Error(err) - return + cfg := config.Config.Bilibili + switch cfg.Type { + case config.BilibiliTypeOfficial: + if err = l.auth(conn); err != nil { + logger.SLog.Error(err) + return + } + case config.BilibiliTypeCustom: + if err = l.joinRoom(conn); err != nil { + logger.SLog.Error(err) + return + } } - // 等待进入房间 + // 等待进入房间或登录成功 <-l.entered - go l.heartbeat(conn, l.HeartbeatInterval) + go l.heartbeat(conn, cfg.HeartbeatInterval*time.Second) return } @@ -129,7 +236,7 @@ func (l *LiveBilibili) HandlerMessage(v interface{}) { } // 处理消息 switch entry.operation { - case WsOpEnterRoomSuccess: + case WsOpEnterRoomOrAuthReply: go func() { select { case l.entered <- struct{}{}: @@ -160,12 +267,29 @@ func (l *LiveBilibili) HandlerMessage(v interface{}) { } } +func (l *LiveBilibili) auth(conn *ws.NWebsocket) error { + if l.webSocketInfo == nil { + return errors.New("websocket信息未获取成功,不能登录") + } + data := &WsEntry{ + operation: WsOpEnterRoomOrAuth, + data: []byte(l.webSocketInfo.AuthBody), + } + l.sequenceId++ + err := conn.SendBinaryMessage(data) + if err != nil { + return errors.Wrap(err, "发送AUTH消息到wss失败") + } + return nil +} + func (l *LiveBilibili) joinRoom(conn *ws.NWebsocket) error { + cfg := config.Config.Bilibili msg := JoinRoomReq{ Platform: "web", ProtoVer: 1, - RoomId: l.RoomInfo.RoomId, - Uid: l.UserId, + RoomId: l.roomInfo.RoomId, + Uid: cfg.UserId, Type: 2, } body, err := json.Marshal(msg) @@ -175,7 +299,7 @@ func (l *LiveBilibili) joinRoom(conn *ws.NWebsocket) error { data := &WsEntry{ protoVer: 0, - operation: WsOpEnterRoom, + operation: WsOpEnterRoomOrAuth, sequenceId: WsHeaderDefaultSequence, data: body, } @@ -191,9 +315,10 @@ func (l *LiveBilibili) heartbeat(conn *ws.NWebsocket, t time.Duration) { data := &WsEntry{ protoVer: 0, operation: WsOpHeartbeat, - sequenceId: WsHeaderDefaultSequence, + sequenceId: l.sequenceId, data: nil, } + l.sequenceId++ err := conn.SendBinaryMessage(data) if err != nil { return diff --git a/bilibili/message.go b/bilibili/message.go index d73d38c..18205f4 100644 --- a/bilibili/message.go +++ b/bilibili/message.go @@ -1,12 +1,14 @@ package bilibili +import "encoding/json" + // ws-ops const ( - WsOpHeartbeat = 2 // 心跳 - WsOpHeartbeatReply = 3 // 心跳回应 - WsOpMessage = 5 // 弹幕消息等 - WsOpEnterRoom = 7 // 请求进入房间 - WsOpEnterRoomSuccess = 8 // 进房回应 + WsOpHeartbeat = 2 // 心跳 + WsOpHeartbeatReply = 3 // 心跳回应 + WsOpMessage = 5 // 弹幕消息等 + WsOpEnterRoomOrAuth = 7 // 请求进入房间 + WsOpEnterRoomOrAuthReply = 8 // 进房回应 ) // version protocol @@ -54,6 +56,28 @@ type JoinRoomReq struct { Key string `json:"key"` } +// BaseResp 基础API返回 +type BaseResp struct { + Code int64 `json:"code"` + Message string `json:"message"` + RequestId string `json:"request_id"` + Data json.RawMessage `json:"data"` +} + +type WebsocketInfoReq struct { + RoomId int64 `json:"room_id"` +} + +// WebsocketInfoResp 官方websocket信息回复 +type WebsocketInfoResp struct { + Ip []string `json:"ip"` + AuthBody string `json:"auth_body"` + Host []string `json:"host"` + TcpPort []int64 `json:"tcp_port"` + WsPort []int64 `json:"ws_port"` + WssPort []int64 `json:"wss_port"` +} + type CMD struct { CMD string `json:"cmd"` } diff --git a/bilibili/msg_handler/common.go b/bilibili/msg_handler/common.go index 1f3e8c7..6e70b25 100644 --- a/bilibili/msg_handler/common.go +++ b/bilibili/msg_handler/common.go @@ -18,3 +18,18 @@ type FansMedal struct { Special string `json:"special"` // ??? TargetId int `json:"target_id"` // 佩戴勋章所指的主播ID } + +const ( + CoinTypeGold = "gold" + CoinTypeSilver = "silver" +) + +func IsPaidGift(coinType string) bool { + if coinType == CoinTypeGold { + return true + } + if coinType == CoinTypeSilver { + return false + } + return false +} diff --git a/bilibili/msg_handler/danmaku.go b/bilibili/msg_handler/danmaku.go index 35976a5..8d6f9b9 100644 --- a/bilibili/msg_handler/danmaku.go +++ b/bilibili/msg_handler/danmaku.go @@ -118,8 +118,8 @@ func (d *DanmakuHandler) HandlerMessage(data []byte) { LiveRoomId: d.liveRoomId, Uid: dm.UID, Uname: dm.Uname, - Content: dm.Content, - SendTime: dm.SendTime, + Msg: dm.Content, + Timestamp: dm.SendTime, } _ = d.producer.SendMessageAsync(dmMsg, strconv.FormatInt(dm.UID, 10)) diff --git a/bilibili/msg_handler/danmaku_official.go b/bilibili/msg_handler/danmaku_official.go new file mode 100644 index 0000000..d1414e4 --- /dev/null +++ b/bilibili/msg_handler/danmaku_official.go @@ -0,0 +1,77 @@ +package msg_handler + +import ( + "encoding/json" + "git.noahlan.cn/northlan/ntools-go/kafka" + "git.noahlan.cn/northlan/ntools-go/logger" + "live-gateway/config" + pbMq "live-gateway/pb" + kfk "live-gateway/pkg/kafka" + "strconv" +) + +//var _ bilibili.MsgHandler = (*DanmakuHandler)(nil) + +// DanmakuOfficial 弹幕结构 官方 +type DanmakuOfficial struct { + Uname string `json:"uname"` // 用户昵称 + UID int64 `json:"uid"` // 用户ID + UFace string `json:"uface"` // 用户头像 + Timestamp int64 `json:"timestamp"` // 弹幕发送时间秒级时间戳 + RoomId int64 `json:"room_id"` // 用户模式 + Msg string `json:"msg"` // 弹幕内容 + MsgId string `json:"msg_id"` // 消息唯一ID + GuardLevel int64 `json:"guard_level"` // 对应房间大航海等级 + FansMedalWearingStatus bool `json:"fans_medal_wearing_status"` // 当前佩戴粉丝勋章佩戴状态 + FansMedalName string `json:"fans_medal_name"` // 粉丝勋章名 + FansMedalLevel int64 `json:"fans_medal_level"` // 粉丝勋章等级 +} + +type DanmakuOfficialHandler struct { + producer *kafka.Producer + liveRoomId int64 +} + +func NewDanmakuOfficialHandler(liveRoomId int64) *DanmakuOfficialHandler { + cfg := config.Config.Kafka.Danmaku + return &DanmakuOfficialHandler{ + producer: kafka.NewKafkaProducer(kfk.DefaultProducerConfig, cfg.Addr, cfg.Topic), + liveRoomId: liveRoomId, + } +} + +func (d *DanmakuOfficialHandler) CMD() string { + return "LIVE_OPEN_PLATFORM_DM" +} + +func (d *DanmakuOfficialHandler) HandlerMessage(data []byte) { + var baseMsg struct { + CMD string `json:"cmd"` + Data *DanmakuOfficial `json:"data"` + } + if err := json.Unmarshal(data, &baseMsg); err != nil { + return + } + + dm := baseMsg.Data + + logger.SLog.Debugf("%s 说: %s", dm.Uname, dm.Msg) + logger.SLog.Debugf("%+v", dm) + + dmMsg := &pbMq.MqDanmaku{ + Platform: pbMq.Platform_name[int32(pbMq.Platform_bilibili)], + LiveRoomId: d.liveRoomId, + Uid: dm.UID, + Uname: dm.Uname, + Avatar: dm.UFace, + Msg: dm.Msg, + MsgId: dm.MsgId, + Timestamp: dm.Timestamp, + NobilityLevel: dm.GuardLevel, + FansMedalWearingStatus: dm.FansMedalWearingStatus, + FansMedalName: dm.FansMedalName, + FansMedalLevel: dm.FansMedalLevel, + } + + _ = d.producer.SendMessageAsync(dmMsg, strconv.FormatInt(dm.UID, 10)) +} diff --git a/bilibili/msg_handler/gift_official.go b/bilibili/msg_handler/gift_official.go new file mode 100644 index 0000000..cc53a29 --- /dev/null +++ b/bilibili/msg_handler/gift_official.go @@ -0,0 +1,98 @@ +package msg_handler + +import ( + "encoding/json" + "git.noahlan.cn/northlan/ntools-go/kafka" + "live-gateway/config" + "live-gateway/pb" + kfk "live-gateway/pkg/kafka" + "strconv" +) + +// GiftOfficial 礼物结构 官方 +type GiftOfficial struct { + RoomId int64 `json:"room_id"` // 房间号 + Uid int64 `json:"uid"` // 送礼用户UID + Uname string `json:"uname"` // 送礼用户昵称 + Uface string `json:"uface"` // 送礼用户头像 + GiftId int64 `json:"gift_id"` // 道具id(盲盒:爆出道具id) + GiftName string `json:"gift_name"` // 道具名(盲盒:爆出道具名) + GiftNum int64 `json:"gift_num"` // 赠送道具数量 + Price int64 `json:"price"` // 支付金额(1000 = 1元 = 10电池),盲盒:爆出道具的价值 + Paid bool `json:"paid"` // 是否是付费道具 + FansMedalLevel int64 `json:"fans_medal_level"` // 实际送礼人的勋章信息 + FansMedalName string `json:"fans_medal_name"` // 粉丝勋章名 + FansMedalWearingStatus bool `json:"fans_medal_wearing_status"` // 当前佩戴的粉丝勋章佩戴状态 + GuardLevel int64 `json:"guard_level"` // 大航海等级 + Timestamp int64 `json:"timestamp"` // 收礼时间秒级时间戳 + AnchorInfo anchorInfo `json:"anchor_info"` // 主播信息 + MsgId string `json:"msg_id"` // 消息唯一id +} + +type anchorInfo struct { + Uid int64 `json:"uid"` // 收礼主播uid + Uname string `json:"uname"` // 收礼主播昵称 + Uface string `json:"uface"` // 收礼主播头像 +} + +type GiftOfficialHandler struct { + producer *kafka.Producer + liveRoomId int64 +} + +func NewGiftOfficialHandler(liveRoomId int64) *GiftOfficialHandler { + cfg := config.Config.Kafka.Gift + return &GiftOfficialHandler{ + producer: kafka.NewKafkaProducer(kfk.DefaultProducerConfig, cfg.Addr, cfg.Topic), + liveRoomId: liveRoomId, + } +} + +func (h *GiftOfficialHandler) CMD() string { + return "LIVE_OPEN_PLATFORM_SEND_GIFT" +} + +func (h *GiftOfficialHandler) HandlerMessage(data []byte) { + var baseMsg struct { + CMD string `json:"cmd"` + Data *GiftOfficial `json:"data"` + } + if err := json.Unmarshal(data, &baseMsg); err != nil { + return + } + + //logger.SLog.Infof("%s %s礼物 %s x%d", baseMsg.Data.Uname, baseMsg.Data.Action, baseMsg.Data.GiftName, baseMsg.Data.Num) + + gift := baseMsg.Data + + dmMsg := &pbMq.MqGift{ + Platform: pbMq.Platform_name[int32(pbMq.Platform_bilibili)], + LiveRoomId: h.liveRoomId, + Uid: gift.Uid, + Uname: gift.Uname, + Avatar: gift.Uface, + GiftId: gift.GiftId, + GiftName: gift.GiftName, + GiftNum: gift.GiftNum, + Price: gift.Price, + IsPaid: gift.Paid, + MsgId: gift.MsgId, + Timestamp: gift.Timestamp, + NobilityLevel: gift.GuardLevel, + FansMedalWearingStatus: gift.FansMedalWearingStatus, + FansMedalName: gift.FansMedalName, + FansMedalLevel: gift.FansMedalLevel, + } + + _ = h.producer.SendMessageAsync(dmMsg, strconv.FormatInt(dmMsg.Uid, 10)) +} + +func (h *GiftOfficialHandler) isPaid(coinType string) bool { + if coinType == CoinTypeGold { + return true + } + if coinType == CoinTypeSilver { + return false + } + return false +} diff --git a/bilibili/msg_handler/guard_buy.go b/bilibili/msg_handler/guard_buy.go index cfb2d32..238b221 100644 --- a/bilibili/msg_handler/guard_buy.go +++ b/bilibili/msg_handler/guard_buy.go @@ -13,7 +13,7 @@ import ( type GuardBuy struct { Uid int64 `json:"uid"` // 用户ID Uname string `json:"username"` // 用户名 - GuardLevel int32 `json:"guard_level"` // 等级(3舰长 1总督) + GuardLevel int64 `json:"guard_level"` // 等级(3舰长 1总督) Num int32 `json:"num"` // 数量 Price int64 `json:"price"` // 价格 金瓜子 GiftId int64 `json:"gift_id"` // 礼物ID @@ -50,18 +50,15 @@ func (h *GuardBuyHandler) HandlerMessage(data []byte) { logger.SLog.Infof("%s 购买 %s x %d", baseMsg.Data.Uname, baseMsg.Data.GiftName, baseMsg.Data.Num) - dmMsg := &pbMq.MqGuardBuy{ - Platform: pbMq.Platform_name[int32(pbMq.Platform_bilibili)], - LiveRoomId: h.liveRoomId, - Uid: baseMsg.Data.Uid, - Uname: baseMsg.Data.Uname, - GuardLevel: baseMsg.Data.GuardLevel, - Num: baseMsg.Data.Num, - Price: baseMsg.Data.Price, - GiftId: baseMsg.Data.GiftId, - GiftName: baseMsg.Data.GiftName, - StartTime: baseMsg.Data.StartTime, - EndTime: baseMsg.Data.EndTime, + dmMsg := &pbMq.MqNobilityBuy{ + Platform: pbMq.Platform_name[int32(pbMq.Platform_bilibili)], + LiveRoomId: h.liveRoomId, + Uid: baseMsg.Data.Uid, + Uname: baseMsg.Data.Uname, + NobilityLevel: baseMsg.Data.GuardLevel, + Price: baseMsg.Data.Price, + StartTime: baseMsg.Data.StartTime, + EndTime: baseMsg.Data.EndTime, } _ = h.producer.SendMessageAsync(dmMsg, strconv.FormatInt(dmMsg.Uid, 10)) diff --git a/bilibili/msg_handler/guard_buy_official.go b/bilibili/msg_handler/guard_buy_official.go new file mode 100644 index 0000000..e2b68c1 --- /dev/null +++ b/bilibili/msg_handler/guard_buy_official.go @@ -0,0 +1,98 @@ +package msg_handler + +import ( + "encoding/json" + "git.noahlan.cn/northlan/ntools-go/kafka" + "git.noahlan.cn/northlan/ntools-go/logger" + "github.com/jinzhu/now" + "live-gateway/config" + "live-gateway/pb" + kfk "live-gateway/pkg/kafka" + "live-gateway/pkg/timex" + "strconv" +) + +type GuardBuyOfficial struct { + UserInfo userInfo `json:"user_info"` // 用户信息 + GuardLevel int64 `json:"guard_level"` // 大航海等级 1总督 2提督 3舰长 + GuardNum int64 `json:"guard_num"` // 大航海数量 + GuardUnit string `json:"guard_unit"` // 大航海单位 (个月) + FansMedalLevel int64 `json:"fans_medal_level"` // 粉丝勋章等级 + FansMedalName string `json:"fans_medal_name"` // 粉丝勋章名 + FansMedalWearingStatus bool `json:"fans_medal_wearing_status"` // 佩戴的粉丝勋章佩戴状态 + RoomId int64 `json:"room_id"` // 房间号 + MsgId string `json:"msg_id"` // 消息唯一id + Timestamp int64 `json:"timestamp"` // 上舰时间秒级时间戳 +} + +type userInfo struct { + Uid int64 `json:"uid"` // 用户uid + Uname string `json:"uname"` // 用户昵称 + Uface string `json:"uface"` // 用户头像 +} + +type GuardBuyOfficialHandler struct { + producer *kafka.Producer + liveRoomId int64 +} + +func NewGuardBuyOfficialHandler(liveRoomId int64) *GuardBuyOfficialHandler { + cfg := config.Config.Kafka.GuardBuy + return &GuardBuyOfficialHandler{ + producer: kafka.NewKafkaProducer(kfk.DefaultProducerConfig, cfg.Addr, cfg.Topic), + liveRoomId: liveRoomId, + } +} + +func (h *GuardBuyOfficialHandler) CMD() string { + return "GUARD_BUY" +} + +func (h *GuardBuyOfficialHandler) HandlerMessage(data []byte) { + var baseMsg struct { + CMD string `json:"cmd"` + Data *GuardBuyOfficial `json:"data"` + } + if err := json.Unmarshal(data, &baseMsg); err != nil { + return + } + + d := baseMsg.Data + + logger.SLog.Infof("%s 购买 %d %d%s", d.UserInfo.Uname, d.GuardLevel, d.GuardNum, d.GuardUnit) + + dmMsg := &pbMq.MqNobilityBuy{ + Platform: pbMq.Platform_name[int32(pbMq.Platform_bilibili)], + LiveRoomId: h.liveRoomId, + Uid: d.UserInfo.Uid, + Uname: d.UserInfo.Uname, + Avatar: d.UserInfo.Uface, + MsgId: d.MsgId, + NobilityLevel: d.GuardLevel, + Price: 0, // 自己算 + StartTime: d.Timestamp, + EndTime: 0, // 自己算 + FansMedalWearingStatus: d.FansMedalWearingStatus, + FansMedalName: d.FansMedalName, + FansMedalLevel: d.FansMedalLevel, + } + switch d.GuardLevel { + case 1: + dmMsg.Price = 19998 * 1000 // 金瓜子 + case 2: + dmMsg.Price = 1998 * 1000 + case 3: + dmMsg.Price = 138 * 1000 // 应该没有人会不用连续包月然后取消吧? + } + // 计算时间 + switch d.GuardUnit { + case "月": + dmMsg.EndTime = now.With(timex.TimestampToTime(d.Timestamp)). + AddDate(0, 1, 0).Unix() + case "年": + dmMsg.EndTime = now.With(timex.TimestampToTime(d.Timestamp)). + AddDate(1, 0, 0).Unix() + } + + _ = h.producer.SendMessageAsync(dmMsg, strconv.FormatInt(dmMsg.Uid, 10)) +} diff --git a/bilibili/msg_handler/guard_buy_official_test.go b/bilibili/msg_handler/guard_buy_official_test.go new file mode 100644 index 0000000..7d7a12c --- /dev/null +++ b/bilibili/msg_handler/guard_buy_official_test.go @@ -0,0 +1,14 @@ +package msg_handler + +import ( + "fmt" + "github.com/jinzhu/now" + "live-gateway/pkg/timex" + "testing" +) + +func TestTime(t *testing.T) { + fmt.Println(timex.TimestampToTime(1653555128)) + last := now.BeginningOfDay().AddDate(0, 1, 0) + fmt.Println(last, last.Unix(), last.UnixMilli(), last.UnixMicro(), last.UnixNano()) +} diff --git a/bilibili/msg_handler/send_gift.go b/bilibili/msg_handler/send_gift.go index 504a5a5..ed21c7c 100644 --- a/bilibili/msg_handler/send_gift.go +++ b/bilibili/msg_handler/send_gift.go @@ -42,7 +42,7 @@ type SendGift struct { NameColor string `json:"name_color"` // 名 颜色 Num int64 `json:"num"` // 数量 OriginalGiftName string `json:"original_gift_name"` // 原始礼物名称??? - Price int `json:"price"` // 价格? 但不是电池 + Price int64 `json:"price"` // 价格? 但不是电池 RCost int `json:"rcost"` // ??? Remain int `json:"remain"` // 用户道具包裹剩余数量 Rnd string `json:"rnd"` // 随机数? @@ -53,18 +53,13 @@ type SendGift struct { SuperGiftNum int `json:"super_gift_num"` // ??? SvgaBlock int `json:"svga_block"` // ??? TagImage string `json:"tag_image"` // ??? - Timestamp int `json:"timestamp"` // 赠送时间 + Timestamp int64 `json:"timestamp"` // 赠送时间 TopList interface{} `json:"top_list"` // ??? TotalCoin int `json:"total_coin"` // 总值 瓜子数 Uid int `json:"uid"` // 用户ID Uname string `json:"uname"` // 用户名 } -const ( - CoinTypeGold = "gold" - CoinTypeSilver = "silver" -) - type SendGiftHandler struct { producer *kafka.Producer liveRoomId int64 @@ -94,26 +89,23 @@ func (h *SendGiftHandler) HandlerMessage(data []byte) { //logger.SLog.Infof("%s %s礼物 %s x%d", baseMsg.Data.Uname, baseMsg.Data.Action, baseMsg.Data.GiftName, baseMsg.Data.Num) dmMsg := &pbMq.MqGift{ - Platform: pbMq.Platform_name[int32(pbMq.Platform_bilibili)], - LiveRoomId: h.liveRoomId, - Uid: int64(baseMsg.Data.Uid), - Uname: baseMsg.Data.Uname, - GiftId: baseMsg.Data.GiftId, - Num: baseMsg.Data.Num, - GiftName: baseMsg.Data.GiftName, - Price: int64(baseMsg.Data.Price), - IsPaid: h.isPaid(baseMsg.Data.CoinType), + Platform: pbMq.Platform_name[int32(pbMq.Platform_bilibili)], + LiveRoomId: h.liveRoomId, + Uid: int64(baseMsg.Data.Uid), + Uname: baseMsg.Data.Uname, + Avatar: "", + GiftId: baseMsg.Data.GiftId, + GiftName: baseMsg.Data.GiftName, + GiftNum: baseMsg.Data.Num, + Price: baseMsg.Data.Price, + IsPaid: IsPaidGift(baseMsg.Data.CoinType), + MsgId: "", + Timestamp: baseMsg.Data.Timestamp, + NobilityLevel: 0, + FansMedalWearingStatus: false, + FansMedalName: "", + FansMedalLevel: 0, } _ = h.producer.SendMessageAsync(dmMsg, strconv.FormatInt(dmMsg.Uid, 10)) } - -func (h *SendGiftHandler) isPaid(coinType string) bool { - if coinType == CoinTypeGold { - return true - } - if coinType == CoinTypeSilver { - return false - } - return false -} diff --git a/bilibili/sign.go b/bilibili/sign.go new file mode 100644 index 0000000..d50989f --- /dev/null +++ b/bilibili/sign.go @@ -0,0 +1,97 @@ +package bilibili + +import ( + "crypto/hmac" + "crypto/md5" + "crypto/sha256" + "encoding/hex" + "fmt" + "sort" + "strings" +) + +const AcceptHeader = "Accept" +const ContentTypeHeader = "Content-Type" +const AuthorizationHeader = "Authorization" +const JsonType = "application/json" +const BiliVersion = "1.0" +const HmacSha256 = "HMAC-SHA256" +const BiliTimestampHeader = "x-bili-timestamp" +const BiliSignatureMethodHeader = "x-bili-signature-method" +const BiliSignatureNonceHeader = "x-bili-signature-nonce" +const BiliAccessKeyIdHeader = "x-bili-accesskeyid" +const BiliSignVersionHeader = "x-bili-signature-version" +const BiliContentMD5Header = "x-bili-content-md5" + +//CreateSignature 生成Authorization加密串 +func CreateSignature(header *CommonHeader, accessKeySecret string) string { + sStr := header.ToSortedString() + return HmacSHA256(accessKeySecret, sStr) +} + +func Md5(str string) (md5str string) { + data := []byte(str) + has := md5.Sum(data) + md5str = fmt.Sprintf("%x", has) + return md5str +} + +func HmacSHA256(key string, data string) string { + mac := hmac.New(sha256.New, []byte(key)) + mac.Write([]byte(data)) + return hex.EncodeToString(mac.Sum(nil)) +} + +type CommonHeader struct { + ContentType string + ContentAcceptType string + Timestamp string + SignatureMethod string + SignatureVersion string + Authorization string + Nonce string + AccessKeyId string + ContentMD5 string +} + +// ToMap 所有字段转map +func (h *CommonHeader) ToMap() map[string]string { + return map[string]string{ + BiliTimestampHeader: h.Timestamp, + BiliSignatureMethodHeader: h.SignatureMethod, + BiliSignatureNonceHeader: h.Nonce, + BiliAccessKeyIdHeader: h.AccessKeyId, + BiliSignVersionHeader: h.SignatureVersion, + BiliContentMD5Header: h.ContentMD5, + AuthorizationHeader: h.Authorization, + ContentTypeHeader: h.ContentType, + AcceptHeader: h.ContentAcceptType, + } +} + +// ToSortMap 参与加密的字段转map +func (h *CommonHeader) ToSortMap() map[string]string { + return map[string]string{ + BiliTimestampHeader: h.Timestamp, + BiliSignatureMethodHeader: h.SignatureMethod, + BiliSignatureNonceHeader: h.Nonce, + BiliAccessKeyIdHeader: h.AccessKeyId, + BiliSignVersionHeader: h.SignatureVersion, + BiliContentMD5Header: h.ContentMD5, + } +} + +//ToSortedString 生成需要加密的文本 +func (h *CommonHeader) ToSortedString() (sign string) { + hMap := h.ToSortMap() + var hSil []string + for k := range hMap { + hSil = append(hSil, k) + } + sort.Strings(hSil) + for _, v := range hSil { + sign += v + ":" + hMap[v] + "\n" + } + sign = strings.TrimRight(sign, "\n") + return +} diff --git a/config-dev.yml b/config-dev.yml index fd09f1d..1326e22 100644 --- a/config-dev.yml +++ b/config-dev.yml @@ -1,10 +1,16 @@ Bilibili: Enabled: true - Url: wss://broadcastlv.chat.bilibili.com:2245/sub + Type: official + Official: + Api: https://live-open.biliapi.com + AkId: 1rVL1YRSoii28LJ1O7KIQqqQ + AkSecret: 5USwZt2bygTIE8a2cXahZrzsdKtbxd + Custom: + Url: wss://broadcastlv.chat.bilibili.com:2245/sub GetRoomUrl: https://api.live.bilibili.com/room/v1/Room/room_init?id= HeartbeatInterval: 30 UserId: 111222 - RoomId: 8722013 + RoomId: 6925399 Log: Console: Level: debug diff --git a/config/config.go b/config/config.go index 37e1309..d4d4aca 100644 --- a/config/config.go +++ b/config/config.go @@ -10,6 +10,13 @@ import ( var Config config +type BilibiliType string + +const ( + BilibiliTypeOfficial BilibiliType = "official" + BilibiliTypeCustom BilibiliType = "custom" +) + type ( Kafka struct { Addr []string @@ -17,8 +24,16 @@ type ( } config struct { Bilibili struct { - Enabled bool // 是否启用 - Url string // 弹幕服务器url + Enabled bool // 是否启用 + Type BilibiliType // 类型 + Official struct { + Api string // API 地址 + AkId string // accessKeyId + AkSecret string // accessSecret + } // 官方API + Custom struct { + Url string // 弹幕服务器url + } GetRoomUrl string // 获取房间信息url RoomId int64 // 待连接roomId UserId int64 // 用于连接的userId,0则随机生成 diff --git a/go.mod b/go.mod index 4d54ffa..24f0314 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,9 @@ require ( github.com/eapache/go-resiliency v1.2.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect github.com/eapache/queue v1.1.0 // indirect + github.com/go-ping/ping v1.1.0 // indirect github.com/golang/snappy v0.0.4 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/gookit/goutil v0.5.0 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/imdario/mergo v0.3.12 // indirect @@ -28,6 +30,7 @@ require ( github.com/jcmturner/gofork v1.0.0 // indirect github.com/jcmturner/gokrb5/v8 v8.4.2 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect + github.com/jinzhu/now v1.1.5 // indirect github.com/klauspost/compress v1.15.1 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -39,7 +42,8 @@ require ( go.uber.org/multierr v1.8.0 // indirect go.uber.org/zap v1.21.0 // indirect golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect - golang.org/x/net v0.0.0-20220421235706-1d1ef9303861 // indirect - golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect + golang.org/x/net v0.0.0-20220531201128-c960675eff93 // indirect + golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect + golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 9d9c1c1..d610f40 100644 --- a/go.sum +++ b/go.sum @@ -32,6 +32,8 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnXyBns= github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw= +github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -44,6 +46,9 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gookit/color v1.5.0 h1:1Opow3+BWDwqor78DcJkJCIwnkviFi+rrOANki9BUFw= github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= github.com/gookit/config/v2 v2.1.0 h1:RNiT4tsAkDBP5QPhxGk/vEcQO4ET1xdRBd9BStL4G1E= @@ -76,6 +81,8 @@ github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJz github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= @@ -168,19 +175,25 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220421235706-1d1ef9303861 h1:yssD99+7tqHWO5Gwh81phT+67hg+KttniBr6UnEXOY8= golang.org/x/net v0.0.0-20220421235706-1d1ef9303861/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220531201128-c960675eff93 h1:MYimHLfoXEpOhqd/zgoA/uoXzHB86AEky4LAx5ij9xA= +golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -189,6 +202,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/main.go b/main.go index 5fec9bd..a8e86e1 100644 --- a/main.go +++ b/main.go @@ -28,7 +28,7 @@ func main() { bLive := bilibili.NewLiveBilibili() go func() { if err := bLive.Serve(); err != nil { - logger.SLog.Error("err", err) + logger.SLog.Error("err: ", err) wg.Done() } }() diff --git a/pb/mq.pb.go b/pb/mq.pb.go index 9cc6dc0..62dab5d 100644 --- a/pb/mq.pb.go +++ b/pb/mq.pb.go @@ -72,26 +72,28 @@ func (Platform) EnumDescriptor() ([]byte, []int) { return file_mq_proto_rawDescGZIP(), []int{0} } -type MqGuardBuy struct { +type MqNobilityBuy struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Platform string `protobuf:"bytes,1,opt,name=platform,proto3" json:"platform,omitempty"` - LiveRoomId int64 `protobuf:"varint,2,opt,name=liveRoomId,proto3" json:"liveRoomId,omitempty"` - Uid int64 `protobuf:"varint,3,opt,name=uid,proto3" json:"uid,omitempty"` - Uname string `protobuf:"bytes,4,opt,name=uname,proto3" json:"uname,omitempty"` - GuardLevel int32 `protobuf:"varint,5,opt,name=guardLevel,proto3" json:"guardLevel,omitempty"` - Num int32 `protobuf:"varint,6,opt,name=num,proto3" json:"num,omitempty"` - Price int64 `protobuf:"varint,7,opt,name=price,proto3" json:"price,omitempty"` - GiftId int64 `protobuf:"varint,8,opt,name=giftId,proto3" json:"giftId,omitempty"` - GiftName string `protobuf:"bytes,9,opt,name=giftName,proto3" json:"giftName,omitempty"` - StartTime int64 `protobuf:"varint,10,opt,name=startTime,proto3" json:"startTime,omitempty"` - EndTime int64 `protobuf:"varint,11,opt,name=endTime,proto3" json:"endTime,omitempty"` -} - -func (x *MqGuardBuy) Reset() { - *x = MqGuardBuy{} + Platform string `protobuf:"bytes,1,opt,name=platform,proto3" json:"platform,omitempty"` // 平台 + LiveRoomId int64 `protobuf:"varint,2,opt,name=liveRoomId,proto3" json:"liveRoomId,omitempty"` // 直播间ID + Uid int64 `protobuf:"varint,3,opt,name=uid,proto3" json:"uid,omitempty"` // 用户ID + Uname string `protobuf:"bytes,4,opt,name=uname,proto3" json:"uname,omitempty"` // 用户名 + Avatar string `protobuf:"bytes,5,opt,name=avatar,proto3" json:"avatar,omitempty"` // 头像 + MsgId string `protobuf:"bytes,6,opt,name=msgId,proto3" json:"msgId,omitempty"` // 消息唯一ID + NobilityLevel int64 `protobuf:"varint,7,opt,name=nobilityLevel,proto3" json:"nobilityLevel,omitempty"` // 贵族等级 + Price int64 `protobuf:"varint,8,opt,name=price,proto3" json:"price,omitempty"` // 平台price + StartTime int64 `protobuf:"varint,9,opt,name=startTime,proto3" json:"startTime,omitempty"` // 开始时间 + EndTime int64 `protobuf:"varint,10,opt,name=endTime,proto3" json:"endTime,omitempty"` // 过期时间 + FansMedalWearingStatus bool `protobuf:"varint,11,opt,name=fansMedalWearingStatus,proto3" json:"fansMedalWearingStatus,omitempty"` // 牌子佩戴状态 + FansMedalName string `protobuf:"bytes,12,opt,name=fansMedalName,proto3" json:"fansMedalName,omitempty"` // 粉丝牌子名 + FansMedalLevel int64 `protobuf:"varint,13,opt,name=fansMedalLevel,proto3" json:"fansMedalLevel,omitempty"` // 粉丝牌子等级 +} + +func (x *MqNobilityBuy) Reset() { + *x = MqNobilityBuy{} if protoimpl.UnsafeEnabled { mi := &file_mq_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -99,13 +101,13 @@ func (x *MqGuardBuy) Reset() { } } -func (x *MqGuardBuy) String() string { +func (x *MqNobilityBuy) String() string { return protoimpl.X.MessageStringOf(x) } -func (*MqGuardBuy) ProtoMessage() {} +func (*MqNobilityBuy) ProtoMessage() {} -func (x *MqGuardBuy) ProtoReflect() protoreflect.Message { +func (x *MqNobilityBuy) ProtoReflect() protoreflect.Message { mi := &file_mq_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -117,84 +119,98 @@ func (x *MqGuardBuy) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use MqGuardBuy.ProtoReflect.Descriptor instead. -func (*MqGuardBuy) Descriptor() ([]byte, []int) { +// Deprecated: Use MqNobilityBuy.ProtoReflect.Descriptor instead. +func (*MqNobilityBuy) Descriptor() ([]byte, []int) { return file_mq_proto_rawDescGZIP(), []int{0} } -func (x *MqGuardBuy) GetPlatform() string { +func (x *MqNobilityBuy) GetPlatform() string { if x != nil { return x.Platform } return "" } -func (x *MqGuardBuy) GetLiveRoomId() int64 { +func (x *MqNobilityBuy) GetLiveRoomId() int64 { if x != nil { return x.LiveRoomId } return 0 } -func (x *MqGuardBuy) GetUid() int64 { +func (x *MqNobilityBuy) GetUid() int64 { if x != nil { return x.Uid } return 0 } -func (x *MqGuardBuy) GetUname() string { +func (x *MqNobilityBuy) GetUname() string { if x != nil { return x.Uname } return "" } -func (x *MqGuardBuy) GetGuardLevel() int32 { +func (x *MqNobilityBuy) GetAvatar() string { if x != nil { - return x.GuardLevel + return x.Avatar } - return 0 + return "" +} + +func (x *MqNobilityBuy) GetMsgId() string { + if x != nil { + return x.MsgId + } + return "" } -func (x *MqGuardBuy) GetNum() int32 { +func (x *MqNobilityBuy) GetNobilityLevel() int64 { if x != nil { - return x.Num + return x.NobilityLevel } return 0 } -func (x *MqGuardBuy) GetPrice() int64 { +func (x *MqNobilityBuy) GetPrice() int64 { if x != nil { return x.Price } return 0 } -func (x *MqGuardBuy) GetGiftId() int64 { +func (x *MqNobilityBuy) GetStartTime() int64 { if x != nil { - return x.GiftId + return x.StartTime } return 0 } -func (x *MqGuardBuy) GetGiftName() string { +func (x *MqNobilityBuy) GetEndTime() int64 { if x != nil { - return x.GiftName + return x.EndTime } - return "" + return 0 } -func (x *MqGuardBuy) GetStartTime() int64 { +func (x *MqNobilityBuy) GetFansMedalWearingStatus() bool { if x != nil { - return x.StartTime + return x.FansMedalWearingStatus } - return 0 + return false } -func (x *MqGuardBuy) GetEndTime() int64 { +func (x *MqNobilityBuy) GetFansMedalName() string { if x != nil { - return x.EndTime + return x.FansMedalName + } + return "" +} + +func (x *MqNobilityBuy) GetFansMedalLevel() int64 { + if x != nil { + return x.FansMedalLevel } return 0 } @@ -204,12 +220,18 @@ type MqDanmaku struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Platform string `protobuf:"bytes,1,opt,name=platform,proto3" json:"platform,omitempty"` - LiveRoomId int64 `protobuf:"varint,2,opt,name=liveRoomId,proto3" json:"liveRoomId,omitempty"` - Uid int64 `protobuf:"varint,3,opt,name=uid,proto3" json:"uid,omitempty"` - Uname string `protobuf:"bytes,4,opt,name=uname,proto3" json:"uname,omitempty"` - Content string `protobuf:"bytes,5,opt,name=content,proto3" json:"content,omitempty"` - SendTime int64 `protobuf:"varint,6,opt,name=sendTime,proto3" json:"sendTime,omitempty"` + Platform string `protobuf:"bytes,1,opt,name=platform,proto3" json:"platform,omitempty"` // 平台 + LiveRoomId int64 `protobuf:"varint,2,opt,name=liveRoomId,proto3" json:"liveRoomId,omitempty"` // 直播间ID + Uid int64 `protobuf:"varint,3,opt,name=uid,proto3" json:"uid,omitempty"` // 用户ID + Uname string `protobuf:"bytes,4,opt,name=uname,proto3" json:"uname,omitempty"` // 用户名 + Avatar string `protobuf:"bytes,5,opt,name=avatar,proto3" json:"avatar,omitempty"` // 头像 + Msg string `protobuf:"bytes,6,opt,name=msg,proto3" json:"msg,omitempty"` // 内容 + MsgId string `protobuf:"bytes,7,opt,name=msgId,proto3" json:"msgId,omitempty"` // 消息唯一ID + Timestamp int64 `protobuf:"varint,8,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // 发送时间 + NobilityLevel int64 `protobuf:"varint,9,opt,name=nobilityLevel,proto3" json:"nobilityLevel,omitempty"` // 贵族等级 + FansMedalWearingStatus bool `protobuf:"varint,10,opt,name=fansMedalWearingStatus,proto3" json:"fansMedalWearingStatus,omitempty"` // 牌子佩戴状态 + FansMedalName string `protobuf:"bytes,11,opt,name=fansMedalName,proto3" json:"fansMedalName,omitempty"` // 粉丝牌子名 + FansMedalLevel int64 `protobuf:"varint,12,opt,name=fansMedalLevel,proto3" json:"fansMedalLevel,omitempty"` // 粉丝牌子等级 } func (x *MqDanmaku) Reset() { @@ -272,16 +294,58 @@ func (x *MqDanmaku) GetUname() string { return "" } -func (x *MqDanmaku) GetContent() string { +func (x *MqDanmaku) GetAvatar() string { if x != nil { - return x.Content + return x.Avatar } return "" } -func (x *MqDanmaku) GetSendTime() int64 { +func (x *MqDanmaku) GetMsg() string { if x != nil { - return x.SendTime + return x.Msg + } + return "" +} + +func (x *MqDanmaku) GetMsgId() string { + if x != nil { + return x.MsgId + } + return "" +} + +func (x *MqDanmaku) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *MqDanmaku) GetNobilityLevel() int64 { + if x != nil { + return x.NobilityLevel + } + return 0 +} + +func (x *MqDanmaku) GetFansMedalWearingStatus() bool { + if x != nil { + return x.FansMedalWearingStatus + } + return false +} + +func (x *MqDanmaku) GetFansMedalName() string { + if x != nil { + return x.FansMedalName + } + return "" +} + +func (x *MqDanmaku) GetFansMedalLevel() int64 { + if x != nil { + return x.FansMedalLevel } return 0 } @@ -291,15 +355,22 @@ type MqGift struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Platform string `protobuf:"bytes,1,opt,name=platform,proto3" json:"platform,omitempty"` - LiveRoomId int64 `protobuf:"varint,2,opt,name=liveRoomId,proto3" json:"liveRoomId,omitempty"` - Uid int64 `protobuf:"varint,3,opt,name=uid,proto3" json:"uid,omitempty"` - Uname string `protobuf:"bytes,4,opt,name=uname,proto3" json:"uname,omitempty"` - GiftId int64 `protobuf:"varint,5,opt,name=giftId,proto3" json:"giftId,omitempty"` - Num int64 `protobuf:"varint,6,opt,name=num,proto3" json:"num,omitempty"` - GiftName string `protobuf:"bytes,7,opt,name=giftName,proto3" json:"giftName,omitempty"` - Price int64 `protobuf:"varint,8,opt,name=price,proto3" json:"price,omitempty"` - IsPaid bool `protobuf:"varint,9,opt,name=isPaid,proto3" json:"isPaid,omitempty"` + Platform string `protobuf:"bytes,1,opt,name=platform,proto3" json:"platform,omitempty"` + LiveRoomId int64 `protobuf:"varint,2,opt,name=liveRoomId,proto3" json:"liveRoomId,omitempty"` + Uid int64 `protobuf:"varint,3,opt,name=uid,proto3" json:"uid,omitempty"` + Uname string `protobuf:"bytes,4,opt,name=uname,proto3" json:"uname,omitempty"` + Avatar string `protobuf:"bytes,5,opt,name=avatar,proto3" json:"avatar,omitempty"` // 头像 + GiftId int64 `protobuf:"varint,6,opt,name=giftId,proto3" json:"giftId,omitempty"` + GiftName string `protobuf:"bytes,7,opt,name=giftName,proto3" json:"giftName,omitempty"` + GiftNum int64 `protobuf:"varint,8,opt,name=giftNum,proto3" json:"giftNum,omitempty"` + Price int64 `protobuf:"varint,9,opt,name=price,proto3" json:"price,omitempty"` + IsPaid bool `protobuf:"varint,10,opt,name=isPaid,proto3" json:"isPaid,omitempty"` + MsgId string `protobuf:"bytes,11,opt,name=msgId,proto3" json:"msgId,omitempty"` // 消息唯一ID + Timestamp int64 `protobuf:"varint,12,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // 收礼时间 + NobilityLevel int64 `protobuf:"varint,13,opt,name=nobilityLevel,proto3" json:"nobilityLevel,omitempty"` // 贵族等级 + FansMedalWearingStatus bool `protobuf:"varint,14,opt,name=fansMedalWearingStatus,proto3" json:"fansMedalWearingStatus,omitempty"` // 牌子佩戴状态 + FansMedalName string `protobuf:"bytes,15,opt,name=fansMedalName,proto3" json:"fansMedalName,omitempty"` // 粉丝牌子名 + FansMedalLevel int64 `protobuf:"varint,16,opt,name=fansMedalLevel,proto3" json:"fansMedalLevel,omitempty"` // 粉丝牌子等级 } func (x *MqGift) Reset() { @@ -362,16 +433,16 @@ func (x *MqGift) GetUname() string { return "" } -func (x *MqGift) GetGiftId() int64 { +func (x *MqGift) GetAvatar() string { if x != nil { - return x.GiftId + return x.Avatar } - return 0 + return "" } -func (x *MqGift) GetNum() int64 { +func (x *MqGift) GetGiftId() int64 { if x != nil { - return x.Num + return x.GiftId } return 0 } @@ -383,6 +454,13 @@ func (x *MqGift) GetGiftName() string { return "" } +func (x *MqGift) GetGiftNum() int64 { + if x != nil { + return x.GiftNum + } + return 0 +} + func (x *MqGift) GetPrice() int64 { if x != nil { return x.Price @@ -397,58 +475,137 @@ func (x *MqGift) GetIsPaid() bool { return false } +func (x *MqGift) GetMsgId() string { + if x != nil { + return x.MsgId + } + return "" +} + +func (x *MqGift) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *MqGift) GetNobilityLevel() int64 { + if x != nil { + return x.NobilityLevel + } + return 0 +} + +func (x *MqGift) GetFansMedalWearingStatus() bool { + if x != nil { + return x.FansMedalWearingStatus + } + return false +} + +func (x *MqGift) GetFansMedalName() string { + if x != nil { + return x.FansMedalName + } + return "" +} + +func (x *MqGift) GetFansMedalLevel() int64 { + if x != nil { + return x.FansMedalLevel + } + return 0 +} + var File_mq_proto protoreflect.FileDescriptor var file_mq_proto_rawDesc = []byte{ - 0x0a, 0x08, 0x6d, 0x71, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0xa4, - 0x02, 0x0a, 0x0a, 0x4d, 0x71, 0x47, 0x75, 0x61, 0x72, 0x64, 0x42, 0x75, 0x79, 0x12, 0x1a, 0x0a, - 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x69, 0x76, - 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6c, - 0x69, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x75, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x75, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x67, 0x75, 0x61, 0x72, 0x64, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x67, 0x75, 0x61, 0x72, 0x64, 0x4c, 0x65, 0x76, 0x65, - 0x6c, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, - 0x6e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x67, 0x69, 0x66, - 0x74, 0x49, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x67, 0x69, 0x66, 0x74, 0x49, - 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x69, 0x66, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x67, 0x69, 0x66, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, - 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, - 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, 0x6e, - 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xa5, 0x01, 0x0a, 0x09, 0x4d, 0x71, 0x44, 0x61, 0x6e, 0x6d, - 0x61, 0x6b, 0x75, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, + 0x0a, 0x08, 0x6d, 0x71, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0x9b, + 0x03, 0x0a, 0x0d, 0x4d, 0x71, 0x4e, 0x6f, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x42, 0x75, 0x79, + 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1e, 0x0a, 0x0a, + 0x6c, 0x69, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0a, 0x6c, 0x69, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, + 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x14, + 0x0a, 0x05, 0x75, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x75, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x14, 0x0a, 0x05, + 0x6d, 0x73, 0x67, 0x49, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x73, 0x67, + 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x6f, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x4c, 0x65, + 0x76, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6e, 0x6f, 0x62, 0x69, 0x6c, + 0x69, 0x74, 0x79, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, + 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1c, + 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, + 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x16, 0x66, 0x61, 0x6e, 0x73, 0x4d, 0x65, + 0x64, 0x61, 0x6c, 0x57, 0x65, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x66, 0x61, 0x6e, 0x73, 0x4d, 0x65, 0x64, 0x61, + 0x6c, 0x57, 0x65, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x24, + 0x0a, 0x0d, 0x66, 0x61, 0x6e, 0x73, 0x4d, 0x65, 0x64, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x18, + 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x66, 0x61, 0x6e, 0x73, 0x4d, 0x65, 0x64, 0x61, 0x6c, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x66, 0x61, 0x6e, 0x73, 0x4d, 0x65, 0x64, 0x61, + 0x6c, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x66, 0x61, + 0x6e, 0x73, 0x4d, 0x65, 0x64, 0x61, 0x6c, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0xf9, 0x02, 0x0a, + 0x09, 0x4d, 0x71, 0x44, 0x61, 0x6e, 0x6d, 0x61, 0x6b, 0x75, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x69, 0x76, 0x65, 0x52, 0x6f, + 0x6f, 0x6d, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6c, 0x69, 0x76, 0x65, + 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x75, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x75, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x73, 0x67, 0x49, + 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x12, 0x1c, + 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x24, 0x0a, 0x0d, + 0x6e, 0x6f, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6e, 0x6f, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x4c, 0x65, 0x76, + 0x65, 0x6c, 0x12, 0x36, 0x0a, 0x16, 0x66, 0x61, 0x6e, 0x73, 0x4d, 0x65, 0x64, 0x61, 0x6c, 0x57, + 0x65, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x16, 0x66, 0x61, 0x6e, 0x73, 0x4d, 0x65, 0x64, 0x61, 0x6c, 0x57, 0x65, 0x61, + 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x66, 0x61, + 0x6e, 0x73, 0x4d, 0x65, 0x64, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x66, 0x61, 0x6e, 0x73, 0x4d, 0x65, 0x64, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x26, 0x0a, 0x0e, 0x66, 0x61, 0x6e, 0x73, 0x4d, 0x65, 0x64, 0x61, 0x6c, 0x4c, 0x65, 0x76, + 0x65, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x66, 0x61, 0x6e, 0x73, 0x4d, 0x65, + 0x64, 0x61, 0x6c, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0xe0, 0x03, 0x0a, 0x06, 0x4d, 0x71, 0x47, + 0x69, 0x66, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x69, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6c, 0x69, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x75, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x75, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x08, 0x73, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xe0, 0x01, - 0x0a, 0x06, 0x4d, 0x71, 0x47, 0x69, 0x66, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, - 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, - 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x69, 0x76, 0x65, 0x52, 0x6f, 0x6f, 0x6d, - 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6c, 0x69, 0x76, 0x65, 0x52, 0x6f, - 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x75, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x75, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x67, 0x69, 0x66, 0x74, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x67, 0x69, - 0x66, 0x74, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x03, 0x6e, 0x75, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x69, 0x66, 0x74, 0x4e, 0x61, - 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x67, 0x69, 0x66, 0x74, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x50, 0x61, - 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x50, 0x61, 0x69, 0x64, - 0x2a, 0x39, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x0c, 0x0a, 0x08, - 0x62, 0x69, 0x6c, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x68, 0x75, - 0x79, 0x61, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x64, 0x6f, 0x75, 0x79, 0x75, 0x10, 0x02, 0x12, - 0x0a, 0x0a, 0x06, 0x64, 0x6f, 0x75, 0x79, 0x69, 0x6e, 0x10, 0x03, 0x42, 0x07, 0x5a, 0x05, 0x2f, - 0x70, 0x62, 0x4d, 0x71, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x05, 0x75, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, + 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, + 0x16, 0x0a, 0x06, 0x67, 0x69, 0x66, 0x74, 0x49, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x06, 0x67, 0x69, 0x66, 0x74, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x69, 0x66, 0x74, 0x4e, + 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x67, 0x69, 0x66, 0x74, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x69, 0x66, 0x74, 0x4e, 0x75, 0x6d, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x67, 0x69, 0x66, 0x74, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, + 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x70, 0x72, + 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x50, 0x61, 0x69, 0x64, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x50, 0x61, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6d, + 0x73, 0x67, 0x49, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x73, 0x67, 0x49, + 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0c, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x24, 0x0a, 0x0d, 0x6e, 0x6f, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x4c, 0x65, 0x76, 0x65, 0x6c, + 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6e, 0x6f, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, + 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x36, 0x0a, 0x16, 0x66, 0x61, 0x6e, 0x73, 0x4d, 0x65, 0x64, + 0x61, 0x6c, 0x57, 0x65, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x66, 0x61, 0x6e, 0x73, 0x4d, 0x65, 0x64, 0x61, 0x6c, + 0x57, 0x65, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x24, 0x0a, + 0x0d, 0x66, 0x61, 0x6e, 0x73, 0x4d, 0x65, 0x64, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x0f, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x66, 0x61, 0x6e, 0x73, 0x4d, 0x65, 0x64, 0x61, 0x6c, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x66, 0x61, 0x6e, 0x73, 0x4d, 0x65, 0x64, 0x61, 0x6c, + 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x66, 0x61, 0x6e, + 0x73, 0x4d, 0x65, 0x64, 0x61, 0x6c, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x2a, 0x39, 0x0a, 0x08, 0x50, + 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x0c, 0x0a, 0x08, 0x62, 0x69, 0x6c, 0x69, 0x62, + 0x69, 0x6c, 0x69, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x68, 0x75, 0x79, 0x61, 0x10, 0x01, 0x12, + 0x09, 0x0a, 0x05, 0x64, 0x6f, 0x75, 0x79, 0x75, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x64, 0x6f, + 0x75, 0x79, 0x69, 0x6e, 0x10, 0x03, 0x42, 0x07, 0x5a, 0x05, 0x2f, 0x70, 0x62, 0x4d, 0x71, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -466,10 +623,10 @@ func file_mq_proto_rawDescGZIP() []byte { var file_mq_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_mq_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_mq_proto_goTypes = []interface{}{ - (Platform)(0), // 0: pb.Platform - (*MqGuardBuy)(nil), // 1: pb.MqGuardBuy - (*MqDanmaku)(nil), // 2: pb.MqDanmaku - (*MqGift)(nil), // 3: pb.MqGift + (Platform)(0), // 0: pb.Platform + (*MqNobilityBuy)(nil), // 1: pb.MqNobilityBuy + (*MqDanmaku)(nil), // 2: pb.MqDanmaku + (*MqGift)(nil), // 3: pb.MqGift } var file_mq_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type @@ -486,7 +643,7 @@ func file_mq_proto_init() { } if !protoimpl.UnsafeEnabled { file_mq_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MqGuardBuy); i { + switch v := v.(*MqNobilityBuy); i { case 0: return &v.state case 1: diff --git a/pb/mq.proto b/pb/mq.proto index 7a6931f..aa90997 100644 --- a/pb/mq.proto +++ b/pb/mq.proto @@ -11,27 +11,36 @@ enum Platform { douyin = 3; // 抖音 } -message MqGuardBuy { - string platform = 1; - int64 liveRoomId = 2; - int64 uid = 3; - string uname = 4; - int32 guardLevel = 5; - int32 num = 6; - int64 price = 7; - int64 giftId = 8; - string giftName = 9; - int64 startTime = 10; - int64 endTime = 11; +message MqNobilityBuy { + string platform = 1; // 平台 + int64 liveRoomId = 2; // 直播间ID + int64 uid = 3; // 用户ID + string uname = 4; // 用户名 + string avatar = 5; // 头像 + string msgId = 6; // 消息唯一ID + int64 nobilityLevel = 7; // 贵族等级 + int64 price = 8; // 平台price + int64 startTime = 9; // 开始时间 + int64 endTime = 10; // 过期时间 + + bool fansMedalWearingStatus = 11; // 牌子佩戴状态 + string fansMedalName = 12; // 粉丝牌子名 + int64 fansMedalLevel = 13; // 粉丝牌子等级 } message MqDanmaku { - string platform = 1; - int64 liveRoomId = 2; - int64 uid = 3; - string uname = 4; - string content = 5; - int64 sendTime = 6; + string platform = 1; // 平台 + int64 liveRoomId = 2; // 直播间ID + int64 uid = 3; // 用户ID + string uname = 4; // 用户名 + string avatar = 5; // 头像 + string msg = 6; // 内容 + string msgId = 7; // 消息唯一ID + int64 timestamp = 8; // 发送时间 + int64 nobilityLevel = 9; // 贵族等级 + bool fansMedalWearingStatus = 10; // 牌子佩戴状态 + string fansMedalName = 11; // 粉丝牌子名 + int64 fansMedalLevel = 12; // 粉丝牌子等级 } message MqGift { @@ -39,9 +48,18 @@ message MqGift { int64 liveRoomId = 2; int64 uid = 3; string uname = 4; - int64 giftId = 5; - int64 num = 6; + string avatar = 5; // 头像 + + int64 giftId = 6; string giftName = 7; - int64 price = 8; - bool isPaid = 9; + int64 giftNum = 8; + int64 price = 9; + bool isPaid = 10; + + string msgId = 11; // 消息唯一ID + int64 timestamp = 12; // 收礼时间 + int64 nobilityLevel = 13; // 贵族等级 + bool fansMedalWearingStatus = 14; // 牌子佩戴状态 + string fansMedalName = 15; // 粉丝牌子名 + int64 fansMedalLevel = 16; // 粉丝牌子等级 } \ No newline at end of file diff --git a/pkg/timex/expire.go b/pkg/timex/expire.go new file mode 100644 index 0000000..806135e --- /dev/null +++ b/pkg/timex/expire.go @@ -0,0 +1,28 @@ +package timex + +import ( + "github.com/jinzhu/now" + "time" +) + +// DayExpire 日期是否过期 +// 使用 BeginningOfDay 判断 +func DayExpire(nowTime time.Time, src time.Time, forever bool) bool { + if forever { + return false + } + today := now.With(nowTime).BeginningOfDay() + return !today.Before(now.With(src).BeginningOfDay()) +} + +// DayRemain 剩余天数(包括今天) +func DayRemain(nowTime time.Time, src time.Time, forever bool) int32 { + if forever { + return -1 + } + resp := int32(src.YearDay() - nowTime.YearDay()) + if resp < 0 { + resp = 0 + } + return resp +} diff --git a/pkg/timex/parse.go b/pkg/timex/parse.go new file mode 100644 index 0000000..b640f46 --- /dev/null +++ b/pkg/timex/parse.go @@ -0,0 +1,22 @@ +package timex + +import "time" + +const ( + seconds = 1e11 + milliseconds = 1e14 + microseconds = 1e17 +) + +func TimestampToTime(ts int64) time.Time { + if ts < seconds { + return time.Unix(ts, 0) + } + if ts < milliseconds { + return time.Unix(ts/1000, (ts%1000)*1e6) + } + if ts < microseconds { + return time.Unix(ts/1e6, (ts%1e6)*1000) + } + return time.Unix(0, ts) +}