This repository has been archived by the owner on Feb 16, 2022. It is now read-only.
/
bot.go
123 lines (102 loc) · 2.69 KB
/
bot.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package onebot
import (
"crypto/hmac"
"crypto/sha1"
"encoding/hex"
"encoding/json"
"io"
"net/http"
"path"
"strconv"
"strings"
"sync"
"github.com/sirupsen/logrus"
"github.com/tidwall/gjson"
)
type Bot struct {
BotConfig *BotConfig
Logger *logrus.Logger
httpServer *http.ServeMux
handlerMap *HandlerMap
}
type BotConfig struct {
SelfId int64
ApiConfig ApiConfig
ServerConfig ServerConfig
}
type ApiConfig struct {
Token string
Address string
}
type ServerConfig struct {
Secret string
Address string
Path string
}
func New(botConfig BotConfig) *Bot {
return &Bot{
BotConfig: &botConfig,
Logger: DefaultLogger(logrus.DebugLevel),
httpServer: http.NewServeMux(),
handlerMap: &HandlerMap{
Map: &sync.Map{},
},
}
}
func (bot *Bot) Start() {
bot.init()
bot.Logger.Infoln("Bot tarted")
bot.Logger.Infoln("Listening event on " + path.Join(bot.BotConfig.ServerConfig.Address, bot.BotConfig.ServerConfig.Path))
http.ListenAndServe(bot.BotConfig.ServerConfig.Address, bot.httpServer)
}
func (bot *Bot) init() {
bot.httpServer.HandleFunc(bot.BotConfig.ServerConfig.Path, bot.eventDispatcher)
}
func (bot *Bot) eventDispatcher(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
bot.Logger.Error("读取 Body 错误: " + err.Error())
return
}
sig := r.Header.Get("X-Signature")
if sig != "" {
if receivedSig := strings.TrimPrefix(r.Header.Get("X-Signature"), "sha1="); !checkSignature(receivedSig, body, bot.BotConfig.ServerConfig.Secret) {
bot.Logger.Warnln("签名认证失败")
w.WriteHeader(http.StatusForbidden)
return
}
}
w.WriteHeader(http.StatusNoContent)
selfId, _ := strconv.ParseInt(r.Header.Get("X-Self-ID"), 10, 64)
if bot.BotConfig.SelfId != selfId {
bot.Logger.Warnln("未知 self_id 事件上报", selfId)
return
}
postType := gjson.ParseBytes(body).Get("post_type").String()
bot.dispatch(body, postType)
}
func (bot *Bot) dispatch(body []byte, postType string) {
var event Event
if err := json.Unmarshal(body, &event); err != nil {
bot.Logger.Errorln("解析 MessageEvent 错误: " + err.Error())
return
}
handlers := bot.handlerMap.GetHandlers(postType)
for _, handler := range handlers {
if event.PostType == PostTypeMessage {
if !strings.HasPrefix(event.RawMessage, handler.MessagePrefix) {
continue
}
if handler.MessageType != "" && handler.MessageType != event.MessageType {
continue
}
}
go handler.Handle(&Context{Event: event, Bot: bot})
}
}
func checkSignature(sha string, body []byte, secret string) bool {
hash := hmac.New(sha1.New, []byte(secret))
hash.Write(body)
expectedSig := hex.EncodeToString(hash.Sum(nil))
return sha == expectedSig
}