Skip to content

Latest commit

 

History

History
307 lines (230 loc) · 9.7 KB

开发指引.md

File metadata and controls

307 lines (230 loc) · 9.7 KB

开发指引

目录结构

Adachi-BOT
├── app.js                      # 主程序
├── config
│   ├── command.yml             # 用户插件配置
│   ├── command_master.yml      # 管理员插件配置
│   └── setting.yml             # 基础配置
├── data
│   └── db                      # 数据库文件
├── resources                   # 资源目录
├── resources_custom
└── src
    ├── plugins                 # 插件
    ├── utils                   # 公共库
    └── views                   # HTML

插件开发

代码示例

下面的 Patch 演示了如何添加一个插件。

From 8dad13377fb41f0fcbc44a1d2f818a7146dbf085 Mon Sep 17 00:00:00 2001
From: Qin Fandong <[email protected]>
Date: Sun, 7 Nov 2021 20:44:32 +0800
Subject: [PATCH] Hello World!

---
 config_defaults/command.yml      | 16 ++++++++++++++++
 src/plugins/hello_world/index.js | 19 +++++++++++++++++++
 src/plugins/master/index.js      |  3 ++-
 3 files changed, 37 insertions(+), 1 deletion(-)
 create mode 100644 src/plugins/hello_world/index.js

diff --git a/config_defaults/command.yml b/config_defaults/command.yml
index e1240f5..4d66d20 100644
--- a/config_defaults/command.yml
+++ b/config_defaults/command.yml
@@ -192,6 +192,22 @@ gacha:
       entrance:
         - ^取消定轨
 
+hello_world:
+  enable: true
+  weights: 10099
+  regex:
+    - ^hello\sworld$
+  functions:
+    hello_world:
+      type: command
+      show: true
+      weights: 9999
+      name: hello world
+      usage:
+      description: 向你致以诚挚的问候
+      entrance:
+        - hello world
+
 tools:
   enable: true
   weights: 99
diff --git a/src/plugins/hello_world/index.js b/src/plugins/hello_world/index.js
new file mode 100644
index 0000000..f7c0a0a
--- /dev/null
+++ b/src/plugins/hello_world/index.js
@@ -0,0 +1,19 @@
+import { checkAuth } from "../../utils/auth.js";
+import { hasEntrance } from "../../utils/config.js";
+
+async function doHelloWorld(msg) {
+  const message = `Welcome to world, ${msg.name} (${msg.uid}) !`;
+  await msg.bot.say(msg.sid, message, msg.type, msg.uid);
+}
+
+async function Plugin(msg) {
+  switch (true) {
+    case hasEntrance(msg.text, "hello_world", "hello_world"):
+      if (false !== (await checkAuth(msg, "hello_world"))) {
+        doHelloWorld(msg);
+      }
+      break;
+  }
+}
+
+export { Plugin as run };
diff --git a/src/plugins/master/index.js b/src/plugins/master/index.js
index 76e37a6..7cefe4d 100644
--- a/src/plugins/master/index.js
+++ b/src/plugins/master/index.js
@@ -63,7 +63,8 @@ async function Plugin(msg) {
       await setAuth(msg, "menu", ...parsed);
       await setAuth(msg, "prophecy", ...parsed);
       await setAuth(msg, "roll", ...parsed);
-      setAuth(msg, "quote", ...parsed);
+      await setAuth(msg, "quote", ...parsed);
+      setAuth(msg, "hello_world", ...parsed);
       break;
     }
     case hasEntrance(msg.text, "master", "reply_auth"):
-- 
2.27.0

应用该 Patch 后,启动机器人,发送 QQ 聊天信息 hello world 则会得到回复 Welcome to world, <nickname> (<id>) !

插件参数

msg

除了 oicq 中原有的属性外,你还可以使用以下属性。

属性 内容
msg.bot QQ Client
msg.atMe 有人 @ 机器人为 true ,否则为 false
msg.uid 消息发送者的 QQ 号
msg.gid 群消息为群号,好友消息为 undefined
msg.sid 群消息为 msg.gid ,好友消息为 msg.uid
msg.type 群消息为 group ,好友消息为 private
msg.name 消息发送者的 QQ 昵称
msg.text 依次去除了 @ 机器人的 CQ 码、命令前缀 config.prefixes 和行首空格的聊天文本

msg.bot

除了 oicq 中原有的属性外,你还可以使用以下属性。

