前言
LinkZone 是一个现代化的机器人框架,采用核心 + 生态系统的架构设计。它支持 Node.js 开发插件和适配器,具有热重载、定时任务、多平台适配等特性。本文将带你从零开始,快速上手 LinkZone。
目录
1. [项目结构](# 项目结构)
2. [快速开始](# 快速开始)
3. [配置说明](# 配置说明)
4. [插件开发](# 插件开发)
5. [适配器开发](# 适配器开发)
6. [SDK API 参考](#sdk-api- 参考)
7. [常见问题](# 常见问题)
---
项目结构
linkzone/
├── data/ # 数据目录
│ ├── config.yaml # 系统配置文件
│ ├── badger/ # 数据库文件
│ └── runtime/ # 运行时文件 (socket 等)
├── ecosystems/ # 生态系统
│ └── nodejs/ # Node.js 运行时
│ ├── adapters/ # 适配器目录
│ ├── plugins/ # 插件目录
│ ├── sdk/ # SDK 库
│ └── runtime.js # Node.js 运行时入口
├── logs/ # 日志目录
└── public/ # 静态文件目录
快速开始
1. 环境要求
- Node.js 16+
- LinkZone 主程序
2. 安装依赖
```bash
cd ecosystems/nodejs
npm install
```
3. 启动框架
启动 LinkZone 主程序后,Node.js 运行时会自动连接并加载插件和适配器。
<!-- [图片: 启动成功的控制台输出] -->
启动成功后,你将看到类似输出:
```
🚀 LinkZone Node.js 统一运行时启动
📡 连接地址: data/runtime/linkzone.sock
📂 扫描插件目录: ecosystems/nodejs/plugins
📦 发现 1 个插件文件
✓ 已加载插件: 青龙面板管理 (v2.0.0)
📂 扫描适配器目录: ecosystems/nodejs/adapters
📦 发现 1 个适配器文件
✓ 已加载适配器: wx (v3.2.0)
🔥 插件热重载已启用
🔥 适配器热重载已启用
✅ 成功启动 1 个插件, 1 个适配器
✅ 运行时准备就绪
```
---
配置说明
系统配置位于 data/config.yaml,采用键值对格式:
```yaml
# 核心配置
- key: system.core.bot_name
value: "LinkZone"
type: string
comment: 机器人名称
- key: system.core.log_level
value: info
type: string
comment: '日志级别 (可选: debug, info, warn, error)'
# HTTP 服务
- key: system.server.http_port
value: :8080
type: string
comment: HTTP 服务器监听的地址和端口
# 管理 Token (请修改为你自己的安全密钥)
- key: system.server.admin_token
value: "your_secure_token_here"
type: string
comment: Web 后台管理 API 的 Bearer Token
# 许可证配置
- key: system.license.key
value: "YOUR-LICENSE-KEY"
type: string
comment: 许可证密钥
- key: system.license.server_url
value: "https://your-license-server.com"
type: string
comment: 授权服务器地址```
---
插件开发
插件结构
插件存放在 ecosystems/nodejs/plugins/ 目录下,支持两种结构:
```
plugins/
├── 作者名 /
│ ├── plugin-name.js # 单文件插件
│ └── complex-plugin/ # 多文件插件
│ └── index.js
```
元数据注释
每个插件必须在文件头部声明元数据:
```javascript
/**
* @name 示例插件
* @version 1.0.0
* @author YourName
* @description 这是一个示例插件
* @command 测试 // 命令触发器 (完全匹配)
* @keyword 关键词 // 关键词触发器 (包含匹配)
* @rule ^ 正则表达式 $ // 正则触发器
* @admin false // 是否需要管理员权限
* @priority 10 // 优先级 (数字越大越先执行)
* @cron 0 0 8 * * * // 定时任务 (可选)
*/
```
编写第一个插件
创建文件 plugins/demo/hello.js:
```javascript
/**
* @name 你好世界
* @version 1.0.0
* @author Demo
* @description 一个简单的示例插件
* @command 你好
* @command hello
*/
module.exports = async function (sender) {
const name = await sender.getSenderName();
await sender.reply你好,${name}!欢迎使用 LinkZone!);
};
```
保存后,框架会自动热重载插件(无需重启)。
使用类形式
对于复杂插件,推荐使用类形式:
/**
* @name 高级插件
* @version 1.0.0
* @author Demo
* @description 类形式的插件示例
* @rule ^calc\\s+(.+)$
*/
class CalcPlugin extends Plugin {
async onStart() {
console.log('计算器插件已启动');
}
async handleMessage(sender) {
const expr = await sender.param(1);
try {
// 注意:实际使用请用安全的计算库
const result = eval(expr);
await sender.reply计算结果: ${result});
} catch (e) {
await sender.reply('表达式错误');
}
}
async onStop() {
console.log('计算器插件已停止');
}
}
module.exports = CalcPlugin;多轮对话
使用 listen() 方法实现多轮对话:
/**
* @name 问卷调查
* @version 1.0.0
* @author Demo
* @description 多轮对话示例
* @command 问卷
*/
module.exports = async function (sender) {
await sender.reply('请问你的名字是?');
const r1 = await sender.listen({ timeout: 30000 });
if (r1.timeout) return sender.reply('超时了,下次再来吧~');
const name = await r1.sender.getMessage();
await sender.reply${name},请问你的年龄是?);
const r2 = await sender.listen({ timeout: 30000 });
if (r2.timeout) return sender.reply('超时了~');
const age = await r2.sender.getMessage();
await sender.reply收到!\n姓名: ${name}\n年龄: ${age});
};### 数据持久化
使用 getData / setData 存储插件数据:
```javascript
/**
* @name 签到插件
* @version 1.0.0
* @author Demo
* @description 每日签到
* @command 签到
*/
module.exports = {
async handleMessage(sender) {
const userId = await sender.getSenderId();
const today = new Date().toDateString();
const key = sign_${userId};
const lastSign = await this.getData(key);
if (lastSign === today) {
return sender.reply('今天已经签到过啦 ~');
}
await this.setData(key, today);
await sender.reply('签到成功!');
}
};
```
### 使用 LZDB
对于更灵活的数据库操作,使用 LZDB:
```javascript
const db = new LZDB('my-plugin'); // 创建命名空间
// 基本操作
await db.set('key', { count: 1});
const data = await db.get('key', { count: 0});
await db.delete('key');
const exists = await db.exists('key');
const keys = await db.keys();
await db.clear();
```
---
适配器开发
适配器负责对接不同的消息平台(微信、QQ、Telegram 等)。
适配器结构
适配器存放在 ecosystems/nodejs/adapters/ 目录:
```
adapters/
├── wx.js # 微信适配器
├── qq.js # QQ 适配器
└── telegram.js # Telegram 适配器
```
元数据注释
/**
* @author YourName
* @name 适配器名称
* @version 1.0.0
* @description 适配器描述
* @platform platform_id
* @icon 💬
* @tags 标签1,标签2
*
* @config-schema {
* "apiUrl": {
* "type": "string",
* "label": "API 地址",
* "required": true
* },
* "token": {
* "type": "string",
* "label": "访问令牌",
* "required": true
* }
* }
*/适配器示例
/**
* @name 示例适配器
* @version 1.0.0
* @description 适配器开发模板
* @platform demo
*/
const axios = require('axios');
module.exports = {
async onStart() {
// 获取配置
const config = await this.getConfig();
// 注册 Webhook 路由
await this.registerRoute('/api/bot/demo', this.handleWebhook.bind(this), 'POST');
console.log('示例适配器已启动');
},
async handleWebhook(req) {
const { user_id, message, group_id } = req.body;
// 推送事件到框架
await this.pushEvent({
type: 'message',
platform: 'demo',
botId: 'bot001',
senderId: user_id,
message: message,
groupId: group_id || '',
timestamp: Date.now()
});
return { status: 200, body: { ok: true } };
},
async send(message) {
const { receiver_id, segments, bot_id } = message;
// 转换消息格式并发送
const text = segments
.filter(s => s.type === 'text')
.map(s => s.data.text)
.join('');
const config = await this.getConfig();
await axios.post(config.apiUrl, {
to: receiver_id,
content: text
});
return demo_${Date.now()};
},
async onStop() {
console.log('示例适配器已停止');
}
};SDK API 参考
Sender 对象
Sender 是消息上下文,提供了丰富的 API:
#### 消息获取
| 方法 | 返回值 | 说明 |
|------|--------|------|
| getMessage() | string | 获取消息文本 |
| getSenderId() | string | 获取发送者 ID |
| getSenderName() | string | 获取发送者昵称 |
| getPlatform() | string | 获取平台标识 |
| getBotId() | string | 获取机器人 ID |
| getGroupId() | string | 获取群组 ID |
| getMessageId() | string | 获取消息 ID |
| getEvent() | object | 获取完整事件对象 |
状态判断
| 方法 | 返回值 | 说明 |
|------|--------|------|
| isAdmin() | boolean | 是否管理员 |
| isGroup() | boolean | 是否群聊 |
| isPrivate() | boolean | 是否私聊 |
常见问题
### Q: 插件修改后不生效?
A: 框架支持热重载,保存文件后会自动重新加载。如果没有生效,请检查控制台是否有错误输出。
### Q: 如何调试插件?
A: 在代码中使用 console.log() 输出调试信息,日志会显示在控制台中。
### Q: 数据存储在哪里?
A: 数据存储在 data/badger/ 目录的 BadgerDB 数据库中。
### Q: 如何添加新的平台适配?
A: 在 adapters/ 目录创建新的适配器文件,实现 send() 方法和事件推送即可。
### Q: 多个插件的执行顺序?
A: 按 @priority 优先级从高到低执行。相同优先级按加载顺序执行。
---
## 附录
### Cron 表达式
```
┌──────────── 秒 (0-59)
│ ┌────────── 分 (0-59)
│ │ ┌──────── 时 (0-23)
│ │ │ ┌────── 日 (1-31)
│ │ │ │ ┌──── 月 (1-12)
│ │ │ │ │ ┌── 周 (0-6, 0= 周日)
│ │ │ │ │ │
* * * * * *
```
示例:
- 0 0 8 * * * - 每天 8:00
- 0 30 * * * * - 每小时的 30 分
- 0 0 0 1 * * - 每月 1 号 0:00
### 许可证
LinkZone 需要有效的许可证才能运行。请联系开发者获取许可证密钥。
---
> 📝 文档版本: 1.0.0
> 📅 更新时间: 2025-12-17
> 💬 如有问题,欢迎反馈