diff --git a/README.md b/README.md
index 284a3405..475f41ef 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
[](https://raw.githubusercontent.com/wdvxdr1123/ZeroBot/main/LICENSE)
[](https://jq.qq.com/?_wv=1027&k=E6Zov6Fi)
-文档正在咕咕中, 具体使用可以参考example文件夹。
+
## ⚡️ 快速使用
@@ -41,6 +41,10 @@ func main() {
}
```
+## 📖 文档
+
+[**--> 点击这里查看文档 <--**](https://wdvxdr1123.github.io/ZeroBot/)
+
## 🎯 特性
- 通过 `init` 函数实现插件式
@@ -62,4 +66,4 @@ func main() {
-
+
\ No newline at end of file
diff --git a/docs/.nojekyll b/docs/.nojekyll
new file mode 100644
index 00000000..e69de29b
diff --git a/docs/_navbar.md b/docs/_navbar.md
new file mode 100644
index 00000000..6d6c437e
--- /dev/null
+++ b/docs/_navbar.md
@@ -0,0 +1,2 @@
+* [English](en/)
+* [简体中文](zh-cn/)
\ No newline at end of file
diff --git a/docs/_sidebar.md b/docs/_sidebar.md
new file mode 100644
index 00000000..8da27d74
--- /dev/null
+++ b/docs/_sidebar.md
@@ -0,0 +1,11 @@
+* [Introduction](en/)
+* [Quick Start](en/guide)
+* [Core API](en/api)
+* [Creating Plugins](en/plugins)
+
+---
+
+* [介绍](zh-cn/)
+* [快速开始](zh-cn/guide)
+* [核心 API](zh-cn/api)
+* [创建插件](zh-cn/plugins)
\ No newline at end of file
diff --git a/docs/en/README.md b/docs/en/README.md
new file mode 100644
index 00000000..e016ca38
--- /dev/null
+++ b/docs/en/README.md
@@ -0,0 +1,5 @@
+# ZeroBot
+
+> A powerful and extensible QQ bot framework.
+
+[Next: Quick Start](/en/guide.md)
\ No newline at end of file
diff --git a/docs/en/_sidebar.md b/docs/en/_sidebar.md
new file mode 100644
index 00000000..1701529e
--- /dev/null
+++ b/docs/en/_sidebar.md
@@ -0,0 +1,4 @@
+* [Home](README.md)
+* [Getting Started](guide.md)
+* [Creating Plugins](plugins.md)
+* [Core API](api.md)
\ No newline at end of file
diff --git a/docs/en/api.md b/docs/en/api.md
new file mode 100644
index 00000000..335c7f5c
--- /dev/null
+++ b/docs/en/api.md
@@ -0,0 +1,808 @@
+[Previous: Quick Start](/en/guide.md)
+
+# Core API
+
+This section provides an overview of the core API provided by ZeroBot.
+
+## The `zero` Package
+
+The `zero` package is the core of ZeroBot. It provides the main functionality for creating and running a bot.
+
+### `zero.New() *zero.Engine`
+
+This function creates a new bot engine.
+
+```go
+engine := zero.New()
+```
+
+### `engine.OnMessage(...Rule) *Matcher`
+
+This method registers a handler for message events. It returns a `Matcher` instance that can be used to further configure the handler.
+
+A `Rule` is a function that takes a `*zero.Ctx` and returns a boolean. If the rule returns `true`, the handler will be executed.
+
+```go
+// This handler will only be triggered if the message is "hello"
+engine.OnMessage(func(ctx *zero.Ctx) bool {
+ return ctx.Event.Message.String() == "hello"
+}).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("world")
+})
+```
+
+### `matcher.Handle(func(ctx *zero.Ctx))`
+
+This method sets the handler function for the matcher. The handler will be called whenever a message event is received that matches the rules of the matcher.
+
+### `ctx.Send(message ...message.MessageSegment)`
+
+This method sends a message to the same context where the event was received.
+
+`message.MessageSegment` is a message segment, which can be text, an image, an emoji, etc.
+
+```go
+ctx.Send("hello", message.Image("https://example.com/image.png"))
+```
+
+## The `Ctx` Object
+
+The `Ctx` object is the context for an event handler. It contains all the information about the event, such as:
+
+- `Ctx.Event`: The raw event data.
+- `Ctx.Event.Message`: The message content.
+- `Ctx.Event.UserID`: The sender's QQ ID.
+- `Ctx.Event.GroupID`: The group ID (if it's a group message).
+
+You can use the `Ctx` object to get more information about an event and to interact with the user.
+
+## The `message` Package
+
+The `message` package provides types and functions for working with message segments.
+
+A `MessageSegment` represents a single part of a message. A complete message, represented by the `Message` type, is an array of these segments (`[]Segment`). This allows you to create rich messages that combine different types of content.
+
+Each `Segment` has two fields:
+
+* **`Type` (string):** Indicates the type of content in the segment. Common types include:
+ * `text`: Plain text.
+ * `image`: An image.
+ * `face`: A QQ emoji.
+ * `at`: Mentioning a user.
+ * `file`: A file.
+
+* **`Data` (map[string]string):** A map containing the data for the segment. The keys and values in this map depend on the segment's `Type`.
+
+The `message` package provides helper functions to easily create these segments, such as:
+
+### `message.Text(text ...interface{})`
+
+Creates a plain text message segment.
+
+- `text`: The text content to be sent. Multiple arguments can be passed, and they will be converted to strings and concatenated.
+
+**Example:**
+```go
+ctx.Send(message.Text("Hello, ", "World!")) // Sends "Hello, World!"
+```
+
+### `message.Face(id int)`
+
+Creates a QQ emoji message segment.
+
+- `id`: The ID of the QQ emoji.
+
+**Example:**
+```go
+ctx.Send(message.Face(123)) // Sends a QQ emoji with ID 123
+```
+
+### `message.File(file, name string)`
+
+Creates a file message segment.
+
+- `file`: The URL, local path, or Base64 encoded data of the file.
+- `name`: The name of the file.
+
+**Example:**
+```go
+ctx.Send(message.File("file:///C:/example.txt", "example.txt"))
+```
+
+### `message.Image(file string, summary ...interface{})`
+
+Creates an image message segment.
+
+- `file`: The URL, local path, or Base64 encoded data of the image.
+- `summary` (optional): The preview text of the image (LLOneBot extension).
+
+**Example:**
+```go
+ctx.Send(message.Image("https://example.com/image.png"))
+```
+
+### `message.ImageBytes(data []byte)`
+
+Creates an image message segment from byte data.
+
+- `data`: The byte data of the image.
+
+**Example:**
+```go
+imageData, _ := ioutil.ReadFile("image.jpg")
+ctx.Send(message.ImageBytes(imageData))
+```
+
+### `message.Record(file string)`
+
+Creates a voice message segment.
+
+- `file`: The URL, local path, or Base64 encoded data of the voice.
+
+**Example:**
+```go
+ctx.Send(message.Record("https://example.com/audio.mp3"))
+```
+
+### `message.Video(file string)`
+
+Creates a video message segment.
+
+- `file`: The URL, local path, or Base64 encoded data of the video.
+
+**Example:**
+```go
+ctx.Send(message.Video("https://example.com/video.mp4"))
+```
+
+### `message.At(qq int64)`
+
+Creates an @ message segment.
+
+- `qq`: The QQ number of the person to @. If it is `0`, it will create an @all message segment.
+
+**Example:**
+```go
+ctx.Send(message.At(123456789)) // @ user with QQ number 123456789
+```
+
+### `message.AtAll()`
+
+Creates an @all message segment.
+
+**Example:**
+```go
+ctx.Send(message.AtAll()) // @ all members
+```
+
+### `message.Music(mType string, id int64)`
+
+Creates a music sharing message segment.
+
+- `mType`: The type of music platform, such as `qq`, `163`.
+- `id`: The ID of the music.
+
+**Example:**
+```go
+ctx.Send(message.Music("163", 123456)) // Share a song with ID 123456 from NetEase Cloud Music
+```
+
+### `message.CustomMusic(url, audio, title string)`
+
+Creates a custom music sharing message segment.
+
+- `url`: The URL to jump to after clicking the share.
+- `audio`: The URL of the music.
+- `title`: The title of the music.
+
+**Example:**
+```go
+ctx.Send(message.CustomMusic("https://example.com", "https://example.com/audio.mp3", "My Song"))
+```
+
+### `message.Reply(id interface{})`
+
+Creates a reply message segment.
+
+- `id`: The ID of the message to reply to.
+
+**Example:**
+```go
+// Reply to the currently received message
+ctx.Send(message.Reply(ctx.Event.MessageID), message.Text("Got it!"))
+```
+
+### `message.Forward(id string)`
+
+Creates a forward message segment.
+
+- `id`: The ID of the forward message (usually returned by `ctx.UploadGroupForwardMessage`).
+
+**Example:**
+```go
+// (Requires uploading the forward message first)
+forwardID := "..." // Get from the upload API
+ctx.Send(message.Forward(forwardID))
+```
+
+### `message.Node(id int64)`
+
+Creates a forward message node.
+
+- `id`: The ID of the message.
+
+**Example:**
+```go
+// Usually used in conjunction with CustomNode to build custom forward messages
+```
+
+### `message.CustomNode(nickname string, userID int64, content interface{})`
+
+Creates a custom forward message node.
+
+- `nickname`: The nickname of the sender.
+- `userID`: The QQ number of the sender.
+- `content`: The message content, which can be `string`, `message.Message`, or `[]message.Segment`.
+
+**Example:**
+```go
+node1 := message.CustomNode("User1", 10001, "Hello")
+node2 := message.CustomNode("User2", 10002, message.Message{message.Image("https://example.com/img.png")})
+forwardMsg, _ := ctx.UploadGroupForwardMessage([]message.Segment{node1, node2})
+ctx.Send(forwardMsg)
+```
+
+### `message.XML(data string)`
+
+Creates an XML message segment.
+
+- `data`: The XML data.
+
+**Example:**
+```go
+xmlData := "content"
+ctx.Send(message.XML(xmlData))
+```
+
+### `message.JSON(data string)`
+
+Creates a JSON message segment.
+
+- `data`: The JSON data.
+
+**Example:**
+```go
+jsonData := `{"key":"value"}`
+ctx.Send(message.JSON(jsonData))
+```
+
+### `message.Gift(userID string, giftID string)`
+
+Creates a group gift message segment (deprecated).
+
+- `userID`: The QQ number of the user who received the gift.
+- `giftID`: The ID of the gift.
+
+### `message.Poke(userID int64)`
+
+Creates a poke message segment.
+
+- `userID`: The QQ number of the user to poke.
+
+**Example:**
+```go
+// Poke someone in a group
+ctx.SendGroupMessage(ctx.Event.GroupID, message.Poke(123456789))
+```
+
+### `message.TTS(text string)`
+
+Creates a text-to-speech message segment.
+
+- `text`: The text to be converted to speech.
+
+**Example:**
+```go
+ctx.Send(message.TTS("Hello, world"))
+```
+
+Creates a new text message segment.
+
+```go
+engine.OnMessage(zero.FullMatchRule("text example")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send(message.Text("This is a text message."))
+})
+```
+
+### `message.Image(string) MessageSegment`
+
+Creates a new image message segment from a URL.
+
+```go
+engine.OnMessage(zero.FullMatchRule("image example")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send(message.Image("https://www.dmoe.cc/random.php"))
+})
+```
+
+### `message.At(int64) MessageSegment`
+
+Creates a new @ message segment.
+
+```go
+engine.OnMessage(zero.FullMatchRule("at example")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send(message.At(ctx.Event.UserID))
+})
+```
+
+## Engine's Chainable Methods
+
+ZeroBot's `engine` provides a series of methods starting with `On` to register handlers for different types of events. These methods are designed to be chained, allowing you to link multiple conditions and the final execution logic into clear, readable code.
+
+A typical chain looks like this:
+
+```go
+engine.OnMessage(Rule1, Rule2, ...).Handle(func(ctx *zero.Ctx) {
+ // Your logic here
+})
+```
+
+- **`engine.OnMessage(...Rule)`**: The start of the chain, indicating you want to handle a message event. You can pass one or more `Rule` functions as arguments. The handler is processed only if **all** `Rule` functions return `true`.
+- **`engine.OnCommand(...string)`**: A convenient method specifically for handling commands. It is equivalent to `engine.OnMessage(OnlyToMe, CommandRule(...))`.
+- **`.Handle(func(*zero.Ctx))`**: The end of the chain, defining the logic to be executed. The function inside `.Handle()` is called only after all preceding rules have been successfully matched.
+
+Other methods like `OnNotice` (for handling notification events) and `OnRequest` (for handling request events) follow a similar chaining pattern.
+
+- **`engine.OnNotice(...Rule)`**: Used to handle notification events. Notification events cover a variety of situations, such as group member changes, group file uploads, etc. You can use the `zero.Type()` rule to precisely match different types of notifications.
+
+```go
+// Example: Handle group member increase notifications
+// Send a welcome message when a new member joins the group.
+engine.OnNotice(zero.Type("notice/group_increase")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("Welcome new member!")
+})
+
+// Example: Handle group file upload notifications
+// Give a prompt when a member uploads a file.
+engine.OnNotice(zero.Type("notice/group_upload")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("A new file has been uploaded, please check it.")
+})
+```
+
+- **`engine.OnRequest(...Rule)`**: Used to handle request events, mainly including friend requests and group requests.
+
+```go
+// Example: Automatically approve friend requests
+// Use zero.Type() to match friend requests and call ctx.Approve() to approve the request.
+engine.OnRequest(zero.Type("request/friend")).Handle(func(ctx *zero.Ctx) {
+ ctx.Approve(ctx.Event.Flag, "Nice to meet you") // The second parameter is the welcome message after approval
+})
+
+// Example: Automatically approve group join requests
+// Use zero.Type() to match group requests and call ctx.Approve() to approve the request.
+engine.OnRequest(zero.Type("request/group")).Handle(func(ctx *zero.Ctx) {
+ ctx.Approve(ctx.Event.Flag, "") // Approve the group join request without an additional message
+})
+```
+
+## Built-in `Rule` Functions
+
+ZeroBot provides many built-in `Rule` functions in the `rules.go` file, allowing you to conveniently filter and match events.
+
+### Event Type Matching
+
+- **`Type(typeString string)`**: Matches based on the event's type string, in the format `"post_type/detail_type/sub_type"`.
+
+```go
+// This example handles group messages that exactly match "hello".
+engine.OnMessage(zero.Type("message/group"), zero.FullMatchRule("hello")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("hello world")
+})
+```
+
+### Message Content Matching
+
+- **`PrefixRule(prefixes ...string)`**: Checks if the message starts with a specified prefix. Stores the prefix in `ctx.State["prefix"]` and the rest of the message in `ctx.State["args"]`.
+
+```go
+// This example responds to messages starting with "hello".
+// If the message is "hello world", ctx.State["prefix"] will be "hello" and ctx.State["args"] will be "world".
+engine.OnMessage(zero.PrefixRule("hello")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("world")
+})
+```
+
+- **`SuffixRule(suffixes ...string)`**: Checks if the message ends with a specified suffix.
+
+```go
+// This example responds to messages ending with "world".
+engine.OnMessage(zero.SuffixRule("world")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("hello")
+})
+```
+
+- **`CommandRule(commands ...string)`**: Checks if the message is a command, starting with the configured `CommandPrefix`. Stores the command and arguments in `ctx.State`.
+
+```go
+// Assuming CommandPrefix is "/", this example responds to "/ping".
+// ctx.State["command"] will be "ping".
+engine.OnCommand("ping").Handle(func(ctx *zero.Ctx) {
+ ctx.Send("pong")
+})
+```
+
+- **`OnShell(command string, model interface{}, rules ...Rule)`**: Parses shell-like commands, automatically extracting arguments and flags.
+
+ `OnShell` provides a powerful way to create command-line-like interactions. It automatically parses flags and arguments based on a struct you provide.
+
+ - Define a struct with fields corresponding to the command's flags. You must use the `flag` tag to specify the flag name (e.g., `flag:"t"`).
+ - Supported field types are `bool`, `int`, `string`, and `float64`.
+ - Inside the handler, you can access a pointer to the populated struct instance from `ctx.State["flag"]`.
+ - Other arguments that are not part of any flag are available as a slice of strings (`[]string`) in `ctx.State["args"]`.
+
+```go
+// Example: Creating a "ping" command
+
+// 1. Define the command struct
+// Only fields with a `flag` tag will be registered.
+type Ping struct {
+ T bool `flag:"t"` // -t
+ Timeout int `flag:"w"` // -w
+ Host string `flag:"host"` // --host
+}
+
+// 2. Register the shell command handler
+func init() {
+ zero.OnShell("ping", Ping{}).Handle(func(ctx *zero.Ctx) {
+ // Get the parsed flags from ctx.State
+ ping := ctx.State["flag"].(*Ping) // Note: this is a pointer type
+
+ // Get the non-flag arguments
+ args := ctx.State["args"].([]string)
+
+ // Use the parsed data
+ logrus.Infoln("Ping Host:", ping.Host)
+ logrus.Infoln("Ping Timeout:", ping.Timeout)
+ logrus.Infoln("Ping T-Flag:", ping.T)
+ for i, v := range args {
+ logrus.Infoln("Arg", i, ":", v)
+ }
+
+ // Assuming the received message is: /ping --host 127.0.0.1 -w 5000 -t other_arg
+ // Host will be "127.0.0.1"
+ // Timeout will be 5000
+ // T will be true
+ // args will be ["other_arg"]
+ })
+}
+```
+
+- **`RegexRule(regexPattern string)`**: Matches message content using a regular expression. Stores the match results in `ctx.State["regex_matched"]`.
+
+```go
+// This example responds to messages like "hello, world".
+// ctx.State["regex_matched"] will be a string slice: ["hello, world", "world"].
+engine.OnMessage(zero.RegexRule(`^hello, (.*)$`)).Handle(func(ctx *zero.Ctx) {
+ matched := ctx.State["regex_matched"].([]string)
+ ctx.Send("hello, " + matched[1])
+})
+```
+
+- **`KeywordRule(keywords ...string)`**: Checks if the message contains any of the specified keywords.
+
+```go
+// This example responds to messages containing "cat" or "dog".
+engine.OnMessage(zero.KeywordRule("cat", "dog")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("I like pets!")
+})
+```
+
+- **`FullMatchRule(texts ...string)`**: Requires the message content to exactly match one of the specified texts.
+
+```go
+// This example only responds to the message "hi".
+engine.OnMessage(zero.FullMatchRule("hi")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("hello")
+})
+```
+
+- **`HasPicture(ctx *Ctx) bool`**: Checks if the message contains any pictures. Stores the picture URLs in `ctx.State["image_url"]`.
+
+```go
+// This example responds when a message contains a picture.
+// ctx.State["image_url"] will be a string slice containing the image URLs.
+engine.OnMessage(zero.HasPicture).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("I see you sent a picture!")
+})
+```
+
+### Message Context Matching
+
+- **`OnlyToMe(ctx *Ctx) bool`**: Requires the message to be sent to the bot (e.g., by @-ing the bot).
+
+```go
+// This example responds when the bot is @-ed with the message "are you there".
+engine.OnMessage(zero.OnlyToMe, zero.FullMatchRule("are you there")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("I'm here")
+})
+```
+
+- **`OnlyPrivate(ctx *Ctx) bool`**: Requires the message to be a private message.
+
+```go
+// This example responds to the private message "hello".
+engine.OnMessage(zero.OnlyPrivate, zero.FullMatchRule("hello")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("Hello, nice to meet you!")
+})
+```
+
+- **`OnlyGroup(ctx *Ctx) bool`**: Requires the message to be a group message.
+
+```go
+// This example responds to the group message "hello everyone".
+engine.OnMessage(zero.OnlyGroup, zero.FullMatchRule("hello everyone")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("Hello everyone!")
+})
+```
+
+- **`ReplyRule(messageID int64)`**: Checks if the message is a reply to a specific message ID.
+
+```go
+// This example listens for a command, then waits for a reply to the bot's response.
+var msgID int64
+engine.OnMessage(zero.CommandRule("hello")).Handle(func(ctx *zero.Ctx) {
+ msgID = ctx.Send("world")
+})
+
+engine.OnMessage(zero.ReplyRule(msgID)).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("You replied to me!")
+})
+```
+
+### User and Permission Matching
+
+- **`CheckUser(userIDs ...int64)`**: Checks if the message is from one of the specified user IDs.
+
+```go
+// This example only responds to messages from user 123456789.
+engine.OnMessage(zero.CheckUser(123456789)).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("Hello, designated user!")
+})
+```
+
+- **`CheckGroup(groupIDs ...int64)`**: Checks if the message is from one of the specified group IDs.
+
+```go
+// This example only responds to messages from group 987654321.
+engine.OnMessage(zero.CheckGroup(987654321)).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("Hello, designated group!")
+})
+```
+
+- **`SuperUserPermission(ctx *Ctx) bool`**: Requires the message sender to be a superuser.
+
+```go
+// This example handles the "admin" command only if the sender is a superuser.
+engine.OnMessage(zero.SuperUserPermission, zero.CommandRule("admin")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("Hello, superuser!")
+})
+```
+
+- **`AdminPermission(ctx *Ctx) bool`**: Requires the message sender to be a group admin, group owner, or superuser.
+
+```go
+// This example handles the "admin" command only if the sender has admin-level permissions.
+engine.OnMessage(zero.AdminPermission, zero.CommandRule("admin")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("Hello, admin!")
+})
+```
+
+- **`OwnerPermission(ctx *Ctx) bool`**: Requires the message sender to be the group owner or a superuser.
+
+```go
+// This example handles the "admin" command only if the sender is the group owner or a superuser.
+engine.OnMessage(zero.OwnerPermission, zero.CommandRule("admin")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("Hello, owner!")
+})
+```
+
+## Plugin Management (Example)
+
+The `example/manager` directory provides a powerful, persistent, per-group plugin management system. This is an optional feature, but it is very useful for complex bots that need to enable or disable certain sets of features for different groups.
+
+### Core Concepts
+
+- **`manager.New(service string, o *Options) *Manager`**: Creates a new plugin manager for a specific "service" (which is just a name for a collection of features).
+- **`Manager.Handler() zero.Rule`**: The core of the manager. It returns a `Rule` that you can use with `engine.UsePreHandler` to enable or disable a set of matchers for a specific group.
+- **`Manager.Enable(groupID int64)`** and **`Manager.Disable(groupID int64)`**: These methods control whether the service is active for a given group. The state is persisted in a key-value store.
+- **`Options.DisableOnDefault`**: If `true`, a service is disabled by default for a group until explicitly enabled. If `false` (the default), it's enabled by default.
+
+### Usage
+
+1. **Create a Manager for Your Feature**
+
+ In a plugin file, create a new `Manager` for a set of related features.
+
+ ```go
+ package my_plugin
+
+ import (
+ zero "github.com/wdvxdr1123/ZeroBot"
+ "github.com/wdvxdr1123/ZeroBot/example/manager"
+ )
+
+ var service = manager.New("my_awesome_feature", nil)
+
+ func init() {
+ // Use service.Handler() as a pre-handler
+ engine := zero.New().UsePreHandler(service.Handler())
+
+ engine.OnCommand("my_feature").Handle(func(ctx *zero.Ctx) {
+ ctx.Send("My awesome feature is running!")
+ })
+ }
+ ```
+
+2. **Manage Services via Chat Commands**
+
+ The `manager` example also includes built-in chat commands to allow group admins to enable/disable services.
+
+ - `/enable `: Enables the specified service for the current group.
+ - `/disable `: Disables the specified service for the current group.
+ - `/service_list`: Lists all available services.
+
+ For example, an admin can send `/enable my_awesome_feature` in a group chat to turn on your feature for that group.
+
+## Future Event Listening
+
+ZeroBot allows you to create temporary, one-off event listeners to handle "future" events. This is very useful for building conversational flows or stateful interactions that need to wait for specific user input.
+
+- **`zero.NewFutureEvent(eventName string, priority int, block bool, rules ...Rule) (<-chan *zero.Ctx, func())`**
+
+ Creates a future event listener.
+
+ - `eventName`: The name of the event to listen for (e.g., `"message"`).
+ - `priority`: The priority of the listener.
+ - `block`: Whether to block other handlers.
+ - `rules`: A set of `Rule` functions to filter events.
+
+ **Returns:**
+
+ - `<-chan *zero.Ctx`: A channel that will receive the event context when a matching event occurs.
+ - `func()`: A cancel function to stop listening when no longer needed.
+
+- **`ctx.FutureEvent(eventName string, rules ...Rule) (<-chan *zero.Ctx, func())`**
+
+ This is a helper method on the `Ctx` object that is a simplified version of `NewFutureEvent`. It uses a default priority and blocking behavior, and it automatically includes a `ctx.CheckSession()` rule to ensure it only listens for events from the same session (the same user in the same group or private chat).
+
+### Example: Repeater Mode
+
+The example in `example/repeat/test.go` demonstrates how to use future events to implement a "repeater" mode that repeats everything a user says until they say "stop repeating".
+
+```go
+package repeat
+
+import (
+ zero "github.com/wdvxdr1123/ZeroBot"
+)
+
+func init() {
+ engine := zero.New()
+ engine.OnCommand("start repeating", zero.OnlyToMe).SetBlock(true).SetPriority(10).
+ Handle(func(ctx *zero.Ctx) {
+ // 1. Create a listener for the "stop repeating" command
+ stop, cancelStop := zero.NewFutureEvent("message", 8, true,
+ zero.CommandRule("stop repeating"), // The stop command
+ ctx.CheckSession()). // Only the person who started it can stop it
+ Repeat() // Keep listening until it succeeds
+ defer cancelStop() // Make sure to cancel the listener on exit
+
+ // 2. Create a listener to repeat the user's messages
+ echo, cancel := ctx.FutureEvent("message",
+ ctx.CheckSession()). // Only repeat messages from the current session
+ Repeat() // Keep listening
+ defer cancel() // Make sure to cancel the listener on exit
+
+ ctx.Send("Repeater mode enabled!")
+
+ // 3. Use a select to wait for either event
+ for {
+ select {
+ case c := <-echo: // Received a message to repeat
+ ctx.Send(c.Event.RawMessage)
+ case <-stop: // Received the stop command
+ ctx.Send("Repeater mode disabled!")
+ return // Exit the handler
+ }
+ }
+ })
+}
+```
+
+## Event Types
+
+All events in ZeroBot are based on the OneBot v11 standard. The core `Event` struct contains a `PostType` field that determines the nature of the event.
+
+### 1. Message Events (`post_type: "message"`)
+
+These are the most common event types, used for handling messages from users or groups. Use `engine.OnMessage(...)` or more specific helpers like `engine.OnCommand(...)` to handle them.
+
+- **`message_type`**: Indicates the source of the message.
+ - `"private"`: A private message from a user.
+ - `"group"`: A message from a group.
+
+**Usage:**
+
+```go
+// Respond to any private message
+engine.OnMessage(zero.OnlyPrivate).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("I received your private message: " + ctx.Event.RawMessage)
+})
+
+// Respond to a command in a group
+engine.OnCommand("hello").Handle(func(ctx *zero.Ctx) {
+ ctx.Send("Hello to you too, " + ctx.Event.Sender.Nickname)
+})
+```
+
+### 2. Notice Events (`post_type: "notice"`)
+
+Notices are for system-level events that don't require a direct reply. Use `engine.OnNotice(...)` to handle them.
+
+- **`notice_type`**: Indicates the type of notice. Common types include:
+ - `"group_increase"`: A user joined a group.
+ - `"group_decrease"`: A user left or was kicked from a group.
+ - `"group_upload"`: Someone uploaded a file to the group.
+ - `"friend_add"`: You have a new friend.
+
+**Usage:**
+
+```go
+// Welcome a new group member
+engine.OnNotice(zero.NoticeType("group_increase")).Handle(func(ctx *zero.Ctx) {
+ ctx.SendGroupMessage(
+ ctx.Event.GroupID,
+ "Welcome to the group, user " + strconv.FormatInt(ctx.Event.UserID, 10) + "!",
+ )
+})
+```
+
+### 3. Request Events (`post_type: "request"`)
+
+Requests require a response from the bot (approval or rejection). Use `engine.OnRequest(...)` to handle them.
+
+- **`request_type`**: Indicates the type of request.
+ - `"friend"`: A user wants to add the bot as a friend.
+ - `"group"`: A user wants to join a group the bot is in (or the bot has been invited to a group).
+
+**Usage:**
+
+```go
+// Automatically approve all friend requests
+engine.OnRequest(zero.RequestType("friend")).Handle(func(ctx *zero.Ctx) {
+ ctx.SetFriendAddRequest(ctx.Event.Flag, true, "") // true to approve
+})
+
+// Automatically approve all group join requests
+engine.OnRequest(zero.RequestType("group"), zero.SubType("add")).Handle(func(ctx *zero.Ctx) {
+ ctx.SetGroupAddRequest(ctx.Event.Flag, ctx.Event.SubType, true, "") // true to approve
+})
+```
+
+### 4. Meta Events (`post_type: "meta_event"`)
+
+These events are about the bot itself or the connection to the OneBot server. Use `engine.OnMetaEvent(...)` to handle them.
+
+- **`meta_event_type`**:
+ - `"lifecycle"`: The OneBot implementation is starting or stopping.
+ - `"heartbeat"`: A heartbeat event to keep the connection alive.
+
+**Usage:**
+
+```go
+// Log when the bot connects
+engine.OnMetaEvent(zero.MetaEventType("lifecycle"), zero.SubType("connect")).Handle(func(ctx *zero.Ctx) {
+ logrus.Infoln("Bot connected!")
+})
+```
+
+[Next: Creating Plugins](/en/plugins.md)
\ No newline at end of file
diff --git a/docs/en/guide.md b/docs/en/guide.md
new file mode 100644
index 00000000..c872ce72
--- /dev/null
+++ b/docs/en/guide.md
@@ -0,0 +1,88 @@
+[Previous: Introduction](/en/README.md)
+
+[Next: Core API](/en/api.md)
+
+# Getting Started
+
+This guide will walk you through the process of setting up and running your first ZeroBot instance.
+
+## Prerequisites
+
+Before you begin, ensure you have [Go](https://golang.org/dl/) (version 1.18 or later) installed on your system.
+
+## Installation
+
+To install ZeroBot, you can use the `go get` command:
+
+```bash
+go get github.com/wdvxdr1123/ZeroBot
+```
+
+This will download and install the ZeroBot library into your Go workspace.
+
+## Configuration
+
+ZeroBot is configured by passing a `zero.Config` struct to the `zero.Run` or `zero.RunAndBlock` function. Here is an example of how to configure your bot in your `main.go` file:
+
+```go
+zero.RunAndBlock(&zero.Config{
+ NickName: []string{"bot"},
+ CommandPrefix: "/",
+ SuperUsers: []int64{123456},
+ Driver: []zero.Driver{
+ // Forward WS
+ driver.NewWebSocketClient("ws://127.0.0.1:6700", ""),
+ // Reverse WS
+ driver.NewWebSocketServer(16, "ws://127.0.0.1:6701", ""),
+ // HTTP
+ driver.NewHTTPClient("http://127.0.0.1:6701", "", "http://127.0.0.1:6700", ""),
+ },
+}, nil)
+```
+
+## Running the bot
+
+Once you have configured your bot, you can create a `main.go` file to run it:
+
+```go
+package main
+
+import (
+ zero "github.com/wdvxdr1123/ZeroBot"
+ "github.com/wdvxdr1123/ZeroBot/driver"
+)
+
+func main() {
+ zero.OnCommand("hello").
+ Handle(func(ctx *zero.Ctx) {
+ ctx.Send("world")
+ })
+
+ zero.RunAndBlock(&zero.Config{
+ NickName: []string{"bot"},
+ CommandPrefix: "/",
+ SuperUsers: []int64{123456},
+ Driver: []zero.Driver{
+ // Forward WS
+ driver.NewWebSocketClient("ws://127.0.0.1:6700", ""),
+ // Reverse WS
+ driver.NewWebSocketServer(16, "ws://127.0.0.1:6701", ""),
+ // HTTP
+ driver.NewHTTPClient("http://127.0.0.1:6701", "", "http://127.0.0.1:6700", ""),
+ },
+ }, nil)
+}
+```
+
+Then, you can run your bot using the following command:
+
+```bash
+go run main.go
+```
+
+## What's Next?
+
+Now that you have your bot up and running, you can start exploring its features:
+
+* **Create your own plugins:** Extend your bot's functionality by creating custom plugins. See the [Creating Plugins](plugins.md) guide for more information.
+* **Explore the Core API:** Learn more about the core functionalities of ZeroBot in the [Core API](api.md) documentation.
\ No newline at end of file
diff --git a/docs/en/plugins.md b/docs/en/plugins.md
new file mode 100644
index 00000000..f487a259
--- /dev/null
+++ b/docs/en/plugins.md
@@ -0,0 +1,89 @@
+[Previous: Core API](/en/api.md)
+
+# Creating Plugins
+
+ZeroBot's functionality can be extended through plugins. This guide will show you how to create your first plugin.
+
+## Hello World Plugin
+
+Here is an example of a simple plugin that responds to "hello" with "world".
+
+Create a new file `hello.go` in your plugins directory:
+
+```go
+package main
+
+import (
+ zero "github.com/wdvxdr1123/ZeroBot"
+ "github.com/wdvxdr1123/ZeroBot/message"
+)
+
+func init() {
+ zero.OnMessage(zero.FullMatch("hello")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("world")
+ })
+}
+```
+
+Then, in your main.go, import the plugin:
+
+```go
+package main
+
+import (
+ _ "your/plugin/path" // Import your plugins here
+ "github.com/wdvxdr1123/ZeroBot"
+ "github.com/wdvxdr1123/ZeroBot/driver"
+)
+
+func main() {
+ zero.RunAndBlock(&zero.Config{
+ NickName: []string{"bot"},
+ CommandPrefix: "/",
+ SuperUsers: []int64{123456},
+ Driver: []zero.Driver{
+ // Forward WS
+ driver.NewWebSocketClient("ws://127.0.0.1:6700", ""),
+ },
+ }, nil)
+}
+```
+
+## Plugin Structure
+
+A typical ZeroBot plugin has the following structure:
+
+- A `go.mod` file to manage the plugin's dependencies.
+- One or more `.go` files containing the plugin's logic.
+- An `init()` function to register the plugin.
+
+## Registering a Plugin
+
+Plugins are registered by creating a new engine instance with `zero.New()` in the `init()` function, and then using `engine.OnMessage()` or other event listeners to register event handlers.
+
+## Event Handling
+
+An event handler is a function that takes a `*zero.Ctx` as a parameter. The `Ctx` object contains the context of the event, such as the message content, sender information, etc. You can use the `ctx.Send()` method to send messages.
+
+## Matchers and Rules
+
+ZeroBot uses matchers and rules to determine which handler should process an event. A `Rule` is a function that returns a boolean value, and a `Matcher` is used to chain rules and attach a handler.
+
+Here's an example of a more advanced plugin that uses a rule to respond to a specific command:
+
+```go
+package main
+
+import (
+ zero "github.com/wdvxdr1123/ZeroBot"
+ "github.com/wdvxdr1123/ZeroBot/message"
+)
+
+func init() {
+ zero.OnCommand("echo").Handle(func(ctx *zero.Ctx) {
+ ctx.Send(ctx.Event.Message.String())
+ })
+}
+```
+
+This plugin will only respond to messages that start with `/echo`.
\ No newline at end of file
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 00000000..3a8896f8
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,30 @@
+
+
+
+
+ ZeroBot Documentation
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/zh-cn/README.md b/docs/zh-cn/README.md
new file mode 100644
index 00000000..0411b0b1
--- /dev/null
+++ b/docs/zh-cn/README.md
@@ -0,0 +1,5 @@
+# ZeroBot
+
+> 一个强大且可扩展的 QQ 机器人框架。
+
+[下一步: 快速开始](/zh-cn/guide.md)
\ No newline at end of file
diff --git a/docs/zh-cn/_sidebar.md b/docs/zh-cn/_sidebar.md
new file mode 100644
index 00000000..e054cfee
--- /dev/null
+++ b/docs/zh-cn/_sidebar.md
@@ -0,0 +1,3 @@
+* [快速入门](zh-cn/guide.md)
+* [创建插件](zh-cn/plugins.md)
+* [核心 API](zh-cn/api.md)
\ No newline at end of file
diff --git a/docs/zh-cn/api.md b/docs/zh-cn/api.md
new file mode 100644
index 00000000..ca2da2d0
--- /dev/null
+++ b/docs/zh-cn/api.md
@@ -0,0 +1,761 @@
+[上一步: 快速开始](/zh-cn/guide.md)
+
+# 核心 API
+
+本节概述了 ZeroBot 提供的核心 API。
+
+## `zero` 包
+
+`zero` 包是 ZeroBot 的核心。它提供了创建和运行机器人的主要功能。
+
+### `zero.New() *zero.Engine`
+
+此函数创建一个新的机器人引擎。
+
+```go
+engine := zero.New()
+```
+
+### `engine.OnMessage(...Rule) *Matcher`
+
+此方法为消息事件注册一个处理程序。它返回一个 `Matcher` 实例,可用于进一步配置处理程序。
+
+`Rule` 是一个函数,它接收一个 `*zero.Ctx` 类型的参数并返回一个布尔值。如果 `Rule` 返回 `true`,则处理程序将处理该事件。
+
+```go
+// 仅当消息为 “hello” 时,此处理程序才会被触发
+engine.OnMessage(func(ctx *zero.Ctx) bool {
+ return ctx.Event.Message.String() == "hello"
+}).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("world")
+})
+```
+
+### `matcher.Handle(func(ctx *zero.Ctx))`
+
+此方法设置匹配器的处理函数。每当收到与匹配器规则匹配的消息事件时,都会调用该处理程序。
+
+### `ctx.Send(message ...message.MessageSegment)`
+
+此方法将消息发送到接收事件的同一上下文中。
+
+`message.MessageSegment` 是一个消息段,它可以是文本、图片、表情等。
+
+```go
+ctx.Send("hello", message.Image("https://example.com/image.png"))
+```
+
+## `Ctx` 对象
+
+`Ctx` 对象是事件处理程序的上下文。它包含了有关事件的所有信息,例如:
+
+- `Ctx.Event`: 事件的原始数据。
+- `Ctx.Event.Message`: 消息内容。
+- `Ctx.Event.UserID`: 发送者的 QQ 号。
+- `Ctx.Event.GroupID`: 群号(如果是群消息)。
+
+您可以使用 `Ctx` 对象来获取有关事件的更多信息,并与用户进行交互。
+
+## `message` 包
+
+`message` 包提供了用于处理消息段的类型和函数。
+
+`MessageSegment` 代表消息的单个部分。一个完整的消息,由 `Message` 类型表示,是这些段的数组 (`[]Segment`)。这使您可以创建组合不同类型内容的富文本消息。
+
+每个 `Segment` 有两个字段:
+
+* **`Type` (string):** 表示段中的内容类型。常见类型包括:
+ * `text`: 纯文本。
+ * `image`: 图片。
+ * `face`: QQ 表情。
+ * `at`: @ 用户。
+ * `file`: 文件。
+
+* **`Data` (map[string]string):** 包含段数据的 map。此 map 中的键和值取决于段的 `Type`。
+
+`message` 包提供了辅助函数来轻松创建这些段,例如:
+
+### `message.Text(text ...interface{})`
+
+创建一个纯文本消息段。
+
+- `text`: 要发送的文本内容。可以传递多个参数,它们会被转换成字符串并连接起来。
+
+**示例:**
+```go
+ctx.Send(message.Text("Hello, ", "World!")) // 发送 "Hello, World!"
+```
+
+### `message.Face(id int)`
+
+创建一个 QQ 表情消息段。
+
+- `id`: QQ 表情的 ID。
+
+**示例:**
+```go
+ctx.Send(message.Face(123)) // 发送 ID 为 123 的 QQ 表情
+```
+
+### `message.File(file, name string)`
+
+创建一个文件消息段。
+
+- `file`: 文件的 URL、本地路径或 Base64 编码的数据。
+- `name`: 文件的名称。
+
+**示例:**
+```go
+ctx.Send(message.File("file:///C:/example.txt", "example.txt"))
+```
+
+### `message.Image(file string, summary ...interface{})`
+
+创建一个图片消息段。
+
+- `file`: 图片的 URL、本地路径或 Base64 编码的数据。
+- `summary` (可选): 图片的预览文字(LLOneBot 扩展)。
+
+**示例:**
+```go
+ctx.Send(message.Image("https://example.com/image.png"))
+```
+
+### `message.ImageBytes(data []byte)`
+
+通过字节数据创建一个图片消息段。
+
+- `data`: 图片的字节数据。
+
+**示例:**
+```go
+imageData, _ := ioutil.ReadFile("image.jpg")
+ctx.Send(message.ImageBytes(imageData))
+```
+
+### `message.Record(file string)`
+
+创建一个语音消息段。
+
+- `file`: 语音的 URL、本地路径或 Base64 编码的数据。
+
+**示例:**
+```go
+ctx.Send(message.Record("https://example.com/audio.mp3"))
+```
+
+### `message.Video(file string)`
+
+创建一个短视频消息段。
+
+- `file`: 视频的 URL、本地路径或 Base64 编码的数据。
+
+**示例:**
+```go
+ctx.Send(message.Video("https://example.com/video.mp4"))
+```
+
+### `message.At(qq int64)`
+
+创建一个 @ 消息段。
+
+- `qq`: 要 @ 的人的 QQ 号。如果为 `0`,则会创建一个 @全体成员 的消息段。
+
+**示例:**
+```go
+ctx.Send(message.At(123456789)) // @ QQ号为 123456789 的用户
+```
+
+### `message.AtAll()`
+
+创建一个 @全体成员 消息段。
+
+**示例:**
+```go
+ctx.Send(message.AtAll()) // @全体成员
+```
+
+### `message.Music(mType string, id int64)`
+
+创建一个音乐分享消息段。
+
+- `mType`: 音乐平台类型,如 `qq`, `163`。
+- `id`: 音乐的 ID。
+
+**示例:**
+```go
+ctx.Send(message.Music("163", 123456)) // 分享网易云音乐中 ID 为 123456 的歌曲
+```
+
+### `message.CustomMusic(url, audio, title string)`
+
+创建一个自定义音乐分享消息段。
+
+- `url`: 点击分享后跳转的 URL。
+- `audio`: 音乐的 URL。
+- `title`: 音乐的标题。
+
+**示例:**
+```go
+ctx.Send(message.CustomMusic("https://example.com", "https://example.com/audio.mp3", "My Song"))
+```
+
+### `message.Reply(id interface{})`
+
+创建一个回复消息段。
+
+- `id`: 要回复的消息的 ID。
+
+**示例:**
+```go
+// 回复当前收到的消息
+ctx.Send(message.Reply(ctx.Event.MessageID), message.Text("收到!"))
+```
+
+### `message.Forward(id string)`
+
+创建一个合并转发消息段。
+
+- `id`: 合并转发的 ID (通常由 `ctx.UploadGroupForwardMessage` 返回)。
+
+**示例:**
+```go
+// (需要先上传合并转发消息)
+forwardID := "..." // 从上传API获取
+ctx.Send(message.Forward(forwardID))
+```
+
+### `message.Node(id int64)`
+
+创建一个合并转发节点。
+
+- `id`: 消息的 ID。
+
+**示例:**
+```go
+// 通常与 CustomNode 结合使用来构建自定义合并转发消息
+```
+
+### `message.CustomNode(nickname string, userID int64, content interface{})`
+
+创建一个自定义合并转发节点。
+
+- `nickname`: 发送者的昵称。
+- `userID`: 发送者的 QQ 号。
+- `content`: 消息内容,可以是 `string`, `message.Message` 或 `[]message.Segment`。
+
+**示例:**
+```go
+node1 := message.CustomNode("User1", 10001, "Hello")
+node2 := message.CustomNode("User2", 10002, message.Message{message.Image("https://example.com/img.png")})
+forwardMsg, _ := ctx.UploadGroupForwardMessage([]message.Segment{node1, node2})
+ctx.Send(forwardMsg)
+```
+
+### `message.XML(data string)`
+
+创建一个 XML 消息段。
+
+- `data`: XML 数据。
+
+**示例:**
+```go
+xmlData := "content"
+ctx.Send(message.XML(xmlData))
+```
+
+### `message.JSON(data string)`
+
+创建一个 JSON 消息段。
+
+- `data`: JSON 数据。
+
+**示例:**
+```go
+jsonData := `{"key":"value"}`
+ctx.Send(message.JSON(jsonData))
+```
+
+### `message.Gift(userID string, giftID string)`
+
+创建一个群礼物消息段 (已弃用)。
+
+- `userID`: 接收礼物的用户的 QQ 号。
+- `giftID`: 礼物的 ID。
+
+### `message.Poke(userID int64)`
+
+创建一个戳一戳消息段。
+
+- `userID`: 要戳的用户的 QQ 号。
+
+**示例:**
+```go
+// 在群里戳某人
+ctx.SendGroupMessage(ctx.Event.GroupID, message.Poke(123456789))
+```
+
+### `message.TTS(text string)`
+
+创建一个文本转语音消息段。
+
+- `text`: 要转换成语音的文本。
+
+**示例:**
+```go
+ctx.Send(message.TTS("你好,世界"))
+```
+
+创建一个新的文本消息段。
+
+```go
+engine.OnMessage(zero.FullMatchRule("文本示例")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send(message.Text("这是一条文本消息。"))
+})
+```
+
+### `message.Image(string) MessageSegment`
+
+从 URL 创建一个新的图片消息段。
+
+```go
+engine.OnMessage(zero.FullMatchRule("图片示例")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send(message.Image("https://www.dmoe.cc/random.php"))
+})
+```
+
+### `message.At(int64) MessageSegment`
+
+创建一个新的 @ 消息段。
+
+```go
+engine.OnMessage(zero.FullMatchRule("at示例")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send(message.At(ctx.Event.UserID), message.Text("\n不要\n@我"))
+})
+```
+
+## Engine 的链式调用
+
+ZeroBot 的 `engine` 提供了一系列以 `On` 开头的方法,用于注册不同类型事件的处理器。这些方法的设计允许你将多个条件和最终的执行逻辑串联起来,形成清晰、可读的代码。
+
+一个典型的链式调用结构如下:
+
+```go
+engine.OnMessage(Rule1, Rule2, ...).Handle(func(ctx *zero.Ctx) {
+ // 你的逻辑代码
+})
+```
+
+- **`engine.OnMessage(...Rule)`**: 这是链的起点,表示你想要处理一个消息事件。你可以传入一个或多个 `Rule` 函数作为参数。只有当**所有**的 `Rule` 函数都返回 `true` 时,事件才会被进一步处理。
+- **`engine.OnCommand(...string)`**: 这是一个便捷的方法,专门用于处理命令。它等价于 `engine.OnMessage(OnlyToMe, CommandRule(...))`。
+- **`.Handle(func(*zero.Ctx))`**: 这是链的终点,用于定义最终要执行的逻辑。只有在所有前面的 `Rule` 都匹配成功后,`.Handle()` 中的函数才会被调用。
+
+除了 `OnMessage` 和 `OnCommand`,还有 `OnNotice` (处理通知事件)、`OnRequest` (处理请求事件) 等,它们都遵循类似的链式调用模式。
+
+- **`engine.OnNotice(...Rule)`**: 用于处理通知事件。通知事件涵盖了多种情况,例如群成员变动、群文件上传等。你可以使用 `zero.Type()` 规则来精确匹配不同类型的通知。
+
+```go
+// 示例:处理群成员增加的通知
+// 当有新成员加入群聊时,发送欢迎消息。
+engine.OnNotice(zero.Type("notice/group_increase")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("欢迎新成员!")
+})
+
+// 示例:处理群文件上传的通知
+// 当有成员上传文件时,进行提示。
+engine.OnNotice(zero.Type("notice/group_upload")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("有新文件上传,请注意查收。")
+})
+```
+
+- **`engine.OnRequest(...Rule)`**: 用于处理请求事件,主要包括加好友请求和加群请求。
+
+```go
+// 示例:自动同意好友请求
+// 使用 zero.Type() 匹配好友请求,并调用 ctx.Approve() 同意请求。
+engine.OnRequest(zero.Type("request/friend")).Handle(func(ctx *zero.Ctx) {
+ ctx.Approve(ctx.Event.Flag, "很高兴认识你") // 第二个参数为同意后的欢迎消息
+})
+
+// 示例:自动同意加群请求
+// 使用 zero.Type() 匹配加群请求,并调用 ctx.Approve() 同意请求。
+engine.OnRequest(zero.Type("request/group")).Handle(func(ctx *zero.Ctx) {
+ ctx.Approve(ctx.Event.Flag, "") // 同意加群请求,无需额外消息
+})
+```
+
+## 内置的 `Rule` 函数
+
+ZeroBot 在 `rules.go` 文件中提供了许多内置的 `Rule` 函数,让你可以方便地过滤和匹配事件。
+
+### 事件类型匹配
+
+- **`Type(typeString string)`**: 根据事件的类型字符串进行匹配,格式为 `"post_type/detail_type/sub_type"`。
+
+```go
+// 这个例子处理完全匹配 "hello" 的群聊消息。
+engine.OnMessage(zero.Type("message/group"), zero.FullMatchRule("hello")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("hello world")
+})
+```
+
+### 消息内容匹配
+
+- **`PrefixRule(prefixes ...string)`**: 检查消息是否以指定的前缀开头。将前缀存储在 `ctx.State["prefix"]` 中,其余部分存储在 `ctx.State["args"]` 中。
+
+```go
+// 这个例子响应以 "你好" 开头的消息。
+// 如果消息是 "你好 世界",ctx.State["prefix"] 将是 "你好",ctx.State["args"] 将是 "世界"。
+engine.OnMessage(zero.PrefixRule("你好")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("世界")
+})
+```
+
+- **`SuffixRule(suffixes ...string)`**: 检查消息是否以指定的后缀结尾。
+
+```go
+// 这个例子响应以 "世界" 结尾的消息。
+engine.OnMessage(zero.SuffixRule("世界")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("你好")
+})
+```
+
+- **`CommandRule(commands ...string)`**: 检查消息是否是命令,以配置的 `CommandPrefix` 开头。将命令和参数存储在 `ctx.State` 中。
+
+```go
+// 假设 CommandPrefix 是 "/",这个例子响应 "/ping"。
+// ctx.State["command"] 将是 "ping"。
+engine.OnMessage(zero.CommandRule("ping")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("pong")
+})
+```
+
+- **`RegexRule(regexPattern string)`**: 使用正则表达式匹配消息内容。将匹配结果存储在 `ctx.State["regex_matched"]` 中。
+
+```go
+// 这个例子响应类似于 "你好, 世界" 的消息。
+// ctx.State["regex_matched"] 将是一个字符串切片:["你好, 世界", "世界"]。
+engine.OnMessage(zero.RegexRule(`^你好, (.*)$`)).Handle(func(ctx *zero.Ctx) {
+ matched := ctx.State["regex_matched"].([]string)
+ ctx.Send("你好, " + matched[1])
+})
+```
+
+- **`KeywordRule(keywords ...string)`**: 检查消息是否包含指定的任何关键字。
+
+```go
+// 这个例子响应包含 "猫" 或 "狗" 的消息。
+engine.OnMessage(zero.KeywordRule("猫", "狗")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("我喜欢宠物!")
+})
+```
+
+- **`FullMatchRule(texts ...string)`**: 要求消息内容与指定的文本之一完全匹配。
+
+```go
+// 这个例子只响应消息 "嗨"。
+engine.OnMessage(zero.FullMatchRule("嗨")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("你好")
+})
+```
+
+- **`HasPicture(ctx *Ctx) bool`**: 检查消息是否包含任何图片。将图片 URL 存储在 `ctx.State["image_url"]` 中。
+
+```go
+// 这个例子在消息包含图片时响应。
+// ctx.State["image_url"] 将是一个包含图片 URL 的字符串切片。
+engine.OnMessage(zero.HasPicture).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("我看到你发了一张图片!")
+})
+```
+
+### 消息上下文匹配
+
+- **`OnlyToMe(ctx *Ctx) bool`**: 要求消息是发给 Bot 的(例如,通过 at Bot)。
+
+```go
+// 这个例子在机器人被 @ 并收到消息 "在吗" 时响应。
+engine.OnMessage(zero.OnlyToMe, zero.FullMatchRule("在吗")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("我在")
+})
+```
+
+- **`OnlyPrivate(ctx *Ctx) bool`**: 要求消息是私聊消息。
+
+```go
+// 这个例子响应私聊消息 "你好"。
+engine.OnMessage(zero.OnlyPrivate, zero.FullMatchRule("你好")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("你好,很高兴认识你!")
+})
+```
+
+- **`OnlyGroup(ctx *Ctx) bool`**: 要求消息是群聊消息。
+
+```go
+// 这个例子响应群聊消息 "大家好"。
+engine.OnMessage(zero.OnlyGroup, zero.FullMatchRule("大家好")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("大家好!")
+})
+```
+
+- **`ReplyRule(messageID int64)`**: 检查消息是否是对特定消息 ID 的回复。
+
+```go
+// 这个例子监听一个命令,然后等待对机器人响应的回复。
+var msgID int64
+engine.OnMessage(zero.CommandRule("你好")).Handle(func(ctx *zero.Ctx) {
+ msgID = ctx.Send("世界")
+})
+
+engine.OnMessage(zero.ReplyRule(msgID)).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("你回复了我!")
+})
+```
+
+### 用户和权限匹配
+
+- **`CheckUser(userIDs ...int64)`**: 检查消息是否来自指定的用户 ID 之一。
+
+```go
+// 这个例子只响应来自用户 123456789 的消息。
+engine.OnMessage(zero.CheckUser(123456789)).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("你好,指定的用户!")
+})
+```
+
+- **`CheckGroup(groupIDs ...int64)`**: 检查消息是否来自指定的群组 ID 之一。
+
+```go
+// 这个例子只响应来自群组 987654321 的消息。
+engine.OnMessage(zero.CheckGroup(987654321)).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("你好,指定的群组!")
+})
+```
+
+- **`SuperUserPermission(ctx *Ctx) bool`**: 要求消息发送者是超级用户。
+
+```go
+// 这个例子仅在发送者是超级用户时处理 "管理" 命令。
+engine.OnMessage(zero.SuperUserPermission, zero.CommandRule("管理")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("你好,超级用户!")
+})
+```
+
+- **`AdminPermission(ctx *Ctx) bool`**: 要求消息发送者是群管理员、群主或超级用户。
+
+```go
+// 这个例子仅在发送者具有管理员级别权限时处理 "管理" 命令。
+engine.OnMessage(zero.AdminPermission, zero.CommandRule("管理")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("你好,管理员!")
+})
+```
+
+- **`OwnerPermission(ctx *Ctx) bool`**: 要求消息发送者是群主或超级用户。
+
+```go
+// 这个例子仅在发送者是群主或超级用户时处理 "管理" 命令。
+engine.OnMessage(zero.OwnerPermission, zero.CommandRule("管理")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("你好,群主!")
+})
+```
+
+- **`OnShell(command string, model interface{}, rules ...Rule)`**: 解析类 shell 命令,自动提取参数和标志。
+
+ `OnShell` 提供了一种强大的方式来创建类似命令行的交互。它会根据你提供的结构体自动解析标志 (flags) 和参数。
+
+ - 定义一个结构体,其字段对应于命令的标志。必须使用 `flag` 标签来指定标志名称 (例如 `flag:"t"`)。
+ - 支持的字段类型为 `bool`, `int`, `string`, 和 `float64`。
+ - 在处理器内部,你可以从 `ctx.State["flag"]` 访问一个指向已填充结构体实例的指针。
+ - 不属于任何标志的其他参数可在 `ctx.State["args"]` 中作为字符串切片 (`[]string`) 使用。
+
+```go
+// 示例:创建一个 "ping" 命令
+
+// 1. 定义命令结构体
+// 只有带有 `flag` 标签的字段才会被注册。
+type Ping struct {
+ T bool `flag:"t"` // -t
+ Timeout int `flag:"w"` // -w
+ Host string `flag:"host"` // --host
+}
+
+// 2. 注册 shell 命令处理器
+func init() {
+ zero.OnShell("ping", Ping{}).Handle(func(ctx *zero.Ctx) {
+ // 从 ctx.State 中获取解析后的标志
+ ping := ctx.State["flag"].(*Ping) // 注意:这是一个指针类型
+
+ // 获取非标志参数
+ args := ctx.State["args"].([]string)
+
+ // 使用解析出的数据
+ logrus.Infoln("Ping Host:", ping.Host)
+ logrus.Infoln("Ping Timeout:", ping.Timeout)
+ logrus.Infoln("Ping T-Flag:", ping.T)
+ for i, v := range args {
+ logrus.Infoln("Arg", i, ":", v)
+ }
+
+ // 假设收到的消息是: /ping --host 127.0.0.1 -w 5000 -t other_arg
+ // Host 将是 "127.0.0.1"
+ // Timeout 将是 5000
+ // T 将是 true
+ // args 将是 ["other_arg"]
+ })
+}
+```
+
+## 未来事件监听
+
+ZeroBot 允许你创建临时的、一次性的事件监听器,以处理“未来”的事件。这对于构建对话流或需要等待用户特定输入的有状态交互非常有用。
+
+- **`zero.NewFutureEvent(eventName string, priority int, block bool, rules ...Rule) (<-chan *zero.Ctx, func())`**
+
+ 创建一个未来事件监听器。
+
+ - `eventName`: 要监听的事件名称 (例如, `"message"`)。
+ - `priority`: 监听器的优先级。
+ - `block`: 是否阻塞其他处理器。
+ - `rules`: 一组用于过滤事件的 `Rule` 函数。
+
+ **返回值:**
+
+ - `<-chan *zero.Ctx`: 一个当匹配事件发生时会接收到事件上下文的 channel。
+ - `func()`: 一个取消函数,用于在不再需要时停止监听。
+
+- **`ctx.FutureEvent(eventName string, rules ...Rule) (<-chan *zero.Ctx, func())`**
+
+ 这是一个 `Ctx` 对象上的辅助方法,是 `NewFutureEvent` 的简化版本。它使用默认的优先级和阻塞行为,并自动包含一个 `ctx.CheckSession()` 规则,以确保只监听来自同一会话(同一用户在同一群组或私聊中)的事件。
+
+### 示例: 复读机模式
+
+`example/repeat/test.go` 中的示例演示了如何使用未来事件来实现一个“复读机”模式,该模式会重复用户发送的所有内容,直到用户说“关闭复读”。
+
+```go
+package repeat
+
+import (
+ zero "github.com/wdvxdr1123/ZeroBot"
+)
+
+func init() {
+ engine := zero.New()
+ engine.OnCommand("开启复读", zero.OnlyToMe).SetBlock(true).SetPriority(10).
+ Handle(func(ctx *zero.Ctx) {
+ // 1. 创建一个监听器,用于监听“关闭复读”命令
+ stop, cancelStop := zero.NewFutureEvent("message", 8, true,
+ zero.CommandRule("关闭复读"), // 关闭指令
+ ctx.CheckSession()). // 只有开启者可以关闭
+ Repeat() // 持续监听,直到成功
+ defer cancelStop() // 确保在函数退出时取消监听
+
+ // 2. 创建一个监听器,用于复读用户的消息
+ echo, cancel := ctx.FutureEvent("message",
+ ctx.CheckSession()). // 只复读当前会话的消息
+ Repeat() // 持续监听
+ defer cancel() // 确保在函数退出时取消监听
+
+ ctx.Send("已开启复读模式!")
+
+ // 3. 使用 select 等待任一事件发生
+ for {
+ select {
+ case c := <-echo: // 收到需要复读的消息
+ ctx.Send(c.Event.RawMessage)
+ case <-stop: // 收到关闭指令
+ ctx.Send("已关闭复读模式!")
+ return // 退出处理器
+ }
+ }
+ })
+}
+```
+
+## 事件类型
+
+ZeroBot 中的所有事件都基于 OneBot v11 标准。核心的 `Event` 结构包含一个 `PostType` 字段,它决定了事件的性质。
+
+### 1. 消息事件 (`post_type: "message"`)
+
+这是最常见的事件类型,用于处理来自用户或群组的消息。使用 `engine.OnMessage(...)` 或更具体的辅助函数(如 `engine.OnCommand(...)`)来处理它们。
+
+- **`message_type`**: 指示消息来源。
+ - `"private"`: 来自用户的私聊消息。
+ - `"group"`: 来自群组的消息。
+
+**使用方法:**
+
+```go
+// 回应任何私聊消息
+engine.OnMessage(zero.OnlyPrivate).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("我收到了你的私聊消息: " + ctx.Event.RawMessage)
+})
+
+// 在群组中回应一个命令
+engine.OnCommand("你好").Handle(func(ctx *zero.Ctx) {
+ ctx.Send("你好, " + ctx.Event.Sender.Nickname)
+})
+```
+
+### 2. 通知事件 (`post_type: "notice"`)
+
+通知是关于不需要直接回复的系统级事件。使用 `engine.OnNotice(...)` 来处理它们。
+
+- **`notice_type`**: 指示通知的类型。常见类型包括:
+ - `"group_increase"`: 用户加入群组。
+ - `"group_decrease"`: 用户离开或被踢出群组。
+ - `"group_upload"`: 有人向群组上传了文件。
+ - `"friend_add"`: 你有了一个新好友。
+
+**使用方法:**
+
+```go
+// 欢迎新群成员
+engine.OnNotice(zero.NoticeType("group_increase")).Handle(func(ctx *zero.Ctx) {
+ ctx.SendGroupMessage(
+ ctx.Event.GroupID,
+ "欢迎新成员 " + strconv.FormatInt(ctx.Event.UserID, 10) + "!",
+ )
+})
+```
+
+### 3. 请求事件 (`post_type: "request"`)
+
+请求需要机器人做出回应(同意或拒绝)。使用 `engine.OnRequest(...)` 来处理它们。
+
+- **`request_type`**: 指示请求的类型。
+ - `"friend"`: 用户想要添加机器人为好友。
+ - `"group"`: 用户想要加入机器人所在的群组(或机器人被邀请加入群组)。
+
+**使用方法:**
+
+```go
+// 自动同意所有好友请求
+engine.OnRequest(zero.RequestType("friend")).Handle(func(ctx *zero.Ctx) {
+ ctx.SetFriendAddRequest(ctx.Event.Flag, true, "") // true 表示同意
+})
+
+// 自动同意所有加群请求
+engine.OnRequest(zero.RequestType("group"), zero.SubType("add")).Handle(func(ctx *zero.Ctx) {
+ ctx.SetGroupAddRequest(ctx.Event.Flag, ctx.Event.SubType, true, "") // true 表示同意
+})
+```
+
+### 4. 元事件 (`post_type: "meta_event"`)
+
+这些事件与机器人本身或与 OneBot 服务器的连接有关。使用 `engine.OnMetaEvent(...)` 来处理它们。
+
+- **`meta_event_type`**:
+ - `"lifecycle"`: OneBot 实现正在启动或停止。
+ - `"heartbeat"`: 用于保持连接的心跳事件。
+
+**使用方法:**
+
+```go
+// 在机器人连接时记录日志
+engine.OnMetaEvent(zero.MetaEventType("lifecycle"), zero.SubType("connect")).Handle(func(ctx *zero.Ctx) {
+ logrus.Infoln("机器人已连接!")
+})
+```
+
+[下一步: 创建插件](/zh-cn/plugins.md)
\ No newline at end of file
diff --git a/docs/zh-cn/guide.md b/docs/zh-cn/guide.md
new file mode 100644
index 00000000..6698bc88
--- /dev/null
+++ b/docs/zh-cn/guide.md
@@ -0,0 +1,88 @@
+[上一步: 介绍](/zh-cn/README.md)
+
+[下一步: 核心 API](/zh-cn/api.md)
+
+# 快速入门
+
+本指南将引导您完成设置和运行第一个 ZeroBot 实例的过程。
+
+## 环境要求
+
+在开始之前,请确保您已经安装了 [Go](https://golang.org/dl/) 语言环境 (1.18 或更高版本)。
+
+## 安装
+
+您可以使用 `go get` 命令来安装 ZeroBot:
+
+```bash
+go get github.com/wdvxdr1123/ZeroBot
+```
+
+这将下载并安装 ZeroBot 库到您的 Go 工作区。
+
+## 配置
+
+ZeroBot 是通过将 `zero.Config` 结构体传递给 `zero.Run` 或 `zero.RunAndBlock` 函数来配置的。以下是如何在 `main.go` 文件中配置您的机器人的示例:
+
+```go
+zero.RunAndBlock(&zero.Config{
+ NickName: []string{"bot"},
+ CommandPrefix: "/",
+ SuperUsers: []int64{123456},
+ Driver: []zero.Driver{
+ // 正向 WS
+ driver.NewWebSocketClient("ws://127.0.0.1:6700", ""),
+ // 反向 WS
+ driver.NewWebSocketServer(16, "ws://127.0.0.1:6701", ""),
+ // HTTP
+ driver.NewHTTPClient("http://127.0.0.1:6701", "", "http://127.0.0.1:6700", ""),
+ },
+}, nil)
+```
+
+## 运行机器人
+
+配置好机器人后,您就可以创建一个 `main.go` 文件来运行它:
+
+```go
+package main
+
+import (
+ zero "github.com/wdvxdr1123/ZeroBot"
+ "github.com/wdvxdr1123/ZeroBot/driver"
+)
+
+func main() {
+ zero.OnCommand("hello").
+ Handle(func(ctx *zero.Ctx) {
+ ctx.Send("world")
+ })
+
+ zero.RunAndBlock(&zero.Config{
+ NickName: []string{"bot"},
+ CommandPrefix: "/",
+ SuperUsers: []int64{123456},
+ Driver: []zero.Driver{
+ // 正向 WS
+ driver.NewWebSocketClient("ws://127.0.0.1:6700", ""),
+ // 反向 WS
+ driver.NewWebSocketServer(16, "ws://127.0.0.1:6701", ""),
+ // HTTP
+ driver.NewHTTPClient("http://127.0.0.1:6701", "", "http://127.0.0.1:6700", ""),
+ },
+ }, nil)
+}
+```
+
+然后,您可以使用以下命令运行您的机器人:
+
+```bash
+go run main.go
+```
+
+## 下一步
+
+现在您的机器人已经启动并运行,您可以开始探索它的功能了:
+
+* **创建您自己的插件:** 通过创建自定义插件来扩展您的机器人的功能。有关更多信息,请参阅[创建插件](/zh-cn/plugins.md)指南。
+* **探索核心 API:** 在[核心 API](/zh-cn/api.md)文档中了解有关 ZeroBot 核心功能的更多信息。
\ No newline at end of file
diff --git a/docs/zh-cn/plugins.md b/docs/zh-cn/plugins.md
new file mode 100644
index 00000000..c5decdd8
--- /dev/null
+++ b/docs/zh-cn/plugins.md
@@ -0,0 +1,88 @@
+[上一步: 核心 API](/zh-cn/api.md)
+
+# 创建插件
+
+ZeroBot 的功能可以通过插件进行扩展。本指南将向您展示如何创建您的第一个插件。
+
+## Hello World 插件
+
+这是一个简单的插件示例,它会在收到“hello”时回复“world”。
+
+在您的插件目录中创建一个名为 `hello.go` 的新文件:
+
+```go
+package main
+
+import (
+ zero "github.com/wdvxdr1123/ZeroBot"
+ "github.com/wdvxdr1123/ZeroBot/message"
+)
+
+func init() {
+ zero.OnMessage(zero.FullMatch("hello")).Handle(func(ctx *zero.Ctx) {
+ ctx.Send("world")
+ })
+}
+```
+
+然后,在您的 `main.go` 文件中,导入您的插件:
+
+```go
+package main
+
+import (
+ _ "your/plugin/path" // 导入您的插件
+ "github.com/wdvxdr1123/ZeroBot"
+)
+
+func main() {
+ zero.RunAndBlock(&zero.Config{
+ NickName: []string{"bot"},
+ CommandPrefix: "/",
+ SuperUsers: []int64{123456},
+ Driver: []zero.Driver{
+ // 正向 WS
+ driver.NewWebSocketClient("ws://127.0.0.1:6700", ""),
+ },
+ }, nil)
+}
+```
+
+## 插件结构
+
+一个典型的 ZeroBot 插件具有以下结构:
+
+- 一个 `go.mod` 文件,用于管理插件的依赖项。
+- 一个或多个 `.go` 文件,其中包含插件的逻辑。
+- 一个 `init()` 函数,用于注册插件。
+
+## 注册插件
+
+插件通过在 `init()` 函数中调用 `zero.New()` 来创建一个新的引擎实例,然后使用 `engine.OnMessage()` 或其他事件监听器来注册事件处理程序。
+
+## 事件处理
+
+事件处理程序是一个函数,它接收一个 `*zero.Ctx` 类型的参数。`Ctx` 对象包含了事件的上下文信息,例如消息内容、发送者信息等。您可以使用 `ctx.Send()` 方法来发送消息。
+
+## 匹配器和规则
+
+ZeroBot 使用匹配器和规则来确定哪个处理程序应该处理一个事件。`Rule` 是一个返回布尔值的函数,而 `Matcher` 用于链接规则并附加处理程序。
+
+下面是一个更高级的插件示例,它使用规则来响应特定的命令:
+
+```go
+package main
+
+import (
+ zero "github.com/wdvxdr1123/ZeroBot"
+ "github.com/wdvxdr1123/ZeroBot/message"
+)
+
+func init() {
+ zero.OnCommand("echo").Handle(func(ctx *zero.Ctx) {
+ ctx.Send(ctx.Event.Message.String())
+ })
+}
+```
+
+这个插件只会响应以 `/echo` 开头的消息。
\ No newline at end of file