Skip to content

Commit 7fb7bc3

Browse files
casonliwsqDevTeam
authored andcommitted
webhook: 支持 http webhook 模式回调 (merge request !42)
Squash merge branch 'feature_20220322_vissong_story_872297131' into 'master' TAPD: --story=872297131
1 parent 7c6485b commit 7fb7bc3

32 files changed

+852
-408
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# vendor/
1616
.idea
1717
# 用于存储demo中使用的 token,不提交到仓库
18-
examples/apitest/config.yaml
18+
examples/apitest/config.yaml.demo
1919
config.yaml
2020
demo
2121

dto/http_gateway.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package dto
2+
3+
// HTTPIdentity 鉴权数据
4+
type HTTPIdentity struct {
5+
Intents Intent `json:"intents"`
6+
Shards [2]uint32 `json:"shards"` // array of two integers (shard_id, num_shards)
7+
Callback string `json:"callback_url"`
8+
}
9+
10+
// HTTPReady ready,鉴权后返回
11+
type HTTPReady struct {
12+
Version int `json:"version"`
13+
SessionID string `json:"session_id"`
14+
Bot struct {
15+
ID string `json:"id"`
16+
Username string `json:"username"`
17+
} `json:"bot"`
18+
Shard [2]uint32 `json:"shard"`
19+
}
20+
21+
// HTTPSession session 对象
22+
type HTTPSession struct {
23+
AppID int64 `json:"app_id"`
24+
SessionID string `json:"session_id"`
25+
CallbackURL string `json:"callback_url"`
26+
Env string `json:"env"`
27+
Intents int64 `json:"intents"`
28+
LastHeartbeatTime string `json:"last_heartbeat_time"`
29+
State string `json:"state"`
30+
Shards [2]int64 `json:"shards"`
31+
}

dto/websocket_opcode.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const (
1717
WSInvalidSession
1818
WSHello
1919
WSHeartbeatAck
20+
HTTPCallbackAck
2021
)
2122

2223
// opMeans op 对应的含义字符串标识

