From b307495bebc1dc301f5468486c292b3c96f8afc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Wed, 3 Dec 2025 00:29:05 +0800 Subject: [PATCH 01/12] =?UTF-8?q?=E2=9C=A8=E6=B7=BB=E5=8A=A0=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +- docs/_navbar.md | 2 + docs/en/README.md | 3 + docs/en/_sidebar.md | 4 ++ docs/en/api.md | 138 +++++++++++++++++++++++++++++++++++++++++ docs/en/guide.md | 67 ++++++++++++++++++++ docs/en/plugins.md | 79 +++++++++++++++++++++++ docs/zh-cn/README.md | 3 + docs/zh-cn/_sidebar.md | 3 + docs/zh-cn/api.md | 138 +++++++++++++++++++++++++++++++++++++++++ docs/zh-cn/guide.md | 67 ++++++++++++++++++++ docs/zh-cn/plugins.md | 86 +++++++++++++++++++++++++ 12 files changed, 595 insertions(+), 1 deletion(-) create mode 100644 docs/_navbar.md create mode 100644 docs/en/README.md create mode 100644 docs/en/_sidebar.md create mode 100644 docs/en/api.md create mode 100644 docs/en/guide.md create mode 100644 docs/en/plugins.md create mode 100644 docs/zh-cn/README.md create mode 100644 docs/zh-cn/_sidebar.md create mode 100644 docs/zh-cn/api.md create mode 100644 docs/zh-cn/guide.md create mode 100644 docs/zh-cn/plugins.md diff --git a/README.md b/README.md index 284a3405..ffad30ca 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,10 @@ func main() { } ``` +## 📖 文档 + +[**--> 点击这里查看文档 <--**](./docs/) + ## 🎯 特性 - 通过 `init` 函数实现插件式 @@ -62,4 +66,4 @@ func main() { - + \ No newline at end of file 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/en/README.md b/docs/en/README.md new file mode 100644 index 00000000..f9d21732 --- /dev/null +++ b/docs/en/README.md @@ -0,0 +1,3 @@ +# ZeroBot + +> A powerful and extensible QQ bot framework. \ 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..94144b08 --- /dev/null +++ b/docs/en/api.md @@ -0,0 +1,138 @@ +# 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(string) MessageSegment` + +Creates a new text message segment. + +### `message.Image(string) MessageSegment` + +Creates a new image message segment from a URL. + +### `message.At(int64) MessageSegment` + +Creates a new @ message segment. + +## 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. + +## 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 events based on their type string, formatted as `"post_type/detail_type/sub_type"`. + - **Example**: `Type("message/group")` matches group messages. + +### 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 in `ctx.State["args"]`. +- **`SuffixRule(suffixes ...string)`**: Checks if the message ends with a specified suffix. +- **`CommandRule(commands ...string)`**: Checks if the message is a command, starting with the configured `CommandPrefix`. Stores the command and arguments in `ctx.State`. +- **`RegexRule(regexPattern string)`**: Matches the message content with a regular expression. Stores the match results in `ctx.State["regex_matched"]`. +- **`KeywordRule(keywords ...string)`**: Checks if the message contains any of the specified keywords. +- **`FullMatchRule(texts ...string)`**: Requires the message content to be an exact match to one of the specified texts. +- **`HasPicture(ctx *Ctx) bool`**: Checks if the message contains any pictures. Stores image URLs in `ctx.State["image_url"]`. + +### Message Context Matching + +- **`OnlyToMe(ctx *Ctx) bool`**: Requires the message to be directed at the bot (e.g., via an @-mention or nickname). +- **`OnlyPrivate(ctx *Ctx) bool`**: Requires the message to be a private message. +- **`OnlyGroup(ctx *Ctx) bool`**: Requires the message to be a group message. +- **`ReplyRule(messageID int64)`**: Checks if the message is a reply to a specific message ID. + +### User and Permission Matching + +- **`CheckUser(userIDs ...int64)`**: Requires the message to be from one of the specified users. +- **`CheckGroup(groupIDs ...int64)`**: Requires the message to be from one of the specified groups. +- **`SuperUserPermission(ctx *Ctx) bool`**: Requires the sender to be a superuser. +- **`AdminPermission(ctx *Ctx) bool`**: Requires the sender to be a group admin, owner, or a superuser. +- **`OwnerPermission(ctx *Ctx) bool`**: Requires the sender to be a group owner or a superuser. \ No newline at end of file diff --git a/docs/en/guide.md b/docs/en/guide.md new file mode 100644 index 00000000..36d55e20 --- /dev/null +++ b/docs/en/guide.md @@ -0,0 +1,67 @@ +# 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 ( + _ "your/plugin/path" // Import your plugins here + "github.com/wdvxdr1123/ZeroBot" +) + +func main() { + zero.Run() +} +``` + +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..b495064c --- /dev/null +++ b/docs/en/plugins.md @@ -0,0 +1,79 @@ +# 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() { + engine := zero.New() + engine.OnMessage().Handle(func(ctx *zero.Ctx) { + if ctx.Event.Message.String() == "hello" { + ctx.Send("world") + } + }) +} +``` + +Then, in your main.go, import the plugin: + +```go +import ( + _ "your/plugin/path" +) +``` + +## 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" + "strings" +) + +func init() { + engine := zero.New() + engine.OnMessage(func(ctx *zero.Ctx) bool { + return strings.HasPrefix(ctx.Event.Message.String(), "/echo") + }).Handle(func(ctx *zero.Ctx) { + msg := strings.TrimPrefix(ctx.Event.Message.String(), "/echo ") + ctx.Send(msg) + }) +} +``` + +This plugin will only respond to messages that start with `/echo`. \ 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..bba46791 --- /dev/null +++ b/docs/zh-cn/README.md @@ -0,0 +1,3 @@ +# ZeroBot + +> 一个强大且可扩展的 QQ 机器人框架。 \ 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..88ff3a7b --- /dev/null +++ b/docs/zh-cn/api.md @@ -0,0 +1,138 @@ +# 核心 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(string) MessageSegment` + +创建一个新的文本消息段。 + +### `message.Image(string) MessageSegment` + +从 URL 创建一个新的图片消息段。 + +### `message.At(int64) MessageSegment` + +创建一个新的 @ 消息段。 + +## 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` (处理请求事件) 等,它们都遵循类似的链式调用模式。 + +## 内置的 `Rule` 函数 + +ZeroBot 在 `rules.go` 文件中提供了许多内置的 `Rule` 函数,让你可以方便地过滤和匹配事件。 + +### 事件类型匹配 + +- **`Type(typeString string)`**: 根据事件的类型字符串进行匹配,格式为 `"post_type/detail_type/sub_type"`。 + - **示例**: `Type("message/group")` 匹配群聊消息。 + +### 消息内容匹配 + +- **`PrefixRule(prefixes ...string)`**: 检查消息是否以指定的前缀开头。将前缀存储在 `ctx.State["prefix"]` 中,其余部分存储在 `ctx.State["args"]` 中。 +- **`SuffixRule(suffixes ...string)`**: 检查消息是否以指定的后缀结尾。 +- **`CommandRule(commands ...string)`**: 检查消息是否是命令,以配置的 `CommandPrefix` 开头。将命令和参数存储在 `ctx.State` 中。 +- **`RegexRule(regexPattern string)`**: 使用正则表达式匹配消息内容。将匹配结果存储在 `ctx.State["regex_matched"]` 中。 +- **`KeywordRule(keywords ...string)`**: 检查消息是否包含指定的任何关键字。 +- **`FullMatchRule(texts ...string)`**: 要求消息内容与指定的文本之一完全匹配。 +- **`HasPicture(ctx *Ctx) bool`**: 检查消息是否包含任何图片。将图片 URL 存储在 `ctx.State["image_url"]` 中。 + +### 消息上下文匹配 + +- **`OnlyToMe(ctx *Ctx) bool`**: 要求消息是发给机器人的(例如,通过 @提及或昵称)。 +- **`OnlyPrivate(ctx *Ctx) bool`**: 要求消息是私聊消息。 +- **`OnlyGroup(ctx *Ctx) bool`**: 要求消息是群聊消息。 +- **`ReplyRule(messageID int64)`**: 检查消息是否是对特定消息 ID 的回复。 + +### 用户和权限匹配 + +- **`CheckUser(userIDs ...int64)`**: 要求消息来自指定的用户之一。 +- **`CheckGroup(groupIDs ...int64)`**: 要求消息来自指定的群组之一。 +- **`SuperUserPermission(ctx *Ctx) bool`**: 要求发送者是超级用户。 +- **`AdminPermission(ctx *Ctx) bool`**: 要求发送者是群组管理员、所有者或超级用户。 +- **`OwnerPermission(ctx *Ctx) bool`**: 要求发送者是群组所有者或超级用户。 \ 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..d330aed2 --- /dev/null +++ b/docs/zh-cn/guide.md @@ -0,0 +1,67 @@ +# 快速入门 + +本指南将引导您完成设置和运行第一个 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 ( + _ "your/plugin/path" // 在这里导入您的插件 + "github.com/wdvxdr1123/ZeroBot" +) + +func main() { + zero.Run() +} +``` + +然后,您可以使用以下命令运行您的机器人: + +```bash +go run main.go +``` + +## 下一步 + +现在您的机器人已经启动并运行,您可以开始探索它的功能了: + +* **创建您自己的插件:** 通过创建自定义插件来扩展您的机器人的功能。有关更多信息,请参阅[创建插件](plugins.md)指南。 +* **探索核心 API:** 在[核心 API](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..b770ac10 --- /dev/null +++ b/docs/zh-cn/plugins.md @@ -0,0 +1,86 @@ +# 创建插件 + +ZeroBot 的功能可以通过插件进行扩展。本指南将向您展示如何创建您的第一个插件。 + +## Hello World 插件 + +这是一个简单的插件示例,它会在收到“hello”时回复“world”。 + +在您的插件目录中创建一个名为 `hello.go` 的新文件: + +```go +package main + +import ( + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/message" +) + +func init() { + engine := zero.New() + engine.OnMessage().Handle(func(ctx *zero.Ctx) { + if ctx.Event.Message.String() == "hello" { + ctx.Send("world") + } + }) +} +``` + +然后,在您的 `main.go` 文件中,导入您的插件: + +```go +package main + +import ( + _ "your/plugin/path" // 导入您的插件 + "github.com/wdvxdr1123/ZeroBot" +) + +func main() { + zero.Run() +} +``` + +## 插件结构 + +一个典型的 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" + "strings" +) + +func init() { + engine := zero.New() + engine.OnMessage(func(ctx *zero.Ctx) bool { + return strings.HasPrefix(ctx.Event.Message.String(), "/echo") + }).Handle(func(ctx *zero.Ctx) { + msg := strings.TrimPrefix(ctx.Event.Message.String(), "/echo ") + ctx.Send(msg) + }) +} +``` + +这个插件只会响应以 `/echo` 开头的消息。 \ No newline at end of file From 889e8451a704e5280fff12b61eb6928e5271fe4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Wed, 3 Dec 2025 11:06:02 +0800 Subject: [PATCH 02/12] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=E6=B7=BB=E5=8A=A0githu?= =?UTF-8?q?b=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/.nojekyll | 0 docs/_sidebar.md | 11 +++++++++++ docs/en/README.md | 4 +++- docs/en/api.md | 6 +++++- docs/en/guide.md | 2 ++ docs/en/plugins.md | 2 ++ docs/index.html | 30 ++++++++++++++++++++++++++++++ docs/zh-cn/README.md | 4 +++- docs/zh-cn/api.md | 6 +++++- docs/zh-cn/guide.md | 2 ++ docs/zh-cn/plugins.md | 2 ++ 11 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 docs/.nojekyll create mode 100644 docs/_sidebar.md create mode 100644 docs/index.html diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 00000000..e69de29b 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 index f9d21732..81b1887d 100644 --- a/docs/en/README.md +++ b/docs/en/README.md @@ -1,3 +1,5 @@ # ZeroBot -> A powerful and extensible QQ bot framework. \ No newline at end of file +> A powerful and extensible QQ bot framework. + +[Next: Quick Start](./guide.md) \ No newline at end of file diff --git a/docs/en/api.md b/docs/en/api.md index 94144b08..cc278f58 100644 --- a/docs/en/api.md +++ b/docs/en/api.md @@ -1,3 +1,5 @@ +[Previous: Quick Start](./guide.md) + # Core API This section provides an overview of the core API provided by ZeroBot. @@ -135,4 +137,6 @@ ZeroBot provides many built-in `Rule` functions in the `rules.go` file, allowing - **`CheckGroup(groupIDs ...int64)`**: Requires the message to be from one of the specified groups. - **`SuperUserPermission(ctx *Ctx) bool`**: Requires the sender to be a superuser. - **`AdminPermission(ctx *Ctx) bool`**: Requires the sender to be a group admin, owner, or a superuser. -- **`OwnerPermission(ctx *Ctx) bool`**: Requires the sender to be a group owner or a superuser. \ No newline at end of file +- **`OwnerPermission(ctx *Ctx) bool`**: Requires the sender to be a group owner or a superuser. + +[Next: Creating Plugins](./plugins.md) \ No newline at end of file diff --git a/docs/en/guide.md b/docs/en/guide.md index 36d55e20..b2eb0f7d 100644 --- a/docs/en/guide.md +++ b/docs/en/guide.md @@ -1,3 +1,5 @@ +[Previous: Introduction](./README.md) + # Getting Started This guide will walk you through the process of setting up and running your first ZeroBot instance. diff --git a/docs/en/plugins.md b/docs/en/plugins.md index b495064c..adfc2810 100644 --- a/docs/en/plugins.md +++ b/docs/en/plugins.md @@ -1,3 +1,5 @@ +[Previous: Core API](./api.md) + # Creating Plugins ZeroBot's functionality can be extended through plugins. This guide will show you how to create your first plugin. 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 index bba46791..cd484e08 100644 --- a/docs/zh-cn/README.md +++ b/docs/zh-cn/README.md @@ -1,3 +1,5 @@ # ZeroBot -> 一个强大且可扩展的 QQ 机器人框架。 \ No newline at end of file +> 一个强大且可扩展的 QQ 机器人框架。 + +[下一步: 快速开始](./guide.md) \ No newline at end of file diff --git a/docs/zh-cn/api.md b/docs/zh-cn/api.md index 88ff3a7b..db3e1cc2 100644 --- a/docs/zh-cn/api.md +++ b/docs/zh-cn/api.md @@ -1,3 +1,5 @@ +[上一步: 快速开始](./guide.md) + # 核心 API 本节概述了 ZeroBot 提供的核心 API。 @@ -135,4 +137,6 @@ ZeroBot 在 `rules.go` 文件中提供了许多内置的 `Rule` 函数,让你 - **`CheckGroup(groupIDs ...int64)`**: 要求消息来自指定的群组之一。 - **`SuperUserPermission(ctx *Ctx) bool`**: 要求发送者是超级用户。 - **`AdminPermission(ctx *Ctx) bool`**: 要求发送者是群组管理员、所有者或超级用户。 -- **`OwnerPermission(ctx *Ctx) bool`**: 要求发送者是群组所有者或超级用户。 \ No newline at end of file +- **`OwnerPermission(ctx *Ctx) bool`**: 要求发送者是群组所有者或超级用户。 + +[下一步: 创建插件](./plugins.md) \ No newline at end of file diff --git a/docs/zh-cn/guide.md b/docs/zh-cn/guide.md index d330aed2..18932378 100644 --- a/docs/zh-cn/guide.md +++ b/docs/zh-cn/guide.md @@ -1,3 +1,5 @@ +[上一步: 介绍](./README.md) + # 快速入门 本指南将引导您完成设置和运行第一个 ZeroBot 实例的过程。 diff --git a/docs/zh-cn/plugins.md b/docs/zh-cn/plugins.md index b770ac10..f2e156f6 100644 --- a/docs/zh-cn/plugins.md +++ b/docs/zh-cn/plugins.md @@ -1,3 +1,5 @@ +[上一步: 核心 API](./api.md) + # 创建插件 ZeroBot 的功能可以通过插件进行扩展。本指南将向您展示如何创建您的第一个插件。 From 8791c0efa7afaaa565b145cd9fd1e1dcda59309e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Wed, 3 Dec 2025 11:18:58 +0800 Subject: [PATCH 03/12] =?UTF-8?q?=F0=9F=90=9B=E8=B0=83=E6=95=B4=E8=B7=AF?= =?UTF-8?q?=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/README.md | 2 +- docs/en/api.md | 4 ++-- docs/en/guide.md | 4 +++- docs/en/plugins.md | 2 +- docs/zh-cn/README.md | 2 +- docs/zh-cn/api.md | 4 ++-- docs/zh-cn/guide.md | 6 +++--- docs/zh-cn/plugins.md | 2 +- 8 files changed, 14 insertions(+), 12 deletions(-) diff --git a/docs/en/README.md b/docs/en/README.md index 81b1887d..e016ca38 100644 --- a/docs/en/README.md +++ b/docs/en/README.md @@ -2,4 +2,4 @@ > A powerful and extensible QQ bot framework. -[Next: Quick Start](./guide.md) \ No newline at end of file +[Next: Quick Start](/en/guide.md) \ No newline at end of file diff --git a/docs/en/api.md b/docs/en/api.md index cc278f58..5e1f74e6 100644 --- a/docs/en/api.md +++ b/docs/en/api.md @@ -1,4 +1,4 @@ -[Previous: Quick Start](./guide.md) +[Previous: Quick Start](/en/guide.md) # Core API @@ -139,4 +139,4 @@ ZeroBot provides many built-in `Rule` functions in the `rules.go` file, allowing - **`AdminPermission(ctx *Ctx) bool`**: Requires the sender to be a group admin, owner, or a superuser. - **`OwnerPermission(ctx *Ctx) bool`**: Requires the sender to be a group owner or a superuser. -[Next: Creating Plugins](./plugins.md) \ No newline at end of file +[Next: Creating Plugins](/en/plugins.md) \ No newline at end of file diff --git a/docs/en/guide.md b/docs/en/guide.md index b2eb0f7d..8715fb5c 100644 --- a/docs/en/guide.md +++ b/docs/en/guide.md @@ -1,4 +1,6 @@ -[Previous: Introduction](./README.md) +[Previous: Introduction](/en/README.md) + +[Next: Core API](/en/api.md) # Getting Started diff --git a/docs/en/plugins.md b/docs/en/plugins.md index adfc2810..7aeaef7b 100644 --- a/docs/en/plugins.md +++ b/docs/en/plugins.md @@ -1,4 +1,4 @@ -[Previous: Core API](./api.md) +[Previous: Core API](/en/api.md) # Creating Plugins diff --git a/docs/zh-cn/README.md b/docs/zh-cn/README.md index cd484e08..0411b0b1 100644 --- a/docs/zh-cn/README.md +++ b/docs/zh-cn/README.md @@ -2,4 +2,4 @@ > 一个强大且可扩展的 QQ 机器人框架。 -[下一步: 快速开始](./guide.md) \ No newline at end of file +[下一步: 快速开始](/zh-cn/guide.md) \ No newline at end of file diff --git a/docs/zh-cn/api.md b/docs/zh-cn/api.md index db3e1cc2..e60dc813 100644 --- a/docs/zh-cn/api.md +++ b/docs/zh-cn/api.md @@ -1,4 +1,4 @@ -[上一步: 快速开始](./guide.md) +[上一步: 快速开始](/zh-cn/guide.md) # 核心 API @@ -139,4 +139,4 @@ ZeroBot 在 `rules.go` 文件中提供了许多内置的 `Rule` 函数,让你 - **`AdminPermission(ctx *Ctx) bool`**: 要求发送者是群组管理员、所有者或超级用户。 - **`OwnerPermission(ctx *Ctx) bool`**: 要求发送者是群组所有者或超级用户。 -[下一步: 创建插件](./plugins.md) \ No newline at end of file +[下一步: 创建插件](/zh-cn/plugins.md) \ No newline at end of file diff --git a/docs/zh-cn/guide.md b/docs/zh-cn/guide.md index 18932378..ca287590 100644 --- a/docs/zh-cn/guide.md +++ b/docs/zh-cn/guide.md @@ -1,4 +1,4 @@ -[上一步: 介绍](./README.md) +[上一步: 介绍](/zh-cn/README.md) # 快速入门 @@ -65,5 +65,5 @@ go run main.go 现在您的机器人已经启动并运行,您可以开始探索它的功能了: -* **创建您自己的插件:** 通过创建自定义插件来扩展您的机器人的功能。有关更多信息,请参阅[创建插件](plugins.md)指南。 -* **探索核心 API:** 在[核心 API](api.md)文档中了解有关 ZeroBot 核心功能的更多信息。 \ No newline at end of file +* **创建您自己的插件:** 通过创建自定义插件来扩展您的机器人的功能。有关更多信息,请参阅[创建插件](/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 index f2e156f6..3298d356 100644 --- a/docs/zh-cn/plugins.md +++ b/docs/zh-cn/plugins.md @@ -1,4 +1,4 @@ -[上一步: 核心 API](./api.md) +[上一步: 核心 API](/zh-cn/api.md) # 创建插件 From 4d5671a2bda90cf70a8004c5ac462abf474f9950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Wed, 3 Dec 2025 11:21:55 +0800 Subject: [PATCH 04/12] =?UTF-8?q?=F0=9F=93=9D=E6=9B=BF=E4=BB=A3run?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/guide.md | 10 +++++++++- docs/zh-cn/guide.md | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/en/guide.md b/docs/en/guide.md index 8715fb5c..82e562bd 100644 --- a/docs/en/guide.md +++ b/docs/en/guide.md @@ -53,7 +53,15 @@ import ( ) func main() { - zero.Run() + 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) } ``` diff --git a/docs/zh-cn/guide.md b/docs/zh-cn/guide.md index ca287590..dee5dbd3 100644 --- a/docs/zh-cn/guide.md +++ b/docs/zh-cn/guide.md @@ -51,7 +51,15 @@ import ( ) func main() { - zero.Run() + zero.RunAndBlock(&zero.Config{ + NickName: []string{"bot"}, + CommandPrefix: "/", + SuperUsers: []int64{123456}, + Driver: []zero.Driver{ + // 正向 WS + driver.NewWebSocketClient("ws://127.0.0.1:6700", ""), + }, + }, nil) } ``` From 44a1a264cd30fda4cb4d9a3591ccef9c8d8c3a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Wed, 3 Dec 2025 11:27:01 +0800 Subject: [PATCH 05/12] =?UTF-8?q?=F0=9F=93=9D=E6=B7=BB=E5=8A=A0=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E6=8C=87=E5=90=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- docs/en/plugins.md | 18 +++++++++++++++++- docs/zh-cn/plugins.md | 10 +++++++++- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ffad30ca..044a9c60 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![License](https://img.shields.io/github/license/wdvxdr1123/ZeroBot.svg?style=flat-square&logo=gnu)](https://raw.githubusercontent.com/wdvxdr1123/ZeroBot/main/LICENSE) [![qq group](https://img.shields.io/badge/group-892659456-red?style=flat-square&logo=tencent-qq)](https://jq.qq.com/?_wv=1027&k=E6Zov6Fi) -文档正在咕咕中, 具体使用可以参考example文件夹。 + ## ⚡️ 快速使用 @@ -43,7 +43,7 @@ func main() { ## 📖 文档 -[**--> 点击这里查看文档 <--**](./docs/) +[**--> 点击这里查看文档 <--**](https://guohuiyuan.github.io/ZeroBot/) ## 🎯 特性 diff --git a/docs/en/plugins.md b/docs/en/plugins.md index 7aeaef7b..50695167 100644 --- a/docs/en/plugins.md +++ b/docs/en/plugins.md @@ -31,9 +31,25 @@ func init() { Then, in your main.go, import the plugin: ```go +package main + import ( - _ "your/plugin/path" + _ "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 diff --git a/docs/zh-cn/plugins.md b/docs/zh-cn/plugins.md index 3298d356..8f10e395 100644 --- a/docs/zh-cn/plugins.md +++ b/docs/zh-cn/plugins.md @@ -39,7 +39,15 @@ import ( ) func main() { - zero.Run() + zero.RunAndBlock(&zero.Config{ + NickName: []string{"bot"}, + CommandPrefix: "/", + SuperUsers: []int64{123456}, + Driver: []zero.Driver{ + // 正向 WS + driver.NewWebSocketClient("ws://127.0.0.1:6700", ""), + }, + }, nil) } ``` From 6a59642f5721b5603b43ce9f0eb42446462ca430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Wed, 3 Dec 2025 11:27:01 +0800 Subject: [PATCH 06/12] =?UTF-8?q?=E2=9C=A8=E5=AE=8C=E5=96=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- docs/en/api.md | 152 ++++++++++++++++++++++++++++++++++++++++-- docs/en/plugins.md | 18 ++++- docs/zh-cn/api.md | 148 ++++++++++++++++++++++++++++++++++++++-- docs/zh-cn/plugins.md | 10 ++- 5 files changed, 315 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index ffad30ca..044a9c60 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![License](https://img.shields.io/github/license/wdvxdr1123/ZeroBot.svg?style=flat-square&logo=gnu)](https://raw.githubusercontent.com/wdvxdr1123/ZeroBot/main/LICENSE) [![qq group](https://img.shields.io/badge/group-892659456-red?style=flat-square&logo=tencent-qq)](https://jq.qq.com/?_wv=1027&k=E6Zov6Fi) -文档正在咕咕中, 具体使用可以参考example文件夹。 + ## ⚡️ 快速使用 @@ -43,7 +43,7 @@ func main() { ## 📖 文档 -[**--> 点击这里查看文档 <--**](./docs/) +[**--> 点击这里查看文档 <--**](https://guohuiyuan.github.io/ZeroBot/) ## 🎯 特性 diff --git a/docs/en/api.md b/docs/en/api.md index 5e1f74e6..3e3c8881 100644 --- a/docs/en/api.md +++ b/docs/en/api.md @@ -79,14 +79,32 @@ The `message` package provides helper functions to easily create these segments, 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. @@ -114,29 +132,151 @@ ZeroBot provides many built-in `Rule` functions in the `rules.go` file, allowing - **`Type(typeString string)`**: Matches events based on their type string, formatted as `"post_type/detail_type/sub_type"`. - **Example**: `Type("message/group")` matches group messages. +```go +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 in `ctx.State["args"]`. + +```go +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 +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 +engine.OnMessage(zero.CommandRule("ping")).Handle(func(ctx *zero.Ctx) { + ctx.Send("pong") +}) +``` + - **`RegexRule(regexPattern string)`**: Matches the message content with a regular expression. Stores the match results in `ctx.State["regex_matched"]`. + +```go +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 +engine.OnMessage(zero.KeywordRule("cat", "dog")).Handle(func(ctx *zero.Ctx) { + ctx.Send("I love pets!") +}) +``` + - **`FullMatchRule(texts ...string)`**: Requires the message content to be an exact match to one of the specified texts. + +```go +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 image URLs in `ctx.State["image_url"]`. +```go +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 directed at the bot (e.g., via an @-mention or nickname). +- **`OnlyToMe(ctx *Ctx) bool`**: Requires the message to be directed at the bot (e.g., via @mention or nickname). + +```go +engine.OnMessage(zero.OnlyToMe, zero.FullMatchRule("hello")).Handle(func(ctx *zero.Ctx) { + ctx.Send("world") +}) +``` + - **`OnlyPrivate(ctx *Ctx) bool`**: Requires the message to be a private message. + +```go +engine.OnMessage(zero.OnlyPrivate, zero.FullMatchRule("hello")).Handle(func(ctx *zero.Ctx) { + ctx.Send("world") +}) +``` + - **`OnlyGroup(ctx *Ctx) bool`**: Requires the message to be a group message. + +```go +engine.OnMessage(zero.OnlyGroup, zero.FullMatchRule("hello")).Handle(func(ctx *zero.Ctx) { + ctx.Send("world") +}) +``` + - **`ReplyRule(messageID int64)`**: Checks if the message is a reply to a specific message ID. +```go +engine.OnMessage(zero.FullMatchRule("track me")).Handle(func(ctx *zero.Ctx) { + msg, err := ctx.Send("I will track this message.") + if err != nil { + return + } + engine.OnMessage(zero.ReplyRule(msg.MessageID)).Handle(func(ctx *zero.Ctx) { + ctx.Send("You replied to the tracked message!") + }) +}) +``` + ### User and Permission Matching -- **`CheckUser(userIDs ...int64)`**: Requires the message to be from one of the specified users. -- **`CheckGroup(groupIDs ...int64)`**: Requires the message to be from one of the specified groups. -- **`SuperUserPermission(ctx *Ctx) bool`**: Requires the sender to be a superuser. -- **`AdminPermission(ctx *Ctx) bool`**: Requires the sender to be a group admin, owner, or a superuser. -- **`OwnerPermission(ctx *Ctx) bool`**: Requires the sender to be a group owner or a superuser. +- **`CheckUser(userIDs ...int64)`**: Checks if the message is from one of the specified user IDs. + +```go +engine.OnMessage(zero.CheckUser(123456789)).Handle(func(ctx *zero.Ctx) { + ctx.Send("Hello, specific user!") +}) +``` + +- **`CheckGroup(groupIDs ...int64)`**: Checks if the message is from one of the specified group IDs. + +```go +engine.OnMessage(zero.CheckGroup(987654321)).Handle(func(ctx *zero.Ctx) { + ctx.Send("Hello, specific group!") +}) +``` + +- **`SuperUserPermission(ctx *Ctx) bool`**: Requires the message sender to be a superuser. + +```go +engine.OnMessage(zero.SuperUserPermission, zero.FullMatchRule("admin command")).Handle(func(ctx *zero.Ctx) { + ctx.Send("Hello, superuser!") +}) +``` + +- **`AdminPermission(ctx *Ctx) bool`**: Requires the message sender to be a group admin, owner, or superuser. + +```go +engine.OnMessage(zero.AdminPermission, zero.FullMatchRule("admin command")).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 +engine.OnMessage(zero.OwnerPermission, zero.FullMatchRule("admin command")).Handle(func(ctx *zero.Ctx) { + ctx.Send("Hello, owner!") +}) +``` [Next: Creating Plugins](/en/plugins.md) \ No newline at end of file diff --git a/docs/en/plugins.md b/docs/en/plugins.md index 7aeaef7b..50695167 100644 --- a/docs/en/plugins.md +++ b/docs/en/plugins.md @@ -31,9 +31,25 @@ func init() { Then, in your main.go, import the plugin: ```go +package main + import ( - _ "your/plugin/path" + _ "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 diff --git a/docs/zh-cn/api.md b/docs/zh-cn/api.md index e60dc813..e0219d0e 100644 --- a/docs/zh-cn/api.md +++ b/docs/zh-cn/api.md @@ -79,14 +79,32 @@ ctx.Send("hello", message.Image("https://example.com/image.png")) 创建一个新的文本消息段。 +```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` 开头的方法,用于注册不同类型事件的处理器。这些方法的设计允许你将多个条件和最终的执行逻辑串联起来,形成清晰、可读的代码。 @@ -114,29 +132,145 @@ ZeroBot 在 `rules.go` 文件中提供了许多内置的 `Rule` 函数,让你 - **`Type(typeString string)`**: 根据事件的类型字符串进行匹配,格式为 `"post_type/detail_type/sub_type"`。 - **示例**: `Type("message/group")` 匹配群聊消息。 +```go +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 +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 +engine.OnMessage(zero.CommandRule("ping")).Handle(func(ctx *zero.Ctx) { + ctx.Send("pong") +}) +``` + - **`RegexRule(regexPattern string)`**: 使用正则表达式匹配消息内容。将匹配结果存储在 `ctx.State["regex_matched"]` 中。 + +```go +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 +engine.OnMessage(zero.HasPicture).Handle(func(ctx *zero.Ctx) { + ctx.Send("我看到你发了一张图片!") +}) +``` + ### 消息上下文匹配 -- **`OnlyToMe(ctx *Ctx) bool`**: 要求消息是发给机器人的(例如,通过 @提及或昵称)。 +- **`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`**: 要求消息是群聊消息。 -- **`ReplyRule(messageID int64)`**: 检查消息是否是对特定消息 ID 的回复。 + +```go +engine.OnMessage(zero.OnlyGroup(), zero.FullMatchRule("大家好")).Handle(func(ctx *zero.Ctx) { + ctx.Send("大家好!") +}) +``` + +- **`ReplyRule(ctx *Ctx) bool`**: 要求消息是回复消息。将回复的消息 ID 存储在 `ctx.State["reply_message_id"]` 中。 + +```go +engine.OnMessage(zero.ReplyRule()).Handle(func(ctx *zero.Ctx) { + ctx.Send("你正在回复一条消息!") +}) +``` ### 用户和权限匹配 -- **`CheckUser(userIDs ...int64)`**: 要求消息来自指定的用户之一。 -- **`CheckGroup(groupIDs ...int64)`**: 要求消息来自指定的群组之一。 -- **`SuperUserPermission(ctx *Ctx) bool`**: 要求发送者是超级用户。 -- **`AdminPermission(ctx *Ctx) bool`**: 要求发送者是群组管理员、所有者或超级用户。 -- **`OwnerPermission(ctx *Ctx) bool`**: 要求发送者是群组所有者或超级用户。 +- **`CheckUser(userIDs ...int64)`**: 检查消息是否来自指定的用户 ID 之一。 + +```go +engine.OnMessage(zero.CheckUser(123456789)).Handle(func(ctx *zero.Ctx) { + ctx.Send("你好,指定的用户!") +}) +``` + +- **`CheckGroup(groupIDs ...int64)`**: 检查消息是否来自指定的群组 ID 之一。 + +```go +engine.OnMessage(zero.CheckGroup(987654321)).Handle(func(ctx *zero.Ctx) { + ctx.Send("你好,指定的群组!") +}) +``` + +- **`SuperUserPermission(ctx *Ctx) bool`**: 要求消息发送者是超级用户。 + +```go +engine.OnMessage(zero.SuperUserPermission, zero.FullMatchRule("管理命令")).Handle(func(ctx *zero.Ctx) { + ctx.Send("你好,超级用户!") +}) +``` + +- **`AdminPermission(ctx *Ctx) bool`**: 要求消息发送者是群管理员、群主或超级用户。 + +```go +engine.OnMessage(zero.AdminPermission, zero.FullMatchRule("管理命令")).Handle(func(ctx *zero.Ctx) { + ctx.Send("你好,管理员!") +}) +``` + +- **`OwnerPermission(ctx *Ctx) bool`**: 要求消息发送者是群主或超级用户。 + +```go +engine.OnMessage(zero.OwnerPermission, zero.FullMatchRule("管理命令")).Handle(func(ctx *zero.Ctx) { + ctx.Send("你好,群主!") +}) +``` [下一步: 创建插件](/zh-cn/plugins.md) \ No newline at end of file diff --git a/docs/zh-cn/plugins.md b/docs/zh-cn/plugins.md index 3298d356..8f10e395 100644 --- a/docs/zh-cn/plugins.md +++ b/docs/zh-cn/plugins.md @@ -39,7 +39,15 @@ import ( ) func main() { - zero.Run() + zero.RunAndBlock(&zero.Config{ + NickName: []string{"bot"}, + CommandPrefix: "/", + SuperUsers: []int64{123456}, + Driver: []zero.Driver{ + // 正向 WS + driver.NewWebSocketClient("ws://127.0.0.1:6700", ""), + }, + }, nil) } ``` From a3c45a15b1ac1f2eb2f4a482bff0f9d92c47c653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Wed, 3 Dec 2025 11:58:40 +0800 Subject: [PATCH 07/12] =?UTF-8?q?=E2=9C=A8=E6=B7=BB=E5=8A=A0api=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/api.md | 63 ++++++++++++++++++++++++++++++----------------- docs/zh-cn/api.md | 33 ++++++++++++++++++++++--- 2 files changed, 70 insertions(+), 26 deletions(-) diff --git a/docs/en/api.md b/docs/en/api.md index 3e3c8881..06783ca2 100644 --- a/docs/en/api.md +++ b/docs/en/api.md @@ -129,10 +129,10 @@ ZeroBot provides many built-in `Rule` functions in the `rules.go` file, allowing ### Event Type Matching -- **`Type(typeString string)`**: Matches events based on their type string, formatted as `"post_type/detail_type/sub_type"`. - - **Example**: `Type("message/group")` matches group messages. +- **`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") }) @@ -140,9 +140,11 @@ engine.OnMessage(zero.Type("message/group"), zero.FullMatchRule("hello")).Handle ### 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 in `ctx.State["args"]`. +- **`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") }) @@ -151,6 +153,7 @@ engine.OnMessage(zero.PrefixRule("hello")).Handle(func(ctx *zero.Ctx) { - **`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") }) @@ -159,6 +162,8 @@ engine.OnMessage(zero.SuffixRule("world")).Handle(func(ctx *zero.Ctx) { - **`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.OnMessage(zero.CommandRule("ping")).Handle(func(ctx *zero.Ctx) { ctx.Send("pong") }) @@ -167,31 +172,37 @@ engine.OnMessage(zero.CommandRule("ping")).Handle(func(ctx *zero.Ctx) { - **`RegexRule(regexPattern string)`**: Matches the message content with 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]) + 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 love pets!") + ctx.Send("I like pets!") }) ``` -- **`FullMatchRule(texts ...string)`**: Requires the message content to be an exact match to one of the specified texts. +- **`FullMatchRule(texts ...string)`**: Requires the message content to exactly match one of the specified texts. ```go +// This example responds only 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 image URLs in `ctx.State["image_url"]`. +- **`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 slice of strings containing the URLs of the images. engine.OnMessage(zero.HasPicture).Handle(func(ctx *zero.Ctx) { ctx.Send("I see you sent a picture!") }) @@ -199,41 +210,44 @@ engine.OnMessage(zero.HasPicture).Handle(func(ctx *zero.Ctx) { ### Message Context Matching -- **`OnlyToMe(ctx *Ctx) bool`**: Requires the message to be directed at the bot (e.g., via @mention or nickname). +- **`OnlyToMe(ctx *Ctx) bool`**: Requires the message to be directed at the Bot (e.g., by @ing it). ```go -engine.OnMessage(zero.OnlyToMe, zero.FullMatchRule("hello")).Handle(func(ctx *zero.Ctx) { - ctx.Send("world") +// 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 am here") }) ``` - **`OnlyPrivate(ctx *Ctx) bool`**: Requires the message to be a private message. ```go -engine.OnMessage(zero.OnlyPrivate, zero.FullMatchRule("hello")).Handle(func(ctx *zero.Ctx) { - ctx.Send("world") +// 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 -engine.OnMessage(zero.OnlyGroup, zero.FullMatchRule("hello")).Handle(func(ctx *zero.Ctx) { - ctx.Send("world") +// 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 -engine.OnMessage(zero.FullMatchRule("track me")).Handle(func(ctx *zero.Ctx) { - msg, err := ctx.Send("I will track this message.") - if err != nil { - return - } - engine.OnMessage(zero.ReplyRule(msg.MessageID)).Handle(func(ctx *zero.Ctx) { - ctx.Send("You replied to the tracked message!") - }) +// This example listens for a command and 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!") }) ``` @@ -242,6 +256,7 @@ engine.OnMessage(zero.FullMatchRule("track me")).Handle(func(ctx *zero.Ctx) { - **`CheckUser(userIDs ...int64)`**: Checks if the message is from one of the specified user IDs. ```go +// This example responds only to messages from user 123456789. engine.OnMessage(zero.CheckUser(123456789)).Handle(func(ctx *zero.Ctx) { ctx.Send("Hello, specific user!") }) @@ -250,6 +265,7 @@ engine.OnMessage(zero.CheckUser(123456789)).Handle(func(ctx *zero.Ctx) { - **`CheckGroup(groupIDs ...int64)`**: Checks if the message is from one of the specified group IDs. ```go +// This example responds only to messages from group 987654321. engine.OnMessage(zero.CheckGroup(987654321)).Handle(func(ctx *zero.Ctx) { ctx.Send("Hello, specific group!") }) @@ -258,6 +274,7 @@ engine.OnMessage(zero.CheckGroup(987654321)).Handle(func(ctx *zero.Ctx) { - **`SuperUserPermission(ctx *Ctx) bool`**: Requires the message sender to be a superuser. ```go +// This example handles an "admin command" only if the sender is a superuser. engine.OnMessage(zero.SuperUserPermission, zero.FullMatchRule("admin command")).Handle(func(ctx *zero.Ctx) { ctx.Send("Hello, superuser!") }) @@ -266,6 +283,7 @@ engine.OnMessage(zero.SuperUserPermission, zero.FullMatchRule("admin command")). - **`AdminPermission(ctx *Ctx) bool`**: Requires the message sender to be a group admin, owner, or superuser. ```go +// This example handles an "admin command" only if the sender has admin-level permissions. engine.OnMessage(zero.AdminPermission, zero.FullMatchRule("admin command")).Handle(func(ctx *zero.Ctx) { ctx.Send("Hello, admin!") }) @@ -274,6 +292,7 @@ engine.OnMessage(zero.AdminPermission, zero.FullMatchRule("admin command")).Hand - **`OwnerPermission(ctx *Ctx) bool`**: Requires the message sender to be the group owner or a superuser. ```go +// This example handles an "admin command" only if the sender is the group owner or a superuser. engine.OnMessage(zero.OwnerPermission, zero.FullMatchRule("admin command")).Handle(func(ctx *zero.Ctx) { ctx.Send("Hello, owner!") }) diff --git a/docs/zh-cn/api.md b/docs/zh-cn/api.md index e0219d0e..0ee9f149 100644 --- a/docs/zh-cn/api.md +++ b/docs/zh-cn/api.md @@ -130,9 +130,9 @@ ZeroBot 在 `rules.go` 文件中提供了许多内置的 `Rule` 函数,让你 ### 事件类型匹配 - **`Type(typeString string)`**: 根据事件的类型字符串进行匹配,格式为 `"post_type/detail_type/sub_type"`。 - - **示例**: `Type("message/group")` 匹配群聊消息。 ```go +// 这个例子处理完全匹配 "hello" 的群聊消息。 engine.OnMessage(zero.Type("message/group"), zero.FullMatchRule("hello")).Handle(func(ctx *zero.Ctx) { ctx.Send("hello world") }) @@ -143,6 +143,8 @@ engine.OnMessage(zero.Type("message/group"), zero.FullMatchRule("hello")).Handle - **`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("世界") }) @@ -151,6 +153,7 @@ engine.OnMessage(zero.PrefixRule("你好")).Handle(func(ctx *zero.Ctx) { - **`SuffixRule(suffixes ...string)`**: 检查消息是否以指定的后缀结尾。 ```go +// 这个例子响应以 "世界" 结尾的消息。 engine.OnMessage(zero.SuffixRule("世界")).Handle(func(ctx *zero.Ctx) { ctx.Send("你好") }) @@ -159,6 +162,8 @@ engine.OnMessage(zero.SuffixRule("世界")).Handle(func(ctx *zero.Ctx) { - **`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") }) @@ -167,6 +172,8 @@ engine.OnMessage(zero.CommandRule("ping")).Handle(func(ctx *zero.Ctx) { - **`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]) @@ -176,6 +183,7 @@ engine.OnMessage(zero.RegexRule(`^你好, (.*)$`)).Handle(func(ctx *zero.Ctx) { - **`KeywordRule(keywords ...string)`**: 检查消息是否包含指定的任何关键字。 ```go +// 这个例子响应包含 "猫" 或 "狗" 的消息。 engine.OnMessage(zero.KeywordRule("猫", "狗")).Handle(func(ctx *zero.Ctx) { ctx.Send("我喜欢宠物!") }) @@ -184,6 +192,7 @@ engine.OnMessage(zero.KeywordRule("猫", "狗")).Handle(func(ctx *zero.Ctx) { - **`FullMatchRule(texts ...string)`**: 要求消息内容与指定的文本之一完全匹配。 ```go +// 这个例子只响应消息 "嗨"。 engine.OnMessage(zero.FullMatchRule("嗨")).Handle(func(ctx *zero.Ctx) { ctx.Send("你好") }) @@ -192,6 +201,8 @@ engine.OnMessage(zero.FullMatchRule("嗨")).Handle(func(ctx *zero.Ctx) { - **`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("我看到你发了一张图片!") }) @@ -202,6 +213,7 @@ engine.OnMessage(zero.HasPicture).Handle(func(ctx *zero.Ctx) { - **`OnlyToMe(ctx *Ctx) bool`**: 要求消息是发给 Bot 的(例如,通过 at Bot)。 ```go +// 这个例子在机器人被 @ 并收到消息 "在吗" 时响应。 engine.OnMessage(zero.OnlyToMe(), zero.FullMatchRule("在吗")).Handle(func(ctx *zero.Ctx) { ctx.Send("我在") }) @@ -210,6 +222,7 @@ engine.OnMessage(zero.OnlyToMe(), zero.FullMatchRule("在吗")).Handle(func(ctx - **`OnlyPrivate(ctx *Ctx) bool`**: 要求消息是私聊消息。 ```go +// 这个例子响应私聊消息 "你好"。 engine.OnMessage(zero.OnlyPrivate(), zero.FullMatchRule("你好")).Handle(func(ctx *zero.Ctx) { ctx.Send("你好,很高兴认识你!") }) @@ -218,16 +231,23 @@ engine.OnMessage(zero.OnlyPrivate(), zero.FullMatchRule("你好")).Handle(func(c - **`OnlyGroup(ctx *Ctx) bool`**: 要求消息是群聊消息。 ```go +// 这个例子响应群聊消息 "大家好"。 engine.OnMessage(zero.OnlyGroup(), zero.FullMatchRule("大家好")).Handle(func(ctx *zero.Ctx) { ctx.Send("大家好!") }) ``` -- **`ReplyRule(ctx *Ctx) bool`**: 要求消息是回复消息。将回复的消息 ID 存储在 `ctx.State["reply_message_id"]` 中。 +- **`ReplyRule(messageID int64)`**: 检查消息是否是对特定消息 ID 的回复。 ```go -engine.OnMessage(zero.ReplyRule()).Handle(func(ctx *zero.Ctx) { - ctx.Send("你正在回复一条消息!") +// 这个例子监听一个命令,然后等待对机器人响应的回复。 +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("你回复了我!") }) ``` @@ -236,6 +256,7 @@ engine.OnMessage(zero.ReplyRule()).Handle(func(ctx *zero.Ctx) { - **`CheckUser(userIDs ...int64)`**: 检查消息是否来自指定的用户 ID 之一。 ```go +// 这个例子只响应来自用户 123456789 的消息。 engine.OnMessage(zero.CheckUser(123456789)).Handle(func(ctx *zero.Ctx) { ctx.Send("你好,指定的用户!") }) @@ -244,6 +265,7 @@ engine.OnMessage(zero.CheckUser(123456789)).Handle(func(ctx *zero.Ctx) { - **`CheckGroup(groupIDs ...int64)`**: 检查消息是否来自指定的群组 ID 之一。 ```go +// 这个例子只响应来自群组 987654321 的消息。 engine.OnMessage(zero.CheckGroup(987654321)).Handle(func(ctx *zero.Ctx) { ctx.Send("你好,指定的群组!") }) @@ -252,6 +274,7 @@ engine.OnMessage(zero.CheckGroup(987654321)).Handle(func(ctx *zero.Ctx) { - **`SuperUserPermission(ctx *Ctx) bool`**: 要求消息发送者是超级用户。 ```go +// 这个例子仅在发送者是超级用户时处理 "管理命令"。 engine.OnMessage(zero.SuperUserPermission, zero.FullMatchRule("管理命令")).Handle(func(ctx *zero.Ctx) { ctx.Send("你好,超级用户!") }) @@ -260,6 +283,7 @@ engine.OnMessage(zero.SuperUserPermission, zero.FullMatchRule("管理命令")).H - **`AdminPermission(ctx *Ctx) bool`**: 要求消息发送者是群管理员、群主或超级用户。 ```go +// 这个例子仅在发送者具有管理员级别权限时处理 "管理命令"。 engine.OnMessage(zero.AdminPermission, zero.FullMatchRule("管理命令")).Handle(func(ctx *zero.Ctx) { ctx.Send("你好,管理员!") }) @@ -268,6 +292,7 @@ engine.OnMessage(zero.AdminPermission, zero.FullMatchRule("管理命令")).Handl - **`OwnerPermission(ctx *Ctx) bool`**: 要求消息发送者是群主或超级用户。 ```go +// 这个例子仅在发送者是群主或超级用户时处理 "管理命令"。 engine.OnMessage(zero.OwnerPermission, zero.FullMatchRule("管理命令")).Handle(func(ctx *zero.Ctx) { ctx.Send("你好,群主!") }) From d4ea522323680d0a4687931fef91e3ef0262fb33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Wed, 3 Dec 2025 12:11:12 +0800 Subject: [PATCH 08/12] =?UTF-8?q?=F0=9F=93=9D=E4=BF=AE=E6=94=B9=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/api.md | 18 +++++++++--------- docs/zh-cn/api.md | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/en/api.md b/docs/en/api.md index 06783ca2..22354a59 100644 --- a/docs/en/api.md +++ b/docs/en/api.md @@ -214,7 +214,7 @@ engine.OnMessage(zero.HasPicture).Handle(func(ctx *zero.Ctx) { ```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) { +engine.OnMessage(zero.OnlyToMe, zero.FullMatchRule("are you there")).Handle(func(ctx *zero.Ctx) { ctx.Send("I am here") }) ``` @@ -223,7 +223,7 @@ engine.OnMessage(zero.OnlyToMe(), zero.FullMatchRule("are you there")).Handle(fu ```go // This example responds to the private message "hello". -engine.OnMessage(zero.OnlyPrivate(), zero.FullMatchRule("hello")).Handle(func(ctx *zero.Ctx) { +engine.OnMessage(zero.OnlyPrivate, zero.FullMatchRule("hello")).Handle(func(ctx *zero.Ctx) { ctx.Send("hello, nice to meet you!") }) ``` @@ -232,7 +232,7 @@ engine.OnMessage(zero.OnlyPrivate(), zero.FullMatchRule("hello")).Handle(func(ct ```go // This example responds to the group message "hello everyone". -engine.OnMessage(zero.OnlyGroup(), zero.FullMatchRule("hello everyone")).Handle(func(ctx *zero.Ctx) { +engine.OnMessage(zero.OnlyGroup, zero.FullMatchRule("hello everyone")).Handle(func(ctx *zero.Ctx) { ctx.Send("hello everyone!") }) ``` @@ -274,8 +274,8 @@ engine.OnMessage(zero.CheckGroup(987654321)).Handle(func(ctx *zero.Ctx) { - **`SuperUserPermission(ctx *Ctx) bool`**: Requires the message sender to be a superuser. ```go -// This example handles an "admin command" only if the sender is a superuser. -engine.OnMessage(zero.SuperUserPermission, zero.FullMatchRule("admin command")).Handle(func(ctx *zero.Ctx) { +// This example handles an "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!") }) ``` @@ -283,8 +283,8 @@ engine.OnMessage(zero.SuperUserPermission, zero.FullMatchRule("admin command")). - **`AdminPermission(ctx *Ctx) bool`**: Requires the message sender to be a group admin, owner, or superuser. ```go -// This example handles an "admin command" only if the sender has admin-level permissions. -engine.OnMessage(zero.AdminPermission, zero.FullMatchRule("admin command")).Handle(func(ctx *zero.Ctx) { +// This example handles an "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!") }) ``` @@ -292,8 +292,8 @@ engine.OnMessage(zero.AdminPermission, zero.FullMatchRule("admin command")).Hand - **`OwnerPermission(ctx *Ctx) bool`**: Requires the message sender to be the group owner or a superuser. ```go -// This example handles an "admin command" only if the sender is the group owner or a superuser. -engine.OnMessage(zero.OwnerPermission, zero.FullMatchRule("admin command")).Handle(func(ctx *zero.Ctx) { +// This example handles an "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!") }) ``` diff --git a/docs/zh-cn/api.md b/docs/zh-cn/api.md index 0ee9f149..744c12cf 100644 --- a/docs/zh-cn/api.md +++ b/docs/zh-cn/api.md @@ -214,7 +214,7 @@ engine.OnMessage(zero.HasPicture).Handle(func(ctx *zero.Ctx) { ```go // 这个例子在机器人被 @ 并收到消息 "在吗" 时响应。 -engine.OnMessage(zero.OnlyToMe(), zero.FullMatchRule("在吗")).Handle(func(ctx *zero.Ctx) { +engine.OnMessage(zero.OnlyToMe, zero.FullMatchRule("在吗")).Handle(func(ctx *zero.Ctx) { ctx.Send("我在") }) ``` @@ -223,7 +223,7 @@ engine.OnMessage(zero.OnlyToMe(), zero.FullMatchRule("在吗")).Handle(func(ctx ```go // 这个例子响应私聊消息 "你好"。 -engine.OnMessage(zero.OnlyPrivate(), zero.FullMatchRule("你好")).Handle(func(ctx *zero.Ctx) { +engine.OnMessage(zero.OnlyPrivate, zero.FullMatchRule("你好")).Handle(func(ctx *zero.Ctx) { ctx.Send("你好,很高兴认识你!") }) ``` @@ -232,7 +232,7 @@ engine.OnMessage(zero.OnlyPrivate(), zero.FullMatchRule("你好")).Handle(func(c ```go // 这个例子响应群聊消息 "大家好"。 -engine.OnMessage(zero.OnlyGroup(), zero.FullMatchRule("大家好")).Handle(func(ctx *zero.Ctx) { +engine.OnMessage(zero.OnlyGroup, zero.FullMatchRule("大家好")).Handle(func(ctx *zero.Ctx) { ctx.Send("大家好!") }) ``` @@ -274,8 +274,8 @@ engine.OnMessage(zero.CheckGroup(987654321)).Handle(func(ctx *zero.Ctx) { - **`SuperUserPermission(ctx *Ctx) bool`**: 要求消息发送者是超级用户。 ```go -// 这个例子仅在发送者是超级用户时处理 "管理命令"。 -engine.OnMessage(zero.SuperUserPermission, zero.FullMatchRule("管理命令")).Handle(func(ctx *zero.Ctx) { +// 这个例子仅在发送者是超级用户时处理 "管理" 命令。 +engine.OnMessage(zero.SuperUserPermission, zero.CommandRule("管理")).Handle(func(ctx *zero.Ctx) { ctx.Send("你好,超级用户!") }) ``` @@ -283,8 +283,8 @@ engine.OnMessage(zero.SuperUserPermission, zero.FullMatchRule("管理命令")).H - **`AdminPermission(ctx *Ctx) bool`**: 要求消息发送者是群管理员、群主或超级用户。 ```go -// 这个例子仅在发送者具有管理员级别权限时处理 "管理命令"。 -engine.OnMessage(zero.AdminPermission, zero.FullMatchRule("管理命令")).Handle(func(ctx *zero.Ctx) { +// 这个例子仅在发送者具有管理员级别权限时处理 "管理" 命令。 +engine.OnMessage(zero.AdminPermission, zero.CommandRule("管理")).Handle(func(ctx *zero.Ctx) { ctx.Send("你好,管理员!") }) ``` @@ -292,8 +292,8 @@ engine.OnMessage(zero.AdminPermission, zero.FullMatchRule("管理命令")).Handl - **`OwnerPermission(ctx *Ctx) bool`**: 要求消息发送者是群主或超级用户。 ```go -// 这个例子仅在发送者是群主或超级用户时处理 "管理命令"。 -engine.OnMessage(zero.OwnerPermission, zero.FullMatchRule("管理命令")).Handle(func(ctx *zero.Ctx) { +// 这个例子仅在发送者是群主或超级用户时处理 "管理" 命令。 +engine.OnMessage(zero.OwnerPermission, zero.CommandRule("管理")).Handle(func(ctx *zero.Ctx) { ctx.Send("你好,群主!") }) ``` From 4679ee8f214b6831bfeec6644972c9eff1e416b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Wed, 3 Dec 2025 12:38:50 +0800 Subject: [PATCH 09/12] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=E6=B7=BB=E5=8A=A0futur?= =?UTF-8?q?eEvent=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/api.md | 227 ++++++++++++++++++++++++++++++++++++++++++---- docs/zh-cn/api.md | 144 +++++++++++++++++++++++++++++ 2 files changed, 353 insertions(+), 18 deletions(-) diff --git a/docs/en/api.md b/docs/en/api.md index 22354a59..b42c1921 100644 --- a/docs/en/api.md +++ b/docs/en/api.md @@ -123,6 +123,38 @@ engine.OnMessage(Rule1, Rule2, ...).Handle(func(ctx *zero.Ctx) { 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. @@ -164,12 +196,58 @@ engine.OnMessage(zero.SuffixRule("world")).Handle(func(ctx *zero.Ctx) { ```go // Assuming CommandPrefix is "/", this example responds to "/ping". // ctx.State["command"] will be "ping". -engine.OnMessage(zero.CommandRule("ping")).Handle(func(ctx *zero.Ctx) { +engine.OnCommand("ping").Handle(func(ctx *zero.Ctx) { ctx.Send("pong") }) ``` -- **`RegexRule(regexPattern string)`**: Matches the message content with a regular expression. Stores the match results in `ctx.State["regex_matched"]`. +- **`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". @@ -192,7 +270,7 @@ engine.OnMessage(zero.KeywordRule("cat", "dog")).Handle(func(ctx *zero.Ctx) { - **`FullMatchRule(texts ...string)`**: Requires the message content to exactly match one of the specified texts. ```go -// This example responds only to the message "hi". +// This example only responds to the message "hi". engine.OnMessage(zero.FullMatchRule("hi")).Handle(func(ctx *zero.Ctx) { ctx.Send("hello") }) @@ -202,7 +280,7 @@ engine.OnMessage(zero.FullMatchRule("hi")).Handle(func(ctx *zero.Ctx) { ```go // This example responds when a message contains a picture. -// ctx.State["image_url"] will be a slice of strings containing the URLs of the images. +// 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!") }) @@ -210,12 +288,12 @@ engine.OnMessage(zero.HasPicture).Handle(func(ctx *zero.Ctx) { ### Message Context Matching -- **`OnlyToMe(ctx *Ctx) bool`**: Requires the message to be directed at the Bot (e.g., by @ing it). +- **`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". +// 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 am here") + ctx.Send("I'm here") }) ``` @@ -224,7 +302,7 @@ engine.OnMessage(zero.OnlyToMe, zero.FullMatchRule("are you there")).Handle(func ```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!") + ctx.Send("Hello, nice to meet you!") }) ``` @@ -233,14 +311,14 @@ engine.OnMessage(zero.OnlyPrivate, zero.FullMatchRule("hello")).Handle(func(ctx ```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!") + 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 and then waits for a reply to the bot's response. +// 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") @@ -256,34 +334,34 @@ engine.OnMessage(zero.ReplyRule(msgID)).Handle(func(ctx *zero.Ctx) { - **`CheckUser(userIDs ...int64)`**: Checks if the message is from one of the specified user IDs. ```go -// This example responds only to messages from user 123456789. +// This example only responds to messages from user 123456789. engine.OnMessage(zero.CheckUser(123456789)).Handle(func(ctx *zero.Ctx) { - ctx.Send("Hello, specific user!") + ctx.Send("Hello, designated user!") }) ``` - **`CheckGroup(groupIDs ...int64)`**: Checks if the message is from one of the specified group IDs. ```go -// This example responds only to messages from group 987654321. +// This example only responds to messages from group 987654321. engine.OnMessage(zero.CheckGroup(987654321)).Handle(func(ctx *zero.Ctx) { - ctx.Send("Hello, specific group!") + ctx.Send("Hello, designated group!") }) ``` - **`SuperUserPermission(ctx *Ctx) bool`**: Requires the message sender to be a superuser. ```go -// This example handles an "admin" command only if the sender is a superuser. +// 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, owner, or superuser. +- **`AdminPermission(ctx *Ctx) bool`**: Requires the message sender to be a group admin, group owner, or superuser. ```go -// This example handles an "admin" command only if the sender has admin-level permissions. +// 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!") }) @@ -292,10 +370,123 @@ engine.OnMessage(zero.AdminPermission, zero.CommandRule("admin")).Handle(func(ct - **`OwnerPermission(ctx *Ctx) bool`**: Requires the message sender to be the group owner or a superuser. ```go -// This example handles an "admin" command only if the sender is the group owner or a superuser. +// 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 + } + } + }) +} +``` + [Next: Creating Plugins](/en/plugins.md) \ No newline at end of file diff --git a/docs/zh-cn/api.md b/docs/zh-cn/api.md index 744c12cf..90cffe92 100644 --- a/docs/zh-cn/api.md +++ b/docs/zh-cn/api.md @@ -123,6 +123,38 @@ engine.OnMessage(Rule1, Rule2, ...).Handle(func(ctx *zero.Ctx) { 除了 `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` 函数,让你可以方便地过滤和匹配事件。 @@ -298,4 +330,116 @@ engine.OnMessage(zero.OwnerPermission, zero.CommandRule("管理")).Handle(func(c }) ``` +- **`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 // 退出处理器 + } + } + }) +} +``` + [下一步: 创建插件](/zh-cn/plugins.md) \ No newline at end of file From 40f2a8ede4afdd51a6abbdb58422f179637da49e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Wed, 3 Dec 2025 13:01:19 +0800 Subject: [PATCH 10/12] =?UTF-8?q?=F0=9F=93=9D=E6=B7=BB=E5=8A=A0=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/api.md | 318 +++++++++++++++++++++++++++++++++++++++++++++- docs/zh-cn/api.md | 318 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 634 insertions(+), 2 deletions(-) diff --git a/docs/en/api.md b/docs/en/api.md index b42c1921..335c7f5c 100644 --- a/docs/en/api.md +++ b/docs/en/api.md @@ -75,7 +75,236 @@ Each `Segment` has two fields: The `message` package provides helper functions to easily create these segments, such as: -### `message.Text(string) MessageSegment` +### `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. @@ -489,4 +718,91 @@ func init() { } ``` +## 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/zh-cn/api.md b/docs/zh-cn/api.md index 90cffe92..ca2da2d0 100644 --- a/docs/zh-cn/api.md +++ b/docs/zh-cn/api.md @@ -75,7 +75,236 @@ ctx.Send("hello", message.Image("https://example.com/image.png")) `message` 包提供了辅助函数来轻松创建这些段,例如: -### `message.Text(string) MessageSegment` +### `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("你好,世界")) +``` 创建一个新的文本消息段。 @@ -442,4 +671,91 @@ func init() { } ``` +## 事件类型 + +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 From fc3331040342f429e97773ac6c54872179b5bfcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Wed, 3 Dec 2025 13:16:22 +0800 Subject: [PATCH 11/12] =?UTF-8?q?=F0=9F=93=9D=E5=AE=8C=E5=96=84=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/guide.md | 13 +++++++++++-- docs/en/plugins.md | 16 ++++------------ docs/zh-cn/guide.md | 15 +++++++++++++-- docs/zh-cn/plugins.md | 16 ++++------------ 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/docs/en/guide.md b/docs/en/guide.md index 82e562bd..c872ce72 100644 --- a/docs/en/guide.md +++ b/docs/en/guide.md @@ -48,11 +48,16 @@ Once you have configured your bot, you can create a `main.go` file to run it: package main import ( - _ "your/plugin/path" // Import your plugins here - "github.com/wdvxdr1123/ZeroBot" + 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: "/", @@ -60,6 +65,10 @@ func main() { 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) } diff --git a/docs/en/plugins.md b/docs/en/plugins.md index 50695167..f487a259 100644 --- a/docs/en/plugins.md +++ b/docs/en/plugins.md @@ -19,11 +19,8 @@ import ( ) func init() { - engine := zero.New() - engine.OnMessage().Handle(func(ctx *zero.Ctx) { - if ctx.Event.Message.String() == "hello" { - ctx.Send("world") - } + zero.OnMessage(zero.FullMatch("hello")).Handle(func(ctx *zero.Ctx) { + ctx.Send("world") }) } ``` @@ -80,16 +77,11 @@ package main import ( zero "github.com/wdvxdr1123/ZeroBot" "github.com/wdvxdr1123/ZeroBot/message" - "strings" ) func init() { - engine := zero.New() - engine.OnMessage(func(ctx *zero.Ctx) bool { - return strings.HasPrefix(ctx.Event.Message.String(), "/echo") - }).Handle(func(ctx *zero.Ctx) { - msg := strings.TrimPrefix(ctx.Event.Message.String(), "/echo ") - ctx.Send(msg) + zero.OnCommand("echo").Handle(func(ctx *zero.Ctx) { + ctx.Send(ctx.Event.Message.String()) }) } ``` diff --git a/docs/zh-cn/guide.md b/docs/zh-cn/guide.md index dee5dbd3..6698bc88 100644 --- a/docs/zh-cn/guide.md +++ b/docs/zh-cn/guide.md @@ -1,5 +1,7 @@ [上一步: 介绍](/zh-cn/README.md) +[下一步: 核心 API](/zh-cn/api.md) + # 快速入门 本指南将引导您完成设置和运行第一个 ZeroBot 实例的过程。 @@ -46,11 +48,16 @@ zero.RunAndBlock(&zero.Config{ package main import ( - _ "your/plugin/path" // 在这里导入您的插件 - "github.com/wdvxdr1123/ZeroBot" + 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: "/", @@ -58,6 +65,10 @@ func main() { 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) } diff --git a/docs/zh-cn/plugins.md b/docs/zh-cn/plugins.md index 8f10e395..c5decdd8 100644 --- a/docs/zh-cn/plugins.md +++ b/docs/zh-cn/plugins.md @@ -19,11 +19,8 @@ import ( ) func init() { - engine := zero.New() - engine.OnMessage().Handle(func(ctx *zero.Ctx) { - if ctx.Event.Message.String() == "hello" { - ctx.Send("world") - } + zero.OnMessage(zero.FullMatch("hello")).Handle(func(ctx *zero.Ctx) { + ctx.Send("world") }) } ``` @@ -79,16 +76,11 @@ package main import ( zero "github.com/wdvxdr1123/ZeroBot" "github.com/wdvxdr1123/ZeroBot/message" - "strings" ) func init() { - engine := zero.New() - engine.OnMessage(func(ctx *zero.Ctx) bool { - return strings.HasPrefix(ctx.Event.Message.String(), "/echo") - }).Handle(func(ctx *zero.Ctx) { - msg := strings.TrimPrefix(ctx.Event.Message.String(), "/echo ") - ctx.Send(msg) + zero.OnCommand("echo").Handle(func(ctx *zero.Ctx) { + ctx.Send(ctx.Event.Message.String()) }) } ``` From b843fc4e15f52ddc9f916db849141f9461f90402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Wed, 3 Dec 2025 13:17:54 +0800 Subject: [PATCH 12/12] =?UTF-8?q?=E2=9C=A8=E4=BF=AE=E6=94=B9=E5=90=8D?= =?UTF-8?q?=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 044a9c60..475f41ef 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ func main() { ## 📖 文档 -[**--> 点击这里查看文档 <--**](https://guohuiyuan.github.io/ZeroBot/) +[**--> 点击这里查看文档 <--**](https://wdvxdr1123.github.io/ZeroBot/) ## 🎯 特性