方法 作用
say 发送一条消息
sayMaster 给全体管理者发送一条消息

开发步骤

  1. ../config_defaults/command.yml 中添加命令入口。
  2. ../src/plugins/ 目录下创建插件目录并编写代码。

全局变量

有以下几个全局变量包含了配置文件中的数据,可以在插件中直接使用。使用这些全局变量前确保仔细阅读../src/utils/config.js 中的注释,清楚地了解你要用的数据结构。

变量 数据
global.rootdir 项目所在的目录
global.all command.ymlcommand_master.yml 的部分内容
global.command command.yml
global.master command_master.yml
global.artifacts artifacts.yml
global.alias alias.yml
global.config setting.ymlgreeting.yml
global.eggs pool_eggs.yml

如果你使用了这些全局变量,确保文件头用类似以下的注释注明用到的全局变量,以避免 npm run check 将全局变量视为未声明的变量。

/* global rootdir, config */
/* eslint no-undef: "error" */

插件接受的 oicq 数据结构改变

当消息为一条命令时,插件通过第一个参数 msg 接收的 oicq 的数据结构可能改变。原本的 CommonMessageEventData 中的 message 字段是一个可能包含这些类型的数组,但是为了统一 messageraw_message 字段,在 ../src/utils/load.js 中剔除了 TextElem 之外的所有类型并只保留一个 TextElem 。除此之外,将 raw_messageGroupMessageEventData 中仅存的 TextElem 进行了统一。最后 GroupMessageEventData 中新增了字段 atMe: boolean 来表示这条消息是否 @ 了机器人。

除此之外, raw_messagemessage[0].data.text 依次去除了 @ 机器人的 CQ 码、命令前缀 config.prefixes 和行首空格。

数据库

../src/utils/database.js 中使用 lodash 封装了 lowdb

API

导入

import db from "../../utils/database.js";

初始化

初始化名称为 name 的数据库。如果数据库已存在,加载其数据;如果数据库不存在,创建空数据库。

default 默认设置为 { user: [] }

db.init(name: string, default?: object);

../src/utils/init.js 中使用,以便启动时初始化。

键的存在性

在数据库 name 中判断 path 是否存在。

db.has(name: string, ...path);

对应 lodash.hasIn

值的存在性

在数据库 name 中的 key 对应的 Array 中,检测所有的索引 index 在是否包含值 value

db.includes(name: string, key: string, index: string, value: any);

对应 lodash.includes

获取数据

index 返回值
undefined key 对应的 Array
object key 对应的 Array 中,获取包含索引 index 的对象
db.get(name: string, key: string, index?: object);

对应 lodash.getlodash.find

写入数据

在数据库 name 中的 key 对应的 Array 中,插入一条数据 data 。此方法自动调用 db.write

db.push(name: string, key: string, data: object);

对应 lodash.push

更新数据

在数据库 name 中的 key 对应的 Array 中,将包含索引 index 的对象更新为 data 。此方法自动调用 db.write

只更新 data 中包含的 pair ,不会修改其他数据。

db.update(name: string, key: string, index: object, data: object);

对应 lodash.assign

设置数据

把数据库 name 中的 key 对应的数据设置为 data 。此方法自动调用 db.write

db.set(name: string, key: string, data: any);

对应 lodash.set

删除数据

在数据库 name 中的 key 对应的 Array 中,将包含索引 index 的对象删除 。此方法自动调用 db.write

db.remove(name: string, key: string, index: object);

对应 lodash.reject

写入磁盘

把数据库 name 的数据写入磁盘,一般无须手动调用

db.write(name: string);

示例

下面的代码演示了如何使用这些数据库 API 。

import db from "../../utils/database.js";

async function func () {
  /* some code */
  await db.init("info");
  await db.has("info", "user", 0, "uid");
  await db.includes("info", "user", uid);
  await db.get("info", "user", { uid });
  await db.get("info", "user");
  await db.push("time", "user", { uid, time: 0 });
  await db.update("music", "source", { ID: id }, { ...data, Source: source });
  await db.set("gacha", "data", [indefinite, character, weapon]);
  await db.remove("cookie", "uid", { cookie });
  await db.write("info");  // 几乎在任何情况下你都不需要手动调用 db.write
  /* some code */
}

注意这些 API 只提供异步版本,你在无法在一个非异步的环境中使用这些 API 。