github.com/Mrs4s/MiraiGo@v0.0.0-20240226124653-54bdd873e3fe/client/guild_eventflow.go (about)

     1  package client
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	"github.com/pierrec/lz4/v4"
     8  
     9  	"github.com/pkg/errors"
    10  
    11  	"github.com/Mrs4s/MiraiGo/client/internal/network"
    12  	"github.com/Mrs4s/MiraiGo/client/pb/channel"
    13  	"github.com/Mrs4s/MiraiGo/client/pb/msg"
    14  	"github.com/Mrs4s/MiraiGo/internal/proto"
    15  )
    16  
    17  func init() {
    18  	decoders["MsgPush.PushGroupProMsg"] = decodeGuildEventFlowPacket
    19  }
    20  
    21  var updateChanLock sync.Mutex
    22  
    23  type tipsPushInfo struct {
    24  	TinyId uint64
    25  	// TargetMessageSenderUin int64
    26  	GuildId   uint64
    27  	ChannelId uint64
    28  }
    29  
    30  func decodeGuildEventFlowPacket(c *QQClient, pkt *network.Packet) (any, error) {
    31  	push := new(channel.MsgOnlinePush)
    32  	if err := proto.Unmarshal(pkt.Payload, push); err != nil {
    33  		return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
    34  	}
    35  	if push.CompressFlag.Unwrap() == 1 && len(push.CompressMsg) > 0 {
    36  		press := new(channel.PressMsg)
    37  		dst := make([]byte, len(push.CompressMsg)*2)
    38  		i, err := lz4.UncompressBlock(push.CompressMsg, dst)
    39  		for times := 0; err != nil && err.Error() == "lz4: invalid source or destination buffer too short" && times < 5; times++ {
    40  			dst = append(dst, make([]byte, 1024)...)
    41  			i, err = lz4.UncompressBlock(push.CompressMsg, dst)
    42  		}
    43  		if err != nil {
    44  			return nil, errors.Wrap(err, "failed to decompress guild event packet")
    45  		}
    46  		if err = proto.Unmarshal(dst[:i], press); err != nil {
    47  			return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
    48  		}
    49  		push.Msgs = press.Msgs
    50  	}
    51  	for _, m := range push.Msgs {
    52  		if m.Head == nil {
    53  			continue
    54  		}
    55  		if m.Head.ContentHead.Type.Unwrap() == 3841 {
    56  			// todo: 回头 event flow 的处理移出去重构下逻辑, 先暂时这样方便改
    57  			var common *msg.CommonElem
    58  			if m.Body != nil && m.Body.RichText != nil {
    59  				for _, e := range m.Body.RichText.Elems {
    60  					if e.CommonElem != nil {
    61  						common = e.CommonElem
    62  						break
    63  					}
    64  				}
    65  			}
    66  			if m.Head.ContentHead.SubType.Unwrap() == 2 { // todo: tips?
    67  				// if common == nil { // empty tips
    68  				// }
    69  				tipsInfo := &tipsPushInfo{
    70  					TinyId:    m.Head.RoutingHead.FromTinyid.Unwrap(),
    71  					GuildId:   m.Head.RoutingHead.GuildId.Unwrap(),
    72  					ChannelId: m.Head.RoutingHead.ChannelId.Unwrap(),
    73  				}
    74  				/*
    75  					if len(m.CtrlHead.IncludeUin) > 0 {
    76  						tipsInfo.TargetMessageSenderUin = int64(m.CtrlHead.IncludeUin[0])
    77  					}
    78  				*/
    79  				return tipsInfo, nil
    80  			}
    81  			if common == nil || common.ServiceType.Unwrap() != 500 {
    82  				continue
    83  			}
    84  			eventBody := new(channel.EventBody)
    85  			if err := proto.Unmarshal(common.PbElem, eventBody); err != nil {
    86  				c.error("failed to unmarshal guild channel event body: %v", err)
    87  				continue
    88  			}
    89  			c.processGuildEventBody(m, eventBody)
    90  			continue
    91  		}
    92  		if m.Head.ContentHead.Type.Unwrap() == 3840 {
    93  			if m.Head.RoutingHead.DirectMessageFlag.Unwrap() == 1 {
    94  				// todo: direct message decode
    95  				continue
    96  			}
    97  			if m.Head.RoutingHead.FromTinyid.Unwrap() == c.GuildService.TinyId {
    98  				continue
    99  			}
   100  			if cm := c.GuildService.parseGuildChannelMessage(m); cm != nil {
   101  				c.dispatchGuildChannelMessage(cm)
   102  			}
   103  		}
   104  	}
   105  	return nil, nil
   106  }
   107  
   108  func (c *QQClient) processGuildEventBody(m *channel.ChannelMsgContent, eventBody *channel.EventBody) {
   109  	var guild *GuildInfo
   110  	if m.Head.RoutingHead.GuildId.Unwrap() != 0 {
   111  		if guild = c.GuildService.FindGuild(m.Head.RoutingHead.GuildId.Unwrap()); guild == nil {
   112  			c.warning("process channel event error: guild not found.")
   113  			return
   114  		}
   115  	}
   116  	switch {
   117  	case eventBody.CreateChan != nil:
   118  		for _, chanId := range eventBody.CreateChan.CreateId {
   119  			if guild.FindChannel(chanId.ChanId.Unwrap()) != nil {
   120  				continue
   121  			}
   122  			channelInfo, err := c.GuildService.FetchChannelInfo(guild.GuildId, chanId.ChanId.Unwrap())
   123  			if err != nil {
   124  				c.warning("process create channel event error: fetch channel info error: %v", err)
   125  				continue
   126  			}
   127  			guild.Channels = append(guild.Channels, channelInfo)
   128  			c.dispatchGuildChannelCreatedEvent(&GuildChannelOperationEvent{
   129  				OperatorId:  m.Head.RoutingHead.FromTinyid.Unwrap(),
   130  				GuildId:     m.Head.RoutingHead.GuildId.Unwrap(),
   131  				ChannelInfo: channelInfo,
   132  			})
   133  		}
   134  	case eventBody.DestroyChan != nil:
   135  		for _, chanId := range eventBody.DestroyChan.DeleteId {
   136  			channelInfo := guild.FindChannel(chanId.ChanId.Unwrap())
   137  			if channelInfo == nil {
   138  				continue
   139  			}
   140  			guild.removeChannel(chanId.ChanId.Unwrap())
   141  			c.dispatchGuildChannelDestroyedEvent(&GuildChannelOperationEvent{
   142  				OperatorId:  m.Head.RoutingHead.FromTinyid.Unwrap(),
   143  				GuildId:     guild.GuildId,
   144  				ChannelInfo: channelInfo,
   145  			})
   146  		}
   147  	case eventBody.ChangeChanInfo != nil:
   148  		updateChanLock.Lock()
   149  		defer updateChanLock.Unlock()
   150  		oldInfo := guild.FindChannel(eventBody.ChangeChanInfo.ChanId.Unwrap())
   151  		if oldInfo == nil {
   152  			info, err := c.GuildService.FetchChannelInfo(m.Head.RoutingHead.GuildId.Unwrap(), eventBody.ChangeChanInfo.ChanId.Unwrap())
   153  			if err != nil {
   154  				c.error("failed to decode channel info updated event: fetch channel info failed: %v", err)
   155  				return
   156  			}
   157  			guild.Channels = append(guild.Channels, info)
   158  			oldInfo = info
   159  		}
   160  		if time.Now().Unix()-oldInfo.fetchTime <= 2 {
   161  			return
   162  		}
   163  		newInfo, err := c.GuildService.FetchChannelInfo(m.Head.RoutingHead.GuildId.Unwrap(), eventBody.ChangeChanInfo.ChanId.Unwrap())
   164  		if err != nil {
   165  			c.error("failed to decode channel info updated event: fetch channel info failed: %v", err)
   166  			return
   167  		}
   168  		for i := range guild.Channels {
   169  			if guild.Channels[i].ChannelId == newInfo.ChannelId {
   170  				guild.Channels[i] = newInfo
   171  				break
   172  			}
   173  		}
   174  		c.dispatchGuildChannelUpdatedEvent(&GuildChannelUpdatedEvent{
   175  			OperatorId:     m.Head.RoutingHead.FromTinyid.Unwrap(),
   176  			GuildId:        m.Head.RoutingHead.GuildId.Unwrap(),
   177  			ChannelId:      eventBody.ChangeChanInfo.ChanId.Unwrap(),
   178  			OldChannelInfo: oldInfo,
   179  			NewChannelInfo: newInfo,
   180  		})
   181  	case eventBody.JoinGuild != nil:
   182  		/* 应该不会重复推送把, 不会吧不会吧
   183  		if mem := guild.FindMember(eventBody.JoinGuild.MemberTinyid.Unwrap()); mem != nil {
   184  			c.info("ignore join guild event: member %v already exists", mem.TinyId)
   185  			return
   186  		}
   187  		*/
   188  		profile, err := c.GuildService.FetchGuildMemberProfileInfo(guild.GuildId, eventBody.JoinGuild.MemberTinyid.Unwrap())
   189  		if err != nil {
   190  			c.error("failed to decode member join guild event: get member profile error: %v", err)
   191  			return
   192  		}
   193  		info := &GuildMemberInfo{
   194  			TinyId:   profile.TinyId,
   195  			Nickname: profile.Nickname,
   196  		}
   197  		// guild.Members = append(guild.Members, info)
   198  		c.dispatchMemberJoinedGuildEvent(&MemberJoinGuildEvent{
   199  			Guild:  guild,
   200  			Member: info,
   201  		})
   202  	case eventBody.UpdateMsg != nil:
   203  		if eventBody.UpdateMsg.EventType.Unwrap() == 1 || eventBody.UpdateMsg.EventType.Unwrap() == 2 {
   204  			c.dispatchGuildMessageRecalledEvent(&GuildMessageRecalledEvent{
   205  				OperatorId: eventBody.UpdateMsg.OperatorTinyid.Unwrap(),
   206  				GuildId:    m.Head.RoutingHead.GuildId.Unwrap(),
   207  				ChannelId:  m.Head.RoutingHead.ChannelId.Unwrap(),
   208  				MessageId:  eventBody.UpdateMsg.MsgSeq.Unwrap(),
   209  				RecallTime: int64(m.Head.ContentHead.Time.Unwrap()),
   210  			})
   211  			return
   212  		}
   213  		if eventBody.UpdateMsg.EventType.Unwrap() == 4 { // 消息贴表情更新 (包含添加或删除)
   214  			t, err := c.GuildService.pullChannelMessages(m.Head.RoutingHead.GuildId.Unwrap(), m.Head.RoutingHead.ChannelId.Unwrap(), eventBody.UpdateMsg.MsgSeq.Unwrap(), eventBody.UpdateMsg.MsgSeq.Unwrap(), eventBody.UpdateMsg.EventVersion.Unwrap()-1, false)
   215  			if err != nil || len(t) == 0 {
   216  				c.error("process guild event flow error: pull eventMsg message error: %v", err)
   217  				return
   218  			}
   219  			// 自己的消息被贴表情会单独推送一个tips, 这里不需要解析
   220  			if t[0].Head.RoutingHead.FromTinyid.Unwrap() == c.GuildService.TinyId {
   221  				return
   222  			}
   223  			updatedEvent := &GuildMessageReactionsUpdatedEvent{
   224  				GuildId:          m.Head.RoutingHead.GuildId.Unwrap(),
   225  				ChannelId:        m.Head.RoutingHead.ChannelId.Unwrap(),
   226  				MessageId:        t[0].Head.ContentHead.Seq.Unwrap(),
   227  				CurrentReactions: decodeGuildMessageEmojiReactions(t[0]),
   228  			}
   229  			tipsInfo, err := c.waitPacketTimeoutSyncF("MsgPush.PushGroupProMsg", time.Second, func(i any) bool {
   230  				if i == nil {
   231  					return false
   232  				}
   233  				_, ok := i.(*tipsPushInfo)
   234  				return ok
   235  			})
   236  			if err == nil {
   237  				updatedEvent.OperatorId = tipsInfo.(*tipsPushInfo).TinyId
   238  				// updatedEvent.MessageSenderUin = tipsInfo.(*tipsPushInfo).TargetMessageSenderUin
   239  			}
   240  			c.dispatchGuildMessageReactionsUpdatedEvent(updatedEvent)
   241  		}
   242  	}
   243  }