event/event.go

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
package event
2+
3+
import (
4+
"encoding/json"
5+
6+
"github.com/tencent-connect/botgo/dto"
7+
"github.com/tidwall/gjson" // 由于回包的 d 类型不确定,gjson 用于从回包json中提取 d 并进行针对性的解析
8+
)
9+
10+
var eventParseFuncMap = map[dto.OPCode]map[dto.EventType]eventParseFunc{
11+
dto.WSDispatchEvent: {
12+
dto.EventGuildCreate: guildHandler,
13+
dto.EventGuildUpdate: guildHandler,
14+
dto.EventGuildDelete: guildHandler,
15+
16+
dto.EventChannelCreate: channelHandler,
17+
dto.EventChannelUpdate: channelHandler,
18+
dto.EventChannelDelete: channelHandler,
19+
20+
dto.EventGuildMemberAdd: guildMemberHandler,
21+
dto.EventGuildMemberUpdate: guildMemberHandler,
22+
dto.EventGuildMemberRemove: guildMemberHandler,
23+
24+
dto.EventMessageCreate: messageHandler,
25+
26+
dto.EventMessageReactionAdd: messageReactionHandler,
27+
dto.EventMessageReactionRemove: messageReactionHandler,
28+
29+
dto.EventAtMessageCreate: atMessageHandler,
30+
dto.EventDirectMessageCreate: directMessageHandler,
31+
32+
dto.EventAudioStart: audioHandler,
33+
dto.EventAudioFinish: audioHandler,
34+
dto.EventAudioOnMic: audioHandler,
35+
dto.EventAudioOffMic: audioHandler,
36+
37+
dto.EventMessageAuditPass: messageAuditHandler,
38+
dto.EventMessageAuditReject: messageAuditHandler,
39+
40+
dto.EventForumThreadCreate: threadHandler,
41+
dto.EventForumThreadUpdate: threadHandler,
42+
dto.EventForumThreadDelete: threadHandler,
43+
dto.EventForumPostCreate: postHandler,
44+
dto.EventForumPostDelete: postHandler,
45+
dto.EventForumReplyCreate: replyHandler,
46+
dto.EventForumReplyDelete: replyHandler,
47+
dto.EventForumAuditResult: forumAuditHandler,
48+
49+
dto.EventInteractionCreate: interactionHandler,
50+
},
51+
}
52+
53+
type eventParseFunc func(event *dto.WSPayload, message []byte) error
54+
55+
// ParseAndHandle 处理回调事件
56+
func ParseAndHandle(payload *dto.WSPayload) error {
57+
// 指定类型的 handler
58+
if h, ok := eventParseFuncMap[payload.OPCode][payload.Type]; ok {
59+
return h(payload, payload.RawMessage)
60+
}
61+
// 透传handler,如果未注册具体类型的 handler,会统一投递到这个 handler
62+
if DefaultHandlers.Plain != nil {
63+
return DefaultHandlers.Plain(payload, payload.RawMessage)
64+
}
65+
return nil
66+
}
67+
68+
// ParseData 解析数据
69+
func ParseData(message []byte, target interface{}) error {
70+
data := gjson.Get(string(message), "d")
71+
return json.Unmarshal([]byte(data.String()), target)
72+
}
73+
74+
func guildHandler(payload *dto.WSPayload, message []byte) error {
75+
data := &dto.WSGuildData{}
76+
if err := ParseData(message, data); err != nil {
77+
return err
78+
}
79+
if DefaultHandlers.Guild != nil {
80+
return DefaultHandlers.Guild(payload, data)
81+
}
82+
return nil
83+
}
84+
85+
func channelHandler(payload *dto.WSPayload, message []byte) error {
86+
data := &dto.WSChannelData{}
87+
if err := ParseData(message, data); err != nil {
88+
return err
89+
}
90+
if DefaultHandlers.Channel != nil {
91+
return DefaultHandlers.Channel(payload, data)
92+
}
93+
return nil
94+
}
95+
96+
func guildMemberHandler(payload *dto.WSPayload, message []byte) error {
97+
data := &dto.WSGuildMemberData{}
98+
if err := ParseData(message, data); err != nil {
99+
return err
100+
}
101+
if DefaultHandlers.GuildMember != nil {
102+
return DefaultHandlers.GuildMember(payload, data)
103+
}
104+
return nil
105+
}
106+
107+
func messageHandler(payload *dto.WSPayload, message []byte) error {
108+
data := &dto.WSMessageData{}
109+
if err := ParseData(message, data); err != nil {
110+
return err
111+
}
112+
if DefaultHandlers.Message != nil {
113+
return DefaultHandlers.Message(payload, data)
114+
}
115+
return nil
116+
}
117+
118+
func messageReactionHandler(payload *dto.WSPayload, message []byte) error {
119+
data := &dto.WSMessageReactionData{}
120+
if err := ParseData(message, data); err != nil {
121+
return err
122+
}
123+
if DefaultHandlers.MessageReaction != nil {
124+
return DefaultHandlers.MessageReaction(payload, data)
125+
}
126+
return nil
127+
}
128+
129+
func atMessageHandler(payload *dto.WSPayload, message []byte) error {
130+
data := &dto.WSATMessageData{}
131+
if err := ParseData(message, data); err != nil {
132+
return err
133+
}
134+
if DefaultHandlers.ATMessage != nil {
135+
return DefaultHandlers.ATMessage(payload, data)
136+
}
137+
return nil
138+
}
139+
140+
func directMessageHandler(payload *dto.WSPayload, message []byte) error {
141+
data := &dto.WSDirectMessageData{}
142+
if err := ParseData(message, data); err != nil {
143+
return err
144+
}
145+
if DefaultHandlers.DirectMessage != nil {
146+
return DefaultHandlers.DirectMessage(payload, data)
147+
}
148+
return nil
149+
}
150+
151+
func audioHandler(payload *dto.WSPayload, message []byte) error {
152+
data := &dto.WSAudioData{}
153+
if err := ParseData(message, data); err != nil {
154+
return err
155+
}
156+
if DefaultHandlers.Audio != nil {
157+
return DefaultHandlers.Audio(payload, data)
158+
}
159+
return nil
160+
}
161+
162+
func threadHandler(payload *dto.WSPayload, message []byte) error {
163+
data := &dto.WSThreadData{}
164+
if err := ParseData(message, data); err != nil {
165+
return err
166+
}
167+
if DefaultHandlers.Thread != nil {
168+
return DefaultHandlers.Thread(payload, data)
169+
}
170+
return nil
171+
}
172+
173+
func postHandler(payload *dto.WSPayload, message []byte) error {
174+
data := &dto.WSPostData{}
175+
if err := ParseData(message, data); err != nil {
176+
return err
177+
}
178+
if DefaultHandlers.Post != nil {
179+
return DefaultHandlers.Post(payload, data)
180+
}
181+
return nil
182+
}
183+
184+
func replyHandler(payload *dto.WSPayload, message []byte) error {
185+
data := &dto.WSReplyData{}
186+
if err := ParseData(message, data); err != nil {
187+
return err
188+
}
189+
if DefaultHandlers.Reply != nil {
190+
return DefaultHandlers.Reply(payload, data)
191+
}
192+
return nil
193+
}
194+
195+
func forumAuditHandler(payload *dto.WSPayload, message []byte) error {
196+
data := &dto.WSForumAuditData{}
197+
if err := ParseData(message, data); err != nil {
198+
return err
199+
}
200+
if DefaultHandlers.ForumAudit != nil {
201+
return DefaultHandlers.ForumAudit(payload, data)
202+
}
203+
return nil
204+
}
205+
206+
func messageAuditHandler(payload *dto.WSPayload, message []byte) error {
207+
data := &dto.WSMessageAuditData{}
208+
if err := ParseData(message, data); err != nil {
209+
return err
210+
}
211+
if DefaultHandlers.MessageAudit != nil {
212+
return DefaultHandlers.MessageAudit(payload, data)
213+
}
214+
return nil
215+
}
216+
217+
func interactionHandler(payload *dto.WSPayload, message []byte) error {
218+
data := &dto.WSInteractionData{}
219+
if err := ParseData(message, data); err != nil {
220+
return err
221+
}
222+
if DefaultHandlers.Interaction != nil {
223+
return DefaultHandlers.Interaction(payload, data)
224+
}
225+
return nil
226+
}

websocket/event_handler.go renamed to event/register.go

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package websocket
1+
package event
22

33
import (
44
"github.com/tencent-connect/botgo/dto"
@@ -10,20 +10,24 @@ var DefaultHandlers struct {
1010
ErrorNotify ErrorNotifyHandler
1111
Plain PlainEventHandler
1212

13-
Guild GuildEventHandler
14-
GuildMember GuildMemberEventHandler
15-
Channel ChannelEventHandler
13+
Guild GuildEventHandler
14+
GuildMember GuildMemberEventHandler
15+
Channel ChannelEventHandler
16+
1617
Message MessageEventHandler
1718
MessageReaction MessageReactionEventHandler
1819
ATMessage ATMessageEventHandler
1920
DirectMessage DirectMessageEventHandler
20-
Audio AudioEventHandler
2121
MessageAudit MessageAuditEventHandler
22-
Thread ThreadEventHandler
23-
Post PostEventHandler
24-
Reply ReplyEventHandler
25-
ForumAudit ForumAuditEventHandler
26-
Interaction InteractionEventHandler
22+
23+
Audio AudioEventHandler
24+
25+
Thread ThreadEventHandler
26+
Post PostEventHandler
27+
Reply ReplyEventHandler
28+
ForumAudit ForumAuditEventHandler
29+
30+
Interaction InteractionEventHandler
2731
}
2832

2933
// ReadyHandler 可以处理 ws 的 ready 事件
@@ -95,24 +99,39 @@ func RegisterHandlers(handlers ...interface{}) dto.Intent {
9599
dto.EventAudioStart, dto.EventAudioFinish,
96100
dto.EventAudioOnMic, dto.EventAudioOffMic,
97101
)
102+
case InteractionEventHandler:
103+
DefaultHandlers.Interaction = handle
104+
i = i | dto.EventToIntent(dto.EventInteractionCreate)
105+
default:
106+
}
107+
}
108+
i = i | registerRelationHandlers(i, handlers...)
109+
i = i | registerMessageHandlers(i, handlers...)
110+
i = i | registerForumHandlers(i, handlers...)
111+
112+
return i
113+
}
114+
115+
func registerForumHandlers(i dto.Intent, handlers ...interface{}) dto.Intent {
116+
for _, h := range handlers {
117+
switch handle := h.(type) {
98118
case ThreadEventHandler:
119+
DefaultHandlers.Thread = handle
99120
i = i | dto.EventToIntent(
100-
dto.EventForumThreadCreate, dto.EventForumThreadUpdate, dto.EventForumThreadDelete)
121+
dto.EventForumThreadCreate, dto.EventForumThreadUpdate, dto.EventForumThreadDelete,
122+
)
101123
case PostEventHandler:
124+
DefaultHandlers.Post = handle
102125
i = i | dto.EventToIntent(dto.EventForumPostCreate, dto.EventForumPostDelete)
103126
case ReplyEventHandler:
127+
DefaultHandlers.Reply = handle
104128
i = i | dto.EventToIntent(dto.EventForumReplyCreate, dto.EventForumReplyDelete)
105129
case ForumAuditEventHandler:
130+
DefaultHandlers.ForumAudit = handle
106131
i = i | dto.EventToIntent(dto.EventForumAuditResult)
107-
case InteractionEventHandler:
108-
DefaultHandlers.Interaction = handle
109-
i = i | dto.EventToIntent(dto.EventInteractionCreate)
110132
default:
111133
}
112134
}
113-
i = i | registerRelationHandlers(i, handlers...)
114-
i = i | registerMessageHandlers(i, handlers...)
115-
116135
return i
117136
}
118137

websocket/event_handler_test.go renamed to event/register_test.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package websocket
1+
package event
22

33
import (
44
"fmt"
@@ -19,11 +19,13 @@ func TestRegisterHandlers(t *testing.T) {
1919
return nil
2020
}
2121

22-
t.Run("test intent", func(t *testing.T) {
23-
i := RegisterHandlers(guild, message, audio)
24-
fmt.Println(i)
25-
assert.Equal(t, dto.IntentGuildMessages, i&dto.IntentGuildMessages)
26-
assert.Equal(t, dto.IntentGuilds, i&dto.IntentGuilds)
27-
assert.Equal(t, dto.IntentAudio, i&dto.IntentAudio)
28-
})
22+
t.Run(
23+
"test intent", func(t *testing.T) {
24+
i := RegisterHandlers(guild, message, audio)
25+
fmt.Println(i)
26+
assert.Equal(t, dto.IntentGuildMessages, i&dto.IntentGuildMessages)
27+
assert.Equal(t, dto.IntentGuilds, i&dto.IntentGuilds)
28+
assert.Equal(t, dto.IntentAudio, i&dto.IntentAudio)
29+
},
30+
)
2931
}

examples/apitest/config.yaml.demo

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# 在这个配置文件中补充你的 appid 和 bot token,并修改文件名为 config.yaml
2-
appid:
3-
token:
2+
appid :
3+
token :

0 commit comments

Comments
 (0)