github.com/fumiama/NanoBot@v0.0.0-20231122134259-c22d8183efca/event.go (about)

     1  package nano
     2  
     3  import (
     4  	"encoding/json"
     5  	"reflect"
     6  	"strings"
     7  
     8  	log "github.com/sirupsen/logrus"
     9  )
    10  
    11  // Event ...
    12  type Event struct {
    13  	// Type is payload.T
    14  	Type string
    15  	// Seq 序列号
    16  	Seq uint32
    17  	// Value 是 D
    18  	Value any
    19  	// value is the reflect value of Value
    20  	value reflect.Value
    21  }
    22  
    23  // processEvent 处理需要关注的业务事件
    24  func (bot *Bot) processEvent(payload *WebsocketPayload) {
    25  	tp := UnderlineToCamel(payload.T)
    26  	if bot.Handler != nil {
    27  		ev, ok := bot.handlers[tp]
    28  		if !ok {
    29  			return
    30  		}
    31  		log.Debugln(getLogHeader(), "使用 handlers 处理", tp, "事件")
    32  		x := reflect.New(ev.t)
    33  		err := json.Unmarshal(payload.D, x.Interface())
    34  		if err != nil {
    35  			log.Warnln(getLogHeader(), "解析", tp, "事件时出现错误:", err)
    36  			return
    37  		}
    38  		go ev.h(payload.S, bot, x.UnsafePointer())
    39  		return
    40  	}
    41  	ctx := &Ctx{
    42  		Event: Event{
    43  			Type: tp,
    44  			Seq:  payload.S,
    45  		},
    46  		State:  State{},
    47  		caller: bot,
    48  	}
    49  	switch tp {
    50  	case "C2cMessageCreate", "GroupAtMessageCreate":
    51  		ctx.IsQQ = true
    52  	}
    53  	switch tp {
    54  	case "DirectMessageCreate", "C2cMessageCreate", "GroupAtMessageCreate":
    55  		ctx.IsToMe = true
    56  		fallthrough
    57  	case "MessageCreate", "AtMessageCreate":
    58  		tp = "Message"
    59  	case "DirectMessageDelete":
    60  		ctx.IsToMe = true
    61  		fallthrough
    62  	case "MessageDelete", "PublicMessageDelete":
    63  		tp = "MessageDelete"
    64  	}
    65  	matcherLock.RLock()
    66  	n := len(matcherMap[tp])
    67  	if n == 0 {
    68  		matcherLock.RUnlock()
    69  		return
    70  	}
    71  	log.Debugln(getLogHeader(), "pass", tp, "event to plugins")
    72  	matchers := make([]*Matcher, n)
    73  	copy(matchers, matcherMap[tp])
    74  	matcherLock.RUnlock()
    75  	x := reflect.New(types[ctx.Type])
    76  	err := json.Unmarshal(payload.D, x.Interface())
    77  	if err != nil {
    78  		log.Warnln(getLogHeader(), "解析", ctx.Type, "事件时出现错误:", err)
    79  		return
    80  	}
    81  	ctx.Value = x.Interface()
    82  	ctx.value = x
    83  	switch tp {
    84  	case "Message":
    85  		ctx.Message = (*Message)(x.UnsafePointer())
    86  		if ctx.Message.MentionEveryone {
    87  			ctx.IsToMe = true
    88  		}
    89  		if ctx.IsQQ {
    90  			if ctx.Message.Author.UserOpenID != "" {
    91  				ctx.Message.Author.ID = ctx.Message.Author.UserOpenID
    92  			} else if ctx.Message.Author.MemberOpenID != "" {
    93  				ctx.Message.Author.ID = ctx.Message.Author.MemberOpenID
    94  			}
    95  			ctx.Message.ChannelID = ctx.Message.GroupOpenID
    96  		}
    97  		log.Infoln(getLogHeader(), "=>", ctx.Message)
    98  	case "MessageDelete":
    99  		mdl := (*MessageDelete)(x.UnsafePointer())
   100  		opmember, err := ctx.GetGuildMemberOf(mdl.Message.GuildID, mdl.OpUser.ID)
   101  		if err != nil {
   102  			log.Warnln(getLogHeader(), "获取撤回消息者详情错误:", err)
   103  			return
   104  		}
   105  		ctx.Message = (*MessageDelete)(x.UnsafePointer()).Message
   106  		ctx.Message.Member = &Member{
   107  			GuildID: mdl.Message.GuildID,
   108  			User:    ctx.Message.Author,
   109  		}
   110  		ctx.Message.Author = opmember.User
   111  		log.Infoln(getLogHeader(), "x>", mdl)
   112  	}
   113  	go match(ctx, matchers)
   114  }
   115  
   116  func match(ctx *Ctx, matchers []*Matcher) {
   117  	if ctx.Message != nil && ctx.Message.Content != "" { // 确保无空
   118  		ctx.Message.Content = strings.TrimSpace(ctx.Message.Content)
   119  		if !ctx.IsToMe {
   120  			ctx.IsToMe = func(ctx *Ctx) bool {
   121  				name := ctx.GetReady().User.Username
   122  				if strings.HasPrefix(ctx.Message.Content, name) {
   123  					log.Debugln(getLogHeader(), "message before process:", ctx.Message.Content)
   124  					ctx.Message.Content = strings.TrimLeft(ctx.Message.Content[len(name):], " ")
   125  					log.Debugln(getLogHeader(), "message after process:", ctx.Message.Content)
   126  					return true
   127  				}
   128  				atme := ctx.AtMe()
   129  				if strings.HasPrefix(ctx.Message.Content, atme) {
   130  					log.Debugln(getLogHeader(), "message before process:", ctx.Message.Content)
   131  					ctx.Message.Content = strings.TrimLeft(ctx.Message.Content[len(atme):], " ")
   132  					log.Debugln(getLogHeader(), "message after process:", ctx.Message.Content)
   133  					return true
   134  				}
   135  				return OnlyPrivate(ctx)
   136  			}(ctx)
   137  		}
   138  	}
   139  	log.Debugln(getLogHeader(), "message is to me:", ctx.IsToMe)
   140  loop:
   141  	for _, matcher := range matchers {
   142  		for k := range ctx.State { // Clear State
   143  			delete(ctx.State, k)
   144  		}
   145  		matcherLock.RLock()
   146  		m := matcher.copy()
   147  		matcherLock.RUnlock()
   148  		ctx.ma = m
   149  
   150  		// pre handler
   151  		if m.Engine != nil {
   152  			for _, handler := range m.Engine.preHandler {
   153  				if !handler(ctx) { // 有 pre handler 未满足
   154  					if m.Break { // 阻断后续
   155  						break loop
   156  					}
   157  					continue loop
   158  				}
   159  			}
   160  		}
   161  
   162  		for _, rule := range m.Rules {
   163  			if rule != nil && !rule(ctx) { // 有 Rule 的条件未满足
   164  				if m.Break { // 阻断后续
   165  					break loop
   166  				}
   167  				continue loop
   168  			}
   169  		}
   170  
   171  		// mid handler
   172  		if m.Engine != nil {
   173  			for _, handler := range m.Engine.midHandler {
   174  				if !handler(ctx) { // 有 mid handler 未满足
   175  					if m.Break { // 阻断后续
   176  						break loop
   177  					}
   178  					continue loop
   179  				}
   180  			}
   181  		}
   182  
   183  		if m.Process != nil {
   184  			m.Process(ctx) // 处理事件
   185  		}
   186  		if matcher.Temp { // 临时 Matcher 删除
   187  			matcher.Delete()
   188  		}
   189  
   190  		if m.Engine != nil {
   191  			// post handler
   192  			for _, handler := range m.Engine.postHandler {
   193  				handler(ctx)
   194  			}
   195  		}
   196  
   197  		if m.Block { // 阻断后续
   198  			break loop
   199  		}
   200  	}
   201  }