Skip to content

Commit

Permalink
文档调整
Browse files Browse the repository at this point in the history
  • Loading branch information
class-liu-fullstack committed Feb 25, 2025
1 parent fb0b980 commit de3c8ef
Show file tree
Hide file tree
Showing 64 changed files with 853 additions and 2,530 deletions.
13 changes: 1 addition & 12 deletions core/src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,13 @@ export type Element = {
export class Adapter<P extends keyof App.Adapters> extends EventEmitter {
elements: Element[] = [];
private [adapterKey] = true;
bots: Adapter.Bot<P>[] = [];
#is_started: boolean = false;
app: App | null = null;
#configs: Adapter.BotConfig<P>[] = [];
static isAdapter(obj: any): obj is Adapter {
return typeof obj === 'object' && !!obj[adapterKey];
}
get bots(): Adapter.Bot<P>[] {
return (this.app?.bots.filter(bot => bot.adapter === this) || []) as unknown as Adapter.Bot<P>[];
}
set bots(bots: Adapter.Bot<P>[]) {
for (const bot of bots) {
if (bot.adapter !== this) throw new Error(`bot ${bot.unique_id} not belongs to adapter ${this.name}`);
const hasBot = (bot: Adapter.Bot<P>) => {
return this.app?.bots.some(b => b.unique_id === bot.unique_id);
};
if (!hasBot(bot)) this.app?.bots.push(bot as any);
}
}
start(app: App, config: Adapter.BotConfig<P>[]) {
this.app = app;
this.emit('start', config);
Expand Down
7 changes: 6 additions & 1 deletion core/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,15 @@ export class App extends EventEmitter {
middlewares: Middleware<Adapters>[] = [];
plugins: PluginMap = new PluginMap();
renders: Message.Render[] = [];
bots: Adapter.Bot[] = [];
get adapters() {
return App.adapters;
}
get bots() {
return Array.from(App.adapters.values()).reduce((result, adapter) => {
result.push(...adapter.bots);
return result;
}, [] as Adapter.Bot[]);
}
constructor() {
super();
this.handleMessage = this.handleMessage.bind(this);
Expand Down
37 changes: 31 additions & 6 deletions core/src/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Dict, escape, unescape } from '@zhinjs/shared';
import { Prompt } from './prompt';
import { Adapter } from './adapter';
import { Adapters, App } from './app';
import path from 'path';
import * as fs from 'node:fs';
export interface MessageBase {
message_id?: string;
channel: Message.Channel;
Expand Down Expand Up @@ -65,7 +67,7 @@ export class Message<P extends keyof App.Adapters> {
export function parseFromTemplate(template: string | MessageElem): MessageElem[] {
if (typeof template !== 'string') return [template];
const result: MessageElem[] = [];
const closingReg = /^<(\S+)(\s[^>]+)?\/>/;
const closingReg = /^<(\S+)(\s[^>]+)?>/;
const twinningReg = /^<(\S+)(\s[^>]+)?>([\s\S]*?)<\/\1>/;
while (template.length) {
const [_, type, attrStr = '', child = ''] = template.match(twinningReg) || template.match(closingReg) || [];
Expand Down Expand Up @@ -123,9 +125,18 @@ export namespace Message {
(type: string, data: Dict): string;
text(text?: string): string;
face(id: number): string;
image(path: string, type?: string): string;
image(url: string, type?: string): string;
image(data: Uint8Array, type?: string): string;
image(base64: string, type?: string): string;
video(file: string, type?: string): string;
audio(file: string, type?: string): string;
video(path: string, type?: string): string;
video(url: string, type?: string): string;
video(data: Uint8Array, type?: string): string;
video(base64: string, type?: string): string;
audio(path: string, type?: string): string;
audio(url: string, type?: string): string;
audio(data: Uint8Array, type?: string): string;
audio(base64: string, type?: string): string;
at(user_id: string | number): string;
};
export type Type = 'private' | 'group' | 'guild' | 'direct';
Expand All @@ -149,9 +160,23 @@ export const segment: Message.DefineSegment = function (type, data) {
})
.join(' ')}/>`;
} as Message.DefineSegment;
function formatSourceDataTostring<T extends string | Uint8Array>(data: T): string {
const result: string = typeof data === 'string' ? data : `base64://${Buffer.from(data).toString('base64')}`;
if (fs.existsSync(result)) return `base64://${fs.readFileSync(result).toString('base64')}`;
return result;
}
segment.text = text => escape(text || '');
segment.face = (id: number) => `<face id='${escape(id.toString())}'/>`;
segment.image = (file: string, type = 'png') => `<image file='${escape(file)}' file_type='${type}'/>`;
segment.video = (file: string, type = 'mp4') => `<video file='${escape(file)}' file_type='${type}'>`;
segment.audio = (file: string, type = 'mp3') => `<audio file='${escape(file)}' file_type='${type}'>`;
segment.image = (file: string | Uint8Array, type = 'png') => {
file = formatSourceDataTostring(file);
return `<image file='${escape(file)}' type='${type}'/>`;
};
segment.video = (file: string | Uint8Array, type = 'mp4') => {
file = formatSourceDataTostring(file);
return `<video file='${escape(file)}' file_type='${type}'/>`;
};
segment.audio = (file: string | Uint8Array, type = 'mp3') => {
file = formatSourceDataTostring(file);
return `<audio file='${escape(file)}' file_type='${type}'/>`;
};
segment.at = user_id => `<at user_id='${escape(user_id.toString())}'/>`;
84 changes: 29 additions & 55 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { defineConfigWithTheme } from 'vitepress';

const pkg = require('../../zhin/package.json');
export default defineConfigWithTheme({
title: '知音(Zhin)',
Expand Down Expand Up @@ -63,9 +64,9 @@ export default defineConfigWithTheme({
},
},
nav: [
{ text: '开始', link: '/guide/start', activeMatch: '/guide/' },
{ text: '配置', link: '/config/common', activeMatch: '/config/' },
{ text: 'API', link: '/api/zhin', activeMatch: '/api/' },
{ text: '开始', link: '/guide/intro', activeMatch: '/guide/' },
{ text: '进阶', link: '/advance/plugin', activeMatch: '/advance/' },
{ text: '开发', link: '/dev/intro', activeMatch: '/dev/' },
{ text: '插件商店', link: '/store', activeMatch: '/store' },
// { text: 'Playground', link: 'https://playground.zhin.icu', activeMatch: '/playground/' },
{
Expand All @@ -86,80 +87,53 @@ export default defineConfigWithTheme({
'/guide/': [
{
text: '介绍',
collapsible: true,
items: [
{ text: `准备工作`, link: '/guide/prepare' },
{ text: `安装`, link: '/guide/start' },
{ text: `编写第一个插件`, link: '/guide/plugin-guide' },
],
},
{
text: '深入了解',
collapsible: true,
items: [
{ text: `插件 - Plugin`, link: '/guide/plugin-introduce' },
{ text: `指令 - Command`, link: '/guide/command' },
{ text: `可交互输入 - Prompt`, link: '/guide/prompt' },
{ text: `组件 - Component`, link: '/guide/component' },
{ text: `Bot API`, link: '/guide/bot' },
{ text: `装饰器(实验性)`, link: '/guide/decorator' },
],
link: '/guide/intro',
},
{
text: '部署',
link: '/guide/deploy',
},
],
'/api/': [
{ text: `目录`, link: '/api/' },
{
text: '核心模块',
text: '安装',
collapsible: true,
items: [
{ text: `知音`, link: '/api/zhin' },
{ text: `服务`, link: '/api/service' },
{ text: `适配器`, link: '/api/adapter' },
{ text: `机器人`, link: '/api/bot' },
{ text: `指令`, link: '/api/command' },
{ text: `上下文`, link: '/api/context' },
{ text: `会话`, link: '/api/session' },
{ text: `Android Phone`, link: '/guide/android' },
{ text: `Windows PC`, link: '/guide/windows' },
{ text: `Linux`, link: '/guide/linux' },
],
},
{
text: '消息定义',
link: '/api/message',
},
{
text: '内置服务',
text: '接入平台',
collapsible: true,
items: [
{ text: `server`, link: '/api/service-server' },
{ text: `router`, link: '/api/service-router' },
{ text: `koa`, link: '/api/service-koa' },
{ text: `QQ`, link: '/guide/qq' },
{ text: `Icqq`, link: '/guide/icqq' },
{ text: `Discord`, link: '/guide/discord' },
{ text: `钉钉`, link: '/guide/dingtalk' },
{ text: `微信(Web)`, link: '/guide/web-wechat' },
{ text: `OneBot 11/12`, link: '/guide/onebot' },
{ text: `Email`, link: '/guide/email' },
],
},
{
text: `事件系统`,
collapsible: true,
items: [{ text: `事件地图`, link: '/api/event/map' }],
text: '配置文件',
link: '/guide/config',
},
],
'/config': [
'/advance/': [
{
text: '通用配置',
link: '/config/common',
text: '插件开发',
link: '/advance/plugin',
},
{
text: '适配器',
text: '核心模块',
collapsible: true,
items: [
{ text: `icqq`, link: '/config/adapter-icqq' },
{ text: `onebot`, link: '/config/adapter-onebot' },
{ text: `服务`, link: '/advance/service' },
{ text: `适配器`, link: '/advance/adapter' },
{ text: `中间件`, link: '/advance/middleware' },
{ text: `指令`, link: '/advance/command' },
],
},
{
text: '内置插件',
link: '/config/built-plugin',
text: '消息',
link: '/advance/message',
},
],
},
Expand Down
1 change: 1 addition & 0 deletions docs/.vitepress/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import zhCn from 'element-plus/es/locale/lang/zh-cn';
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
import 'element-plus/dist/index.css';
import 'element-plus/theme-chalk/dark/css-vars.css';
import './custom.css';
import ChatHistory from './components/ChatHistory.vue';
import UserAvatar from './components/UserAvatar.vue';
import ChatMsg from './components/ChatMsg.vue';
Expand Down
76 changes: 76 additions & 0 deletions docs/src/advance/plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# 插件
- 在知音的设计理念中,插件是实现一切业务逻辑的载体,小到指令定义,大到服务定义、中间件定义,都可以通过插件来实现。插件是知音的核心,也是知音的灵魂。
- 知音同时支持使用 `javascript``typescript` 进行插件开发,开发者可以根据自己的喜好选择开发语言。
- 插件分为 `本地插件`` 模块插件`
- 无论是本地插件还是模块插件,都需要在 `zhin.config.yml` 中配置启用才能生效。
## 本地插件
- 本地插件是指在本地开发的插件,可以是一个普通的 `js``ts` 文件,也可以是一个目录,目录下包含一个 `index.js``index.ts` 文件,或者通过 `package.json` 管理的插件包。

## 模块插件
- 模块插件是指通过 `npm` 发布的插件,可以通过 `npm` 安装到项目中。
## 插件开发
### 1. 创建插件
- 在项目的 `plugins` 目录下创建一个插件目录,插件目录下创建一个 `index.js``index.ts` 文件。
- 也可以通过 `npm init` 创建一个插件包。
- 一个插件的目录结构如下:
```text
plugins
└── my-plugin
├── index.js
└── package.json
```
### 2. 编写插件
- 知音通过实例化 `Plugin` 类来创建一个插件。
- 通过实例化对象 你可以往插件实例上挂载指令、服务、中间件等。
- 你可以通过 `mounted` 声明周期,指定插件挂载时的操作。
- 你需要将实例化对象作为默认导出,zhin才会视为有效插件。
- 一个简单的插件示例:
::: code-group

```javascript [index.js]
import { Plugin } from 'zhin';
const plugin = new Plugin('my-plugin');
// 定义指令
plugin.command('hello', 'hello world');
// 定义服务
plugin.service('foo',{
async bar(){
return 'bar';
}
})
// 定义中间件
plugin.middleware(async (message, next) => {
console.log('before');
await next();
});
// 挂载周期
plugin.mounted(() => {
console.log('my-plugin is mounted');
// 使用服务
console.log(plugin.hello.bar()) // bar
});
export default plugin;
```
```json [package.json]
{
"name": "my-plugin",
"version": "1.0.0",
"main": "index.js",
"peerDependencies": {
"zhin": "latest"
}
}
```
:::
### 3. 启用插件
-`zhin.config.yml` 中的 `plugins` 下添加插件名称即可启用插件。
```yaml
plugins:
- my-plugin
```
### 4. 插件发布
- 如果你的插件是一个模块插件,你可以通过 `npm publish` 发布到 `npm` 上。
- 其他开发者可以通过 `npm install my-plugin` 安装你的插件。
## 更多
- 本篇章节只是简单介绍了插件的基本使用,更多插件实例方法,请参考当前页面左侧 `核心模块` 功能介绍。

Loading

0 comments on commit de3c8ef

Please sign in to comment.