Skip to content

Commit ce34c99

Browse files
committed
finish
1 parent 6a1019d commit ce34c99

25 files changed

+2844
-8
lines changed

.github/nano.jpeg

46.7 KB
Loading

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ go.work
2222

2323
bot_test.go
2424
/test
25+
/data

README.md

+120-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,120 @@
1-
# NanoBot
2-
ZeroBot-like Official QQ Bot Adapter
1+
<div align="center">
2+
<a href="https://crypko.ai/crypko/GtWYDpVMx5GYm/">
3+
<img src=".github/nano.jpeg" alt="东云名乃" width = "256">
4+
</a><br>
5+
6+
<h1>NanoBot</h1>
7+
类 ZeroBot 的官方 QQ 频道适配器<br><br>
8+
9+
<img src="https://counter.seku.su/cmoe?name=NanoBot&theme=r34" /><br>
10+
11+
</div>
12+
13+
## Instructions
14+
15+
> Note: This framework is built mainly for Chinese users thus may display hard-coded Chinese prompts during the interaction.
16+
17+
参见 QQ 官方[文档](https://bot.q.qq.com/wiki/)
18+
19+
## 快速开始(基于插件)
20+
> 查看`example`文件夹以获取更多信息
21+
22+
<table>
23+
<tr>
24+
<td align="center"><img src="https://github.com/fumiama/NanoBot/assets/41315874/6ef9fd95-ae99-449e-85e1-25797271e088"></td>
25+
<td align="center"><img src="https://github.com/fumiama/NanoBot/assets/41315874/edd374e4-b8a5-4cff-a463-8c3b30e537c4"></td>
26+
<td align="center"><img src="https://github.com/fumiama/NanoBot/assets/41315874/ed1b063f-44b0-4950-ac35-1e72745cf3f4"></td>
27+
</tr>
28+
<tr>
29+
<td align="center">开始响应</td>
30+
<td align="center">服务列表</td>
31+
<td align="center">查看用法</td>
32+
</tr>
33+
</table>
34+
35+
![启用禁用](https://github.com/fumiama/NanoBot/assets/41315874/fc7f4774-f64b-44c5-9575-b9483bf3a455)
36+
37+
38+
```go
39+
package main
40+
41+
import (
42+
_ "github.com/fumiama/NanoBot/example/echo"
43+
44+
nano "github.com/fumiama/NanoBot"
45+
log "github.com/sirupsen/logrus"
46+
)
47+
48+
func main() {
49+
log.SetLevel(log.DebugLevel)
50+
nano.OpenAPI = nano.SandboxAPI
51+
nano.OnMessageFullMatch("help").SetBlock(true).
52+
Handle(func(ctx *nano.Ctx) {
53+
_, _ = ctx.SendPlainMessage(false, "echo string")
54+
})
55+
nano.Run(&nano.Bot{
56+
AppID: "你的AppID",
57+
Token: "你的Token",
58+
Secret: "你的Secret, 目前没用到, 可以不填",
59+
Intents: nano.IntentPublic,
60+
SuperUsers: []string{"用户ID1", "用户ID2"},
61+
})
62+
}
63+
```
64+
65+
## 更多选择(传统的事件驱动)
66+
67+
> 如果声明了 Handler, 所有插件将被禁用
68+
69+
![event-based example](https://github.com/fumiama/NanoBot/assets/41315874/414ef9a6-1da2-49ff-b28e-9e3009cdb41c)
70+
71+
```go
72+
package main
73+
74+
import (
75+
"strings"
76+
77+
nano "github.com/fumiama/NanoBot"
78+
log "github.com/sirupsen/logrus"
79+
)
80+
81+
func main() {
82+
log.SetLevel(log.DebugLevel)
83+
nano.OpenAPI = nano.SandboxAPI
84+
nano.Run(&nano.Bot{
85+
AppID: "你的AppID",
86+
Token: "你的Token",
87+
Secret: "你的Secret, 目前没用到, 可以不填",
88+
Intents: nano.IntentPublic,
89+
Handler: &nano.Handler{
90+
OnAtMessageCreate: func(s uint32, bot *nano.Bot, d *nano.Message) {
91+
u := ""
92+
if len(d.Attachments) > 0 {
93+
u = d.Attachments[0].URL
94+
if !strings.HasPrefix(u, "http") {
95+
u = "http://" + u
96+
}
97+
}
98+
_, err := bot.PostMessageToChannel(d.ChannelID, &nano.MessagePost{
99+
Content: "您发送了: " + d.Content,
100+
Image: u,
101+
ReplyMessageID: d.ID,
102+
MessageReference: &nano.MessageReference{
103+
MessageID: d.ID,
104+
},
105+
})
106+
if err != nil {
107+
bot.PostMessageToChannel(d.ChannelID, &nano.MessagePost{
108+
Content: "[ERROR]: " + err.Error(),
109+
ReplyMessageID: d.ID,
110+
})
111+
}
112+
},
113+
},
114+
})
115+
}
116+
```
117+
118+
## Thanks
119+
120+
- [ZeroBot](https://github.com/wdvxdr1123/ZeroBot)

bot.go

+5
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ func (bot *Bot) Authorization() string {
143143
return "Bot " + bot.AppID + "." + bot.Token
144144
}
145145

146+
// AtMe 返回 "<@!"+bot.ready.User.ID+">"
147+
func (bot *Bot) AtMe() string {
148+
return "<@!" + bot.ready.User.ID + ">"
149+
}
150+
146151
// receive 收一个 payload
147152
func (bot *Bot) reveive() (payload WebsocketPayload, err error) {
148153
err = bot.conn.ReadJSON(&payload)

codegen/engine/engine.yml

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
emptyon:
2+
- Message
3+
4+
- GuildCreate
5+
- GuildUpdate
6+
- GuildDelete
7+
- ChannelCreate
8+
- ChannelUpdate
9+
- ChannelDelete
10+
11+
- GuildMemberAdd
12+
- GuildMemberUpdate
13+
- GuildMemberRemove
14+
15+
- MessageCreate
16+
- MessageDelete
17+
18+
- MessageReactionAdd
19+
- MessageReactionRemove
20+
21+
- DirectMessageCreate
22+
- DirectMessageDelete
23+
24+
- OpenForumThreadCreate
25+
- OpenForumThreadUpdate
26+
- OpenForumThreadDelete
27+
- OpenForumPostCreate
28+
- OpenForumPostDelete
29+
- OpenForumReplyCreate
30+
- OpenForumReplyDelete
31+
32+
- AudioOrLiveChannelMemberEnter
33+
- AudioOrLiveChannelMemberExit
34+
35+
- MessageAuditPass
36+
- MessageAuditReject
37+
38+
- ForumThreadCreate
39+
- ForumThreadUpdate
40+
- ForumThreadDelete
41+
- ForumPostCreate
42+
- ForumPostDelete
43+
- ForumReplyCreate
44+
- ForumReplyDelete
45+
- ForumPublishAuditResult
46+
47+
- AudioStart
48+
- AudioFinish
49+
- AudioOnMic
50+
- AudioOffMic
51+
52+
- AtMessageCreate
53+
- PublicMessageDelete
54+
55+
ruleon:
56+
Message:
57+
- Message
58+
Rule:
59+
Prefix: [prefix, string]
60+
Suffix: [suffix, string]
61+
Command: [commands, string]
62+
Regex: [regexPattern, string]
63+
Keyword: [keyword, string]
64+
FullMatch: [src, string]
65+
FullMatchGroup: [src, "[]string"]
66+
KeywordGroup: [keywords, "[]string"]
67+
CommandGroup: [commands, "[]string"]
68+
PrefixGroup: [prefix, "[]string"]
69+
SuffixGroup: [suffix, "[]string"]

codegen/engine/main.go

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package main
2+
3+
import (
4+
"os"
5+
"strings"
6+
7+
"gopkg.in/yaml.v3"
8+
)
9+
10+
const head = `// Code generated by codegen/engine. DO NOT EDIT.
11+
12+
package nano
13+
`
14+
15+
const emptyon = `
16+
// On[Message] ...
17+
func (e *Engine) On[Message](rules ...Rule) *Matcher { return e.On("[Message]", rules...) }
18+
19+
// On[Message] ...
20+
func On[Message](rules ...Rule) *Matcher { return On("[Message]", rules...) }
21+
`
22+
23+
const ruleon = `
24+
// On[Message][Rule] ...
25+
func On[Message][Rule]([Name] [Type], rules ...Rule) *Matcher {
26+
return defaultEngine.On[Message][Rule]([Name], rules...)
27+
}
28+
29+
// On[Message][Rule] ...
30+
func (e *Engine) On[Message][Rule]([Name] [Type], rules ...Rule) *Matcher {
31+
matcher := &Matcher{
32+
Type: "[Message]",
33+
Rules: append([]Rule{[Rule]Rule([Name][...])}, rules...),
34+
Engine: e,
35+
}
36+
e.matchers = append(e.matchers, matcher)
37+
return StoreMatcher(matcher)
38+
}
39+
`
40+
41+
const ruleonshell = `
42+
// On[Message]Shell shell命令触发器
43+
func On[Message]Shell(command string, model interface{}, rules ...Rule) *Matcher {
44+
return defaultEngine.On[Message]Shell(command, model, rules...)
45+
}
46+
47+
// On[Message]Shell shell命令触发器
48+
func (e *Engine) On[Message]Shell(command string, model interface{}, rules ...Rule) *Matcher {
49+
matcher := &Matcher{
50+
Type: "[Message]",
51+
Rules: append([]Rule{ShellRule(command, model)}, rules...),
52+
Engine: e,
53+
}
54+
e.matchers = append(e.matchers, matcher)
55+
return StoreMatcher(matcher)
56+
}
57+
`
58+
59+
type config struct {
60+
EmptyOn []string `yaml:"emptyon"`
61+
RuleOn struct {
62+
Message []string `yaml:"Message"`
63+
Rule map[string][2]string `yaml:"Rule"`
64+
} `yaml:"ruleon"`
65+
}
66+
67+
func main() {
68+
f, err := os.Create("engine_generated.go")
69+
if err != nil {
70+
panic(err)
71+
}
72+
defer f.Close()
73+
_, err = f.WriteString(head)
74+
if err != nil {
75+
panic(err)
76+
}
77+
ef, err := os.Open("codegen/engine/engine.yml")
78+
if err != nil {
79+
panic(err)
80+
}
81+
defer ef.Close()
82+
cfg := config{}
83+
err = yaml.NewDecoder(ef).Decode(&cfg)
84+
if err != nil {
85+
panic(err)
86+
}
87+
for _, msg := range cfg.EmptyOn {
88+
_, err = f.WriteString(strings.ReplaceAll(emptyon, "[Message]", msg))
89+
if err != nil {
90+
panic(err)
91+
}
92+
}
93+
for _, msg := range cfg.RuleOn.Message {
94+
for rule, x := range cfg.RuleOn.Rule {
95+
s := strings.ReplaceAll(ruleon, "[Message]", msg)
96+
s = strings.ReplaceAll(s, "[Rule]", rule)
97+
s = strings.ReplaceAll(s, "[Name]", x[0])
98+
s = strings.ReplaceAll(s, "[Type]", x[1])
99+
if strings.Contains(rule, "Group") {
100+
s = strings.ReplaceAll(s, "[...]", "...")
101+
} else {
102+
s = strings.ReplaceAll(s, "[...]", "")
103+
}
104+
_, err = f.WriteString(s)
105+
if err != nil {
106+
panic(err)
107+
}
108+
}
109+
_, err = f.WriteString(strings.ReplaceAll(ruleonshell, "[Message]", msg))
110+
if err != nil {
111+
panic(err)
112+
}
113+
}
114+
}

0 commit comments

Comments
 (0)