node-karin 0.10.7 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/defSet/group.yaml +6 -6
- package/lib/adapter/onebot/11/convert.js +1 -1
- package/lib/core/index.d.ts +1 -1
- package/lib/core/index.js +1 -1
- package/lib/core/karin/karin.d.ts +41 -54
- package/lib/core/karin/karin.js +61 -54
- package/lib/core/listener/listener.js +14 -0
- package/lib/core/plugin/base.d.ts +10 -23
- package/lib/core/plugin/base.js +6 -15
- package/lib/core/plugin/loader.d.ts +79 -102
- package/lib/core/plugin/loader.js +440 -404
- package/lib/core/server/server.d.ts +1 -1
- package/lib/event/handler/base.d.ts +13 -4
- package/lib/event/handler/base.js +38 -20
- package/lib/event/handler/message.d.ts +11 -7
- package/lib/event/handler/message.js +111 -81
- package/lib/event/handler/notice.d.ts +1 -0
- package/lib/event/handler/notice.js +37 -37
- package/lib/event/handler/request.d.ts +1 -0
- package/lib/event/handler/request.js +32 -37
- package/lib/event/handler/review.d.ts +10 -10
- package/lib/event/handler/review.js +34 -39
- package/lib/types/config/config.d.ts +12 -2
- package/lib/types/event/contact.d.ts +1 -1
- package/lib/types/event/event.d.ts +9 -106
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.js +1 -0
- package/lib/types/plugin/app.d.ts +71 -0
- package/lib/types/plugin/app.js +1 -0
- package/lib/types/plugin/plugin.d.ts +192 -12
- package/lib/utils/common/common.d.ts +19 -7
- package/lib/utils/common/common.js +74 -73
- package/lib/utils/config/config.d.ts +2 -2
- package/lib/utils/core/handler.d.ts +0 -14
- package/lib/utils/core/handler.js +7 -76
- package/lib/utils/tools/button.d.ts +1 -1
- package/lib/utils/tools/button.js +18 -29
- package/package.json +1 -1
- package/lib/core/plugin/app.d.ts +0 -19
- package/lib/core/plugin/app.js +0 -19
|
@@ -4,52 +4,18 @@ import lodash from 'lodash';
|
|
|
4
4
|
import chokidar from 'chokidar';
|
|
5
5
|
import schedule from 'node-schedule';
|
|
6
6
|
import { listener } from '../listener/listener.js';
|
|
7
|
-
import PluginApp from './app.js';
|
|
8
7
|
import { render } from '../../render/index.js';
|
|
9
|
-
import { common,
|
|
8
|
+
import { common, logger } from '../../utils/index.js';
|
|
10
9
|
class PluginLoader {
|
|
11
10
|
dir;
|
|
12
|
-
dirPath;
|
|
13
11
|
/**
|
|
14
12
|
* - 插件索引ID
|
|
15
13
|
*/
|
|
16
14
|
index;
|
|
17
|
-
/**
|
|
18
|
-
* - 命令插件索引列表
|
|
19
|
-
*/
|
|
20
|
-
ruleIds;
|
|
21
|
-
/**
|
|
22
|
-
* - 按钮插件索引列表
|
|
23
|
-
*/
|
|
24
|
-
buttonIds;
|
|
25
|
-
/**
|
|
26
|
-
* - accept插件索引列表
|
|
27
|
-
*/
|
|
28
|
-
acceptIds;
|
|
29
|
-
/**
|
|
30
|
-
* - handler
|
|
31
|
-
*/
|
|
32
|
-
handlerIds;
|
|
33
|
-
/**
|
|
34
|
-
* - 插件列表
|
|
35
|
-
*/
|
|
36
|
-
FileList;
|
|
37
|
-
/**
|
|
38
|
-
* - 是否ts环境
|
|
39
|
-
*/
|
|
40
|
-
isTs;
|
|
41
|
-
/**
|
|
42
|
-
* - 是否开发环境
|
|
43
|
-
*/
|
|
44
|
-
isDev;
|
|
45
|
-
/**
|
|
46
|
-
* - 最终缓存的插件列表 通过index索引
|
|
47
|
-
*/
|
|
48
|
-
PluginList;
|
|
49
15
|
/**
|
|
50
16
|
* - 定时任务
|
|
51
17
|
*/
|
|
52
|
-
task
|
|
18
|
+
// task: Array<PluginTask & { App: NewMessagePlugin, schedule?: schedule.Job, file: { dir: dirName, name: fileName } }>
|
|
53
19
|
/**
|
|
54
20
|
* - 监听器
|
|
55
21
|
*/
|
|
@@ -58,267 +24,362 @@ class PluginLoader {
|
|
|
58
24
|
* - 热更新列表
|
|
59
25
|
*/
|
|
60
26
|
watchList;
|
|
61
|
-
/**
|
|
62
|
-
* - 所有插件包package.json
|
|
63
|
-
*/
|
|
64
|
-
pkgJson;
|
|
65
27
|
/**
|
|
66
28
|
* - 依赖缺失收集
|
|
67
29
|
*/
|
|
68
30
|
dependErr;
|
|
31
|
+
/** accept */
|
|
32
|
+
accept;
|
|
33
|
+
/** button */
|
|
34
|
+
button;
|
|
35
|
+
/** command规则集信息 */
|
|
36
|
+
command;
|
|
37
|
+
/** handler */
|
|
38
|
+
handler;
|
|
39
|
+
/** plugin基本信息 */
|
|
40
|
+
plugin;
|
|
41
|
+
/** task定时任务信息 */
|
|
42
|
+
task;
|
|
43
|
+
/** 中间件 */
|
|
44
|
+
use;
|
|
45
|
+
/** 加载的文件数组 .js .ts */
|
|
46
|
+
ext;
|
|
69
47
|
constructor() {
|
|
48
|
+
this.accept = [];
|
|
49
|
+
this.button = [];
|
|
50
|
+
this.command = [];
|
|
51
|
+
this.handler = {};
|
|
52
|
+
this.plugin = {};
|
|
53
|
+
this.task = [];
|
|
54
|
+
this.use = {
|
|
55
|
+
recvMsg: [],
|
|
56
|
+
replyMsg: [],
|
|
57
|
+
sendMsg: [],
|
|
58
|
+
};
|
|
59
|
+
this.ext = process.env.karin_app_lang === 'ts' ? ['.js', '.ts'] : ['.js'];
|
|
70
60
|
this.index = 0;
|
|
71
61
|
this.dir = './plugins';
|
|
72
|
-
this.dirPath = common.urlToPath(import.meta.url);
|
|
73
|
-
this.isTs = process.env.karin_app_lang === 'ts';
|
|
74
|
-
this.isDev = process.env.karin_app_mode === 'dev';
|
|
75
62
|
this.watcher = new Map();
|
|
76
63
|
this.watchList = [];
|
|
77
|
-
this.FileList = [];
|
|
78
|
-
this.PluginList = {};
|
|
79
|
-
this.task = [];
|
|
80
|
-
this.ruleIds = [];
|
|
81
|
-
this.acceptIds = [];
|
|
82
|
-
this.buttonIds = [];
|
|
83
|
-
this.handlerIds = {};
|
|
84
|
-
this.pkgJson = {};
|
|
85
64
|
this.dependErr = {};
|
|
86
65
|
}
|
|
87
66
|
/**
|
|
88
67
|
* 插件初始化
|
|
89
68
|
*/
|
|
90
69
|
async load() {
|
|
91
|
-
await this.getPlugins();
|
|
92
70
|
listener.once('plugin.watch', () => {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
logger.debug(`[热更新][${
|
|
96
|
-
}
|
|
71
|
+
this.watchList.forEach(async ({ plugin, path }) => {
|
|
72
|
+
await this.watchDir(plugin, path);
|
|
73
|
+
logger.debug(`[热更新][${plugin}][${path}] 监听中...`);
|
|
74
|
+
});
|
|
75
|
+
this.watchList = [];
|
|
97
76
|
});
|
|
98
77
|
logger.info(logger.green('-----------'));
|
|
99
|
-
logger.info('
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
/** 载入npm插件 */
|
|
105
|
-
promises.push(...npm.map(async ({ dir, name, isMain }) => await this.createdApp(dir, name, false, true, isMain)));
|
|
106
|
-
/** 等待所有插件加载完成 */
|
|
107
|
-
await Promise.all(promises);
|
|
78
|
+
logger.info('加载插件中...');
|
|
79
|
+
const list = [];
|
|
80
|
+
list.push(...await this.getGitPlugin());
|
|
81
|
+
list.push(...await this.getNpmPlugin());
|
|
82
|
+
await Promise.all(list);
|
|
108
83
|
/** 打印依赖缺失 */
|
|
109
84
|
this.printDependErr();
|
|
110
|
-
/** 释放缓存 */
|
|
111
|
-
this.FileList = [];
|
|
112
85
|
/** 优先级排序并打印插件信息 */
|
|
113
86
|
this.orderBy(true);
|
|
114
87
|
listener.emit('plugin.watch');
|
|
115
88
|
return this;
|
|
116
89
|
}
|
|
117
90
|
/**
|
|
118
|
-
*
|
|
91
|
+
* 获取Git插件
|
|
119
92
|
*/
|
|
120
|
-
async
|
|
93
|
+
async getGitPlugin() {
|
|
121
94
|
/** 获取所有插件包 */
|
|
122
95
|
const plugins = common.getPlugins();
|
|
96
|
+
const list = [];
|
|
123
97
|
for (const dir of plugins) {
|
|
124
|
-
/**
|
|
125
|
-
|
|
126
|
-
* - 例如: ./plugins/karin-plugin-example
|
|
127
|
-
*/
|
|
128
|
-
const PluginPath = `${this.dir}/${dir}`;
|
|
129
|
-
/**
|
|
130
|
-
* 一共3种模式
|
|
131
|
-
* 1. npm run dev 开发模式 直接加载ts,js文件,对于同时存在编译产物、源代码的情况,优先加载编译产物而不加载源代码
|
|
132
|
-
* 2. node . 生产模式 只加载js文件
|
|
133
|
-
* 3. npm run debug 调试模式 利用tsx自身的热更新机制,重启karin
|
|
134
|
-
*/
|
|
98
|
+
/** 插件包路径 例如: ./plugins/karin-plugin-example */
|
|
99
|
+
const root = `${this.dir}/${dir}`;
|
|
135
100
|
/** 非插件包 加载该文件夹下全部js 视语言环境加载ts */
|
|
136
|
-
if (!common.isPlugin(
|
|
137
|
-
|
|
101
|
+
if (!common.isPlugin(root)) {
|
|
102
|
+
/** 热更新 */
|
|
103
|
+
this.watchList.push({ plugin: dir, path: '' });
|
|
104
|
+
list.push(...this.loadApps(dir, '', `${"js" /* AppsType.Js */}`));
|
|
138
105
|
continue;
|
|
139
106
|
}
|
|
140
107
|
/** package */
|
|
141
|
-
const pkg = common.readJson(`${
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
if (
|
|
159
|
-
this.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
108
|
+
const pkg = common.readJson(`${root}/package.json`);
|
|
109
|
+
this.loadMain(root, pkg.main, false);
|
|
110
|
+
/**
|
|
111
|
+
* 插件加载优先级:
|
|
112
|
+
* 1. ts环境: 按照 编译产物 > TS源代码 举例: 优先级高的不存在才会加载下一个。
|
|
113
|
+
* 2. js环境: 按照 pkg.apps 进行加载。 当前版本兼容apps,apps处于根目录并且没有在pkg.apps中填写会自动加载,后续废弃。
|
|
114
|
+
*
|
|
115
|
+
* 注: ts编译产物的路径也是根据pkg.apps进行加载的。
|
|
116
|
+
*
|
|
117
|
+
* 开发环境说明:
|
|
118
|
+
* 1. ts环境默认为开发模式
|
|
119
|
+
* 2. 在开发环境下 会对所有 `.js`,`.ts` 文件进行热更新 只需要点下保存即可。
|
|
120
|
+
* 3. 监察者模式当前暂未适配 待后续适配。
|
|
121
|
+
*/
|
|
122
|
+
/** ts环境 */
|
|
123
|
+
if (process.env.karin_app_lang === 'ts') {
|
|
124
|
+
/** 加载ts入口 */
|
|
125
|
+
if (pkg?.karin?.main)
|
|
126
|
+
this.loadMain(root, pkg.karin.main, false);
|
|
127
|
+
/** 获取apps */
|
|
128
|
+
const apps = pkg?.karin?.apps && Array.isArray(pkg.karin.apps) ? pkg.karin.apps : [];
|
|
129
|
+
/** apps为空则跳过 */
|
|
130
|
+
if (!apps.length)
|
|
131
|
+
continue;
|
|
132
|
+
const { outDir, rootDir } = await this.getTsMain(root, pkg);
|
|
133
|
+
/** 先瞅瞅编译产物根目录是否存在 */
|
|
134
|
+
if (common.exists(path.join(root, outDir))) {
|
|
135
|
+
for (const file of apps) {
|
|
136
|
+
const rootApps = path.join(root, outDir, file);
|
|
137
|
+
if (!common.exists(rootApps)) {
|
|
138
|
+
logger.debug(`[插件收集][${rootApps}] 路径不存在,已忽略`);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const _path = path.join(outDir, file);
|
|
142
|
+
/** 热更新 */
|
|
143
|
+
this.watchList.push({ plugin: dir, path: _path });
|
|
144
|
+
list.push(...this.loadApps(dir, _path, `${"git" /* AppsType.Git */}`));
|
|
173
145
|
}
|
|
174
|
-
|
|
175
|
-
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
/** 源码根目录 */
|
|
149
|
+
if (common.exists(path.join(root, rootDir))) {
|
|
150
|
+
for (const file of apps) {
|
|
151
|
+
const rootApps = path.join(root, rootDir, file);
|
|
152
|
+
if (!common.exists(rootApps)) {
|
|
153
|
+
logger.debug(`[插件收集][${rootApps}] 路径不存在,已忽略`);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const _path = path.join(rootDir, file);
|
|
157
|
+
/** 热更新 */
|
|
158
|
+
this.watchList.push({ plugin: dir, path: _path });
|
|
159
|
+
list.push(...this.loadApps(dir, _path, `${"git" /* AppsType.Git */}`));
|
|
176
160
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const outDir = pkg?.karin?.outDir || 'lib';
|
|
182
|
-
const rootDir = pkg?.karin?.rootDir || 'src';
|
|
183
|
-
/** 编译产物存在 */
|
|
184
|
-
if (common.exists(`${PluginPath}/${outDir}/apps`)) {
|
|
185
|
-
this.getApps((`${dir}/${outDir}/apps`), true, this.isDev);
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
/** 走到这说明有问题 打印错误信息 */
|
|
164
|
+
logger.error(`[插件收集][${dir}] 加载错误,未检测到任何文件,请检查配置是否正确`);
|
|
186
165
|
continue;
|
|
187
166
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
167
|
+
/** 全部apps路径 */
|
|
168
|
+
const apps = pkg?.karin?.apps && Array.isArray(pkg.karin.apps) ? pkg.karin.apps : [];
|
|
169
|
+
/** 暂时兼容旧版本 加入apps 计划在正式版本发布之前废弃 */
|
|
170
|
+
if (!apps.includes('apps'))
|
|
171
|
+
apps.push('apps');
|
|
172
|
+
for (const file of apps) {
|
|
173
|
+
const rootApps = path.join(root, file);
|
|
174
|
+
if (!common.exists(rootApps)) {
|
|
175
|
+
logger.debug(`[插件收集][${rootApps}] 路径不存在,已忽略`);
|
|
194
176
|
continue;
|
|
195
177
|
}
|
|
196
|
-
|
|
197
|
-
if (
|
|
198
|
-
|
|
199
|
-
|
|
178
|
+
const dev = process.env.karin_app_mode === 'dev';
|
|
179
|
+
if (dev) {
|
|
180
|
+
/** 热更新 */
|
|
181
|
+
this.watchList.push({ plugin: dir, path: file });
|
|
200
182
|
}
|
|
183
|
+
list.push(...this.loadApps(dir, file, `${"git" /* AppsType.Git */}`));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return list;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* 获取Npm插件
|
|
190
|
+
*/
|
|
191
|
+
async getNpmPlugin() {
|
|
192
|
+
const list = [];
|
|
193
|
+
const info = await common.getNpmPlugins(true);
|
|
194
|
+
for (const { plugin, path: _path, file, isMain } of info) {
|
|
195
|
+
if (!isMain) {
|
|
196
|
+
const root = path.join(process.cwd(), 'node_modules', plugin, _path);
|
|
197
|
+
this.loadMain(root, file, true);
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
list.push(this.createdApp(plugin, _path, file, `${"npm" /* AppsType.Npm */}`));
|
|
201
|
+
}
|
|
202
|
+
return list;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* 加载入口文件 只加载
|
|
206
|
+
* @param root - 插件根目录
|
|
207
|
+
* @param main - 入口文件
|
|
208
|
+
* @param isNpm - 是否为npm插件
|
|
209
|
+
*/
|
|
210
|
+
async loadMain(root, main, isNpm) {
|
|
211
|
+
const _path = path.resolve(root, main || '');
|
|
212
|
+
if (!common.exists(_path) || !main) {
|
|
213
|
+
if (isNpm)
|
|
214
|
+
return false;
|
|
215
|
+
const defRoot = path.resolve(root, 'index.js');
|
|
216
|
+
if (common.exists(defRoot)) {
|
|
217
|
+
await import(`file://${defRoot}`);
|
|
218
|
+
return true;
|
|
201
219
|
}
|
|
220
|
+
logger.debug(`[插件收集][${main}] 入口文件不存在,已忽略`);
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
await import(`file://${_path}`);
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* 获取ts插件入口 编译入口路径
|
|
228
|
+
* @param root - 插件根目录
|
|
229
|
+
* @param pkg - package.json
|
|
230
|
+
*/
|
|
231
|
+
async getTsMain(root, pkg) {
|
|
232
|
+
let outDir = 'dist';
|
|
233
|
+
let rootDir = 'src';
|
|
234
|
+
/** 先尝试解析tsconfig.json来进行读取 */
|
|
235
|
+
try {
|
|
236
|
+
const tsconfig = common.readJson(`${root}/tsconfig.json`);
|
|
237
|
+
if (tsconfig?.compilerOptions?.outDir)
|
|
238
|
+
outDir = tsconfig.compilerOptions.outDir;
|
|
239
|
+
if (tsconfig?.compilerOptions?.rootDir)
|
|
240
|
+
rootDir = tsconfig.compilerOptions.rootDir;
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
logger.error(`[插件收集][${root}] tsconfig.json解析错误,请检查格式`);
|
|
244
|
+
logger.error(error);
|
|
245
|
+
/** 如果报错 则读取pkg的 */
|
|
246
|
+
if (pkg?.karin?.outDir)
|
|
247
|
+
outDir = pkg.karin.outDir;
|
|
248
|
+
if (pkg?.karin?.rootDir)
|
|
249
|
+
rootDir = pkg.karin.rootDir;
|
|
202
250
|
}
|
|
203
|
-
return
|
|
251
|
+
return { outDir, rootDir };
|
|
204
252
|
}
|
|
205
253
|
/**
|
|
206
|
-
*
|
|
207
|
-
* @param
|
|
208
|
-
* @param
|
|
254
|
+
* 加载指定文件夹下的所有插件
|
|
255
|
+
* @param plugin - 插件名称
|
|
256
|
+
* @param _path - 插件apps相对路径
|
|
257
|
+
* @param file - 插件文件名称
|
|
258
|
+
* @param isNpm - 是否为npm插件
|
|
259
|
+
* @param isWatch - 是否监听热更新
|
|
209
260
|
*/
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const
|
|
213
|
-
const
|
|
214
|
-
for (const file of
|
|
261
|
+
loadApps(plugin, _path, type) {
|
|
262
|
+
const list = [];
|
|
263
|
+
const root = type === 'npm' ? path.join(process.cwd(), 'node_modules', plugin, _path) : path.join(this.dir, plugin, _path);
|
|
264
|
+
const files = fs.readdirSync(root, { withFileTypes: true });
|
|
265
|
+
for (const file of files) {
|
|
215
266
|
const extname = path.extname(file.name);
|
|
216
|
-
if (!ext.includes(extname))
|
|
267
|
+
if (!this.ext.includes(extname))
|
|
217
268
|
continue;
|
|
218
|
-
|
|
269
|
+
list.push(this.createdApp(plugin, _path, file.name, type));
|
|
219
270
|
}
|
|
271
|
+
return list;
|
|
220
272
|
}
|
|
221
273
|
/**
|
|
222
274
|
* 排序并打印插件信息
|
|
223
275
|
* @param isPrint - 是否打印
|
|
224
276
|
*/
|
|
225
277
|
orderBy(isPrint = false) {
|
|
226
|
-
let taskCount = 0;
|
|
227
278
|
let handlerCount = 0;
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
279
|
+
this.accept = lodash.orderBy(this.accept, ['rank'], ['asc']);
|
|
280
|
+
this.button = lodash.orderBy(this.button, ['rank'], ['asc']);
|
|
281
|
+
this.command = lodash.orderBy(this.command, ['rank'], ['asc']);
|
|
282
|
+
this.task = lodash.orderBy(this.task, ['rank'], ['asc']);
|
|
283
|
+
this.use.recvMsg = lodash.orderBy(this.use.recvMsg, ['rank'], ['asc']);
|
|
284
|
+
this.use.replyMsg = lodash.orderBy(this.use.replyMsg, ['rank'], ['asc']);
|
|
285
|
+
this.use.sendMsg = lodash.orderBy(this.use.sendMsg, ['rank'], ['asc']);
|
|
286
|
+
const handler = Object.keys(this.handler);
|
|
287
|
+
handler.forEach(key => {
|
|
288
|
+
this.handler[key] = lodash.orderBy(this.handler[key], ['rank'], ['asc']);
|
|
289
|
+
handlerCount += this.handler[key].length;
|
|
239
290
|
});
|
|
240
|
-
this.ruleIds = lodash.orderBy(rule, ['val'], ['asc']).map((v) => Number(v.key));
|
|
241
|
-
logger.debug('rule排序完成...');
|
|
242
|
-
this.buttonIds = lodash.orderBy(button, ['val'], ['asc']).map((v) => Number(v.key));
|
|
243
|
-
logger.debug('button排序完成...');
|
|
244
|
-
this.acceptIds = lodash.orderBy(accept, ['val'], ['asc']).map((v) => Number(v.key));
|
|
245
291
|
if (!isPrint)
|
|
246
292
|
return;
|
|
247
|
-
|
|
248
|
-
const handlerKeys = Object.keys(this.handlerIds);
|
|
249
|
-
handlerKeys.forEach((key) => {
|
|
250
|
-
handlerCount += this.handlerIds[key].length;
|
|
251
|
-
});
|
|
252
|
-
logger.info(`[插件][${PluginListKeys.length}个] 加载完成`);
|
|
293
|
+
logger.info(`[插件][${Object.keys(this.plugin).length}个] 加载完成`);
|
|
253
294
|
logger.info(`[渲染器][${render.Apps.length}个] 加载完成`);
|
|
254
|
-
logger.info(`[
|
|
255
|
-
logger.info(`[button][${this.
|
|
256
|
-
logger.info(`[accept][${this.
|
|
257
|
-
logger.info(`[定时任务][${
|
|
258
|
-
logger.info(`[Handler][Key:${
|
|
295
|
+
logger.info(`[command][${this.command.length}个] 加载完成`);
|
|
296
|
+
logger.info(`[button][${this.button.length}个] 加载完成`);
|
|
297
|
+
logger.info(`[accept][${this.accept.length}个] 加载完成`);
|
|
298
|
+
logger.info(`[定时任务][${this.task.length}个] 加载完成`);
|
|
299
|
+
logger.info(`[Handler][Key:${handler.length}个][fnc:${handlerCount}个] 加载完成`);
|
|
259
300
|
logger.info(logger.green('-----------'));
|
|
260
301
|
logger.info(`Karin启动完成:耗时 ${logger.green(process.uptime().toFixed(2))} 秒...`);
|
|
261
302
|
}
|
|
262
303
|
/**
|
|
263
304
|
* 新增插件
|
|
264
|
-
* @param
|
|
265
|
-
* @param
|
|
266
|
-
* @param
|
|
267
|
-
* @param
|
|
268
|
-
* @param
|
|
305
|
+
* @param plugin - 插件名称 例如: karin-plugin-example
|
|
306
|
+
* @param _path - 插件路径 例如: lib/apps 不存在则传空字符串
|
|
307
|
+
* @param file - 插件文件 例如: index.js ts目前解释器支持不够,暂不支持ts
|
|
308
|
+
* @param type - 插件类型 默认为git
|
|
309
|
+
* @param isOrderBy - 是否排序 开启会使用动态导入
|
|
269
310
|
*/
|
|
270
|
-
async createdApp(
|
|
311
|
+
async createdApp(plugin, _path, file, type = 'git', isOrderBy = false) {
|
|
271
312
|
try {
|
|
313
|
+
const index = ++this.index;
|
|
314
|
+
/** 缓存基本信息 */
|
|
315
|
+
this.plugin[index] = { type, plugin, path: _path, file };
|
|
272
316
|
const list = [];
|
|
273
|
-
let
|
|
317
|
+
let rootPath = 'file://' + path.join(process.cwd(), type === 'npm' ? 'node_modules' : 'plugins', plugin, _path, file);
|
|
274
318
|
if (isOrderBy)
|
|
275
|
-
|
|
276
|
-
const tmp = await import(
|
|
277
|
-
|
|
278
|
-
if (isMain)
|
|
279
|
-
return true;
|
|
280
|
-
lodash.forEach(tmp, (App) => {
|
|
319
|
+
rootPath = rootPath + `?${Date.now()}`;
|
|
320
|
+
const tmp = await import(rootPath);
|
|
321
|
+
lodash.forEach(tmp, (Fn) => {
|
|
281
322
|
const index = this.index;
|
|
282
323
|
this.index++;
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
App.file.dir = dir;
|
|
289
|
-
App.file.name = name;
|
|
290
|
-
App.rule.forEach((v, index) => {
|
|
291
|
-
App.rule[index].log = v.log === false ? (id, log) => logger.bot('debug', id, log) : (id, log) => logger.bot('mark', id, log);
|
|
292
|
-
});
|
|
293
|
-
/** handler */
|
|
294
|
-
App.task = this.addTaskFnc(dir, App);
|
|
295
|
-
this.PluginList[index] = App;
|
|
296
|
-
handler.add(index + '', App);
|
|
297
|
-
if (App.accept)
|
|
298
|
-
this.acceptIds.push(index);
|
|
324
|
+
/** 函数语法糖 */
|
|
325
|
+
if (typeof Fn === 'object' && Fn?.type) {
|
|
326
|
+
logger.debug(`载入插件 [${plugin}]${_path ? `${common.getRelPath(_path)}` : ''}[${file}][${Fn.name}]`);
|
|
327
|
+
list.push(this.cachePlugin(index, plugin, file, Fn));
|
|
299
328
|
return true;
|
|
300
329
|
}
|
|
301
|
-
if (typeof
|
|
330
|
+
if (typeof Fn !== 'function' || !Fn?.prototype?.constructor)
|
|
302
331
|
return false;
|
|
303
|
-
const Class = new
|
|
332
|
+
const Class = new Fn();
|
|
304
333
|
if (!Class.name) {
|
|
305
|
-
logger.error(`[${
|
|
334
|
+
logger.error(`[${plugin}]${_path ? `${common.getRelPath(_path)}` : ''}[${file}] 插件名称错误`);
|
|
306
335
|
return false;
|
|
307
336
|
}
|
|
308
|
-
logger.debug(`载入插件 [${
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
337
|
+
logger.debug(`载入插件 [${plugin}]${_path ? `${common.getRelPath(_path)}` : ''}[${file}][${Class.name}]`);
|
|
338
|
+
if (Class.rule.length) {
|
|
339
|
+
for (const val of Class.rule) {
|
|
340
|
+
list.push(() => {
|
|
341
|
+
const log = val.log === false
|
|
342
|
+
? (id, log) => logger.debug('mark', id, log)
|
|
343
|
+
: (id, log) => logger.bot('mark', id, log);
|
|
344
|
+
const fn = typeof val.fnc === 'function' ? val.fnc : Class[val.fnc];
|
|
345
|
+
return this.cachePlugin(index, plugin, file, {
|
|
346
|
+
name: Class.name,
|
|
347
|
+
type: 'command',
|
|
348
|
+
fn,
|
|
349
|
+
fnname: typeof val.fnc === 'function' ? val.fnc.name || 'fnc' : val.fnc,
|
|
350
|
+
data: Fn,
|
|
351
|
+
event: val.event || Class.event || 'message',
|
|
352
|
+
log,
|
|
353
|
+
perm: val.permission || "all" /* Permission.All */,
|
|
354
|
+
rank: val.priority || Class.priority || 10000,
|
|
355
|
+
reg: val.reg instanceof RegExp ? val.reg : new RegExp(val.reg),
|
|
356
|
+
}, Fn);
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (Class.task.length) {
|
|
361
|
+
for (const val of Class.task) {
|
|
362
|
+
list.push(() => {
|
|
363
|
+
if (!val.name)
|
|
364
|
+
throw TypeError(`[${plugin}][${file}] 定时任务name错误`);
|
|
365
|
+
if (!val.cron)
|
|
366
|
+
throw TypeError(`[${plugin}][${file}] 定时任务cron错误:${Class.name}`);
|
|
367
|
+
const log = val.log === false ? (log) => logger.debug(log) : (log) => logger.mark(log);
|
|
368
|
+
return this.cachePlugin(index, plugin, file, {
|
|
369
|
+
name: Class.name,
|
|
370
|
+
fnname: val.name,
|
|
371
|
+
type: 'task',
|
|
372
|
+
fn: typeof val.fnc === 'function' ? val.fnc : Class[val.fnc],
|
|
373
|
+
log,
|
|
374
|
+
cron: val.cron,
|
|
375
|
+
}, Fn);
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
/** init */
|
|
380
|
+
list.push(async () => {
|
|
381
|
+
'init' in Class && typeof Class.init === 'function' && await Class.init();
|
|
315
382
|
});
|
|
316
|
-
/** 异步收集 加载速度 */
|
|
317
|
-
list.push(this.addRule(dir, name, index, Class));
|
|
318
|
-
list.push(this.addTask(dir, name, index, Class, App));
|
|
319
|
-
list.push(this.addAccept(index, Class));
|
|
320
|
-
list.push(this.addButton(dir, name, index, Class));
|
|
321
|
-
list.push(this.addInit(Class));
|
|
322
383
|
return true;
|
|
323
384
|
});
|
|
324
385
|
await Promise.all(list);
|
|
@@ -329,22 +390,121 @@ class PluginLoader {
|
|
|
329
390
|
}
|
|
330
391
|
catch (error) {
|
|
331
392
|
if (/Cannot find package '(.+?)'/.exec(error)?.[1]) {
|
|
332
|
-
const key = `${
|
|
393
|
+
const key = `${plugin}.${_path}.${file}`;
|
|
333
394
|
if (this.dependErr[key])
|
|
334
395
|
return false;
|
|
335
396
|
this.dependErr[key] = {
|
|
336
|
-
|
|
337
|
-
|
|
397
|
+
plugin,
|
|
398
|
+
path: _path,
|
|
399
|
+
file,
|
|
338
400
|
depend: /Cannot find package '(.+?)'/.exec(error)?.[1] || '',
|
|
339
401
|
};
|
|
340
402
|
}
|
|
341
403
|
else {
|
|
342
|
-
logger.error(`载入插件错误:${logger.red(`${
|
|
404
|
+
logger.error(`载入插件错误:${logger.red(`${plugin}/${_path}/${file}`)}`);
|
|
343
405
|
logger.error(error);
|
|
344
406
|
}
|
|
345
407
|
return false;
|
|
346
408
|
}
|
|
347
409
|
}
|
|
410
|
+
/**
|
|
411
|
+
* 缓存插件
|
|
412
|
+
* @param index - 插件索引
|
|
413
|
+
*/
|
|
414
|
+
async cachePlugin(index, plugin, file, info, App) {
|
|
415
|
+
if (!info?.name) {
|
|
416
|
+
logger.error(`[${plugin}][${file}][${info.name}] 插件名称错误`);
|
|
417
|
+
return false;
|
|
418
|
+
}
|
|
419
|
+
switch (info.type) {
|
|
420
|
+
case 'accept': {
|
|
421
|
+
this.accept.push({
|
|
422
|
+
name: info.name,
|
|
423
|
+
event: info.event,
|
|
424
|
+
fn: info.fn,
|
|
425
|
+
key: index + '',
|
|
426
|
+
log: info.log,
|
|
427
|
+
rank: info.rank,
|
|
428
|
+
});
|
|
429
|
+
return true;
|
|
430
|
+
}
|
|
431
|
+
case 'button': {
|
|
432
|
+
this.button.push({
|
|
433
|
+
name: info.name,
|
|
434
|
+
reg: info.reg,
|
|
435
|
+
fn: info.fn,
|
|
436
|
+
key: index + '',
|
|
437
|
+
rank: info.rank,
|
|
438
|
+
});
|
|
439
|
+
return true;
|
|
440
|
+
}
|
|
441
|
+
case 'handler': {
|
|
442
|
+
if (!this.handler[info.key])
|
|
443
|
+
this.handler[info.key] = [];
|
|
444
|
+
this.handler[info.key].push({
|
|
445
|
+
name: info.name,
|
|
446
|
+
fn: info.fn,
|
|
447
|
+
key: index + '',
|
|
448
|
+
rank: info.rank,
|
|
449
|
+
});
|
|
450
|
+
return true;
|
|
451
|
+
}
|
|
452
|
+
case 'command': {
|
|
453
|
+
this.command.push({
|
|
454
|
+
name: info.name,
|
|
455
|
+
data: App,
|
|
456
|
+
event: info.event,
|
|
457
|
+
fn: info.fn,
|
|
458
|
+
fnname: info.fnname,
|
|
459
|
+
key: index + '',
|
|
460
|
+
log: info.log,
|
|
461
|
+
perm: info.perm,
|
|
462
|
+
rank: info.rank,
|
|
463
|
+
reg: info.reg,
|
|
464
|
+
type: 'function',
|
|
465
|
+
});
|
|
466
|
+
return true;
|
|
467
|
+
}
|
|
468
|
+
case 'task': {
|
|
469
|
+
this.task.push({
|
|
470
|
+
name: info.name,
|
|
471
|
+
cron: info.cron,
|
|
472
|
+
fn: info.fn,
|
|
473
|
+
key: index + '',
|
|
474
|
+
taskname: info.fnname,
|
|
475
|
+
data: App,
|
|
476
|
+
log: info.log,
|
|
477
|
+
schedule: schedule.scheduleJob(info.cron, async () => {
|
|
478
|
+
try {
|
|
479
|
+
info.log(`[定时任务][${plugin}][${info.fnname}] 开始执行`);
|
|
480
|
+
if (App) {
|
|
481
|
+
const app = new App();
|
|
482
|
+
await info.fn.call(app);
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
await info.fn();
|
|
486
|
+
}
|
|
487
|
+
info.log(`[定时任务][${plugin}][${info.fnname}] 执行完毕`);
|
|
488
|
+
}
|
|
489
|
+
catch (error) {
|
|
490
|
+
logger.error(`[定时任务][${plugin}][${info.fnname}] 执行报错`);
|
|
491
|
+
logger.error(error);
|
|
492
|
+
}
|
|
493
|
+
}),
|
|
494
|
+
});
|
|
495
|
+
return true;
|
|
496
|
+
}
|
|
497
|
+
case 'use': {
|
|
498
|
+
this.use[info.key].push({
|
|
499
|
+
name: info.name,
|
|
500
|
+
fn: info.fn,
|
|
501
|
+
key: index + '',
|
|
502
|
+
rank: info.rank,
|
|
503
|
+
});
|
|
504
|
+
return true;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
348
508
|
/**
|
|
349
509
|
* 打印依赖缺失
|
|
350
510
|
*/
|
|
@@ -355,8 +515,8 @@ class PluginLoader {
|
|
|
355
515
|
return;
|
|
356
516
|
const msg = ['-----依赖缺失----'];
|
|
357
517
|
keys.forEach(key => {
|
|
358
|
-
const {
|
|
359
|
-
msg.push(`[${
|
|
518
|
+
const { plugin, path, file, depend } = this.dependErr[key];
|
|
519
|
+
msg.push(`[${plugin}]${path ? `[${path}]` : ''}[${file}] 缺少依赖:${logger.red(depend)}`);
|
|
360
520
|
});
|
|
361
521
|
msg.push('-------------------');
|
|
362
522
|
logger.error(msg.join('\n'));
|
|
@@ -367,209 +527,85 @@ class PluginLoader {
|
|
|
367
527
|
}
|
|
368
528
|
}
|
|
369
529
|
/**
|
|
370
|
-
*
|
|
371
|
-
*/
|
|
372
|
-
async addRule(dir, name, index, Class) {
|
|
373
|
-
lodash.forEach(Class.rule, val => {
|
|
374
|
-
if (!val.fnc)
|
|
375
|
-
return logger.error(`[${dir}][${name}] rule.fnc错误:${Class.name}`);
|
|
376
|
-
this.PluginList[index].rule.push({
|
|
377
|
-
reg: val.reg instanceof RegExp ? val.reg : new RegExp(val.reg),
|
|
378
|
-
fnc: val.fnc,
|
|
379
|
-
event: val.event,
|
|
380
|
-
permission: val.permission || "all" /* Permission.All */,
|
|
381
|
-
log: val.log === false ? (id, log) => logger.debug('mark', id, log) : (id, log) => logger.bot('mark', id, log),
|
|
382
|
-
});
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
/**
|
|
386
|
-
* 新增task fnc模式
|
|
530
|
+
* 卸载插件
|
|
387
531
|
*/
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
logger.error(error);
|
|
532
|
+
uninstallApp(plugin, _path, file) {
|
|
533
|
+
Object.keys(this.plugin).forEach(key => {
|
|
534
|
+
const info = this.plugin[key];
|
|
535
|
+
if (info.plugin === plugin && info.path === _path && info.file === file) {
|
|
536
|
+
/** 删除缓存 */
|
|
537
|
+
delete this.plugin[key];
|
|
538
|
+
this.accept = this.accept.filter(val => val.key !== key);
|
|
539
|
+
this.button = this.button.filter(val => val.key !== key);
|
|
540
|
+
this.command = this.command.filter(val => val.key !== key);
|
|
541
|
+
this.use.recvMsg = this.use.recvMsg.filter(val => val.key !== key);
|
|
542
|
+
this.use.replyMsg = this.use.replyMsg.filter(val => val.key !== key);
|
|
543
|
+
this.use.sendMsg = this.use.sendMsg.filter(val => val.key !== key);
|
|
544
|
+
/** 定时任务需要先停止 */
|
|
545
|
+
this.task = this.task.filter(val => {
|
|
546
|
+
if (val.key === key) {
|
|
547
|
+
val.schedule?.cancel();
|
|
548
|
+
return false;
|
|
406
549
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
/** 定时任务 */
|
|
418
|
-
lodash.forEach(Class.task, val => {
|
|
419
|
-
if (!val.name)
|
|
420
|
-
return logger.error(`[${dir}][${name}] 定时任务name错误`);
|
|
421
|
-
if (!val.cron)
|
|
422
|
-
return logger.error(`[${dir}][${name}] 定时任务cron错误:${Class.name}`);
|
|
423
|
-
this.PluginList[index].task.push({
|
|
424
|
-
name: val.name,
|
|
425
|
-
cron: val.cron,
|
|
426
|
-
fnc: val.fnc,
|
|
427
|
-
log: val.log === false ? (log) => logger.debug(log) : (log) => logger.mark(log),
|
|
428
|
-
schedule: schedule.scheduleJob(val.cron, async () => {
|
|
429
|
-
try {
|
|
430
|
-
typeof val.log === 'function' && val.log(`[定时任务][${dir}][${val.name}] 开始执行`);
|
|
431
|
-
if (typeof val.fnc === 'function') {
|
|
432
|
-
await val.fnc();
|
|
433
|
-
}
|
|
434
|
-
else {
|
|
435
|
-
const cla = new App();
|
|
436
|
-
await cla[val.fnc]();
|
|
550
|
+
return true;
|
|
551
|
+
});
|
|
552
|
+
/** 处理handler */
|
|
553
|
+
Object.keys(this.handler).forEach(keys => {
|
|
554
|
+
this.handler[keys].forEach((val, i) => {
|
|
555
|
+
if (val.key === key) {
|
|
556
|
+
this.handler[keys].splice(i, 1);
|
|
557
|
+
if (!this.handler[keys].length)
|
|
558
|
+
delete this.handler[keys];
|
|
559
|
+
return true;
|
|
437
560
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
catch (error) {
|
|
441
|
-
logger.error(`[定时任务][${dir}][${val.name}] 执行报错`);
|
|
442
|
-
logger.error(error);
|
|
443
|
-
}
|
|
444
|
-
}),
|
|
445
|
-
});
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
/**
|
|
449
|
-
* 新增accept、handler
|
|
450
|
-
*/
|
|
451
|
-
async addAccept(index, Class) {
|
|
452
|
-
if ('accept' in Class && typeof Class.accept === 'function') {
|
|
453
|
-
this.PluginList[index].accept = true;
|
|
454
|
-
this.acceptIds.push(index);
|
|
455
|
-
}
|
|
456
|
-
await handler.add(index + '', Class);
|
|
457
|
-
}
|
|
458
|
-
/**
|
|
459
|
-
* 新增button
|
|
460
|
-
*/
|
|
461
|
-
async addButton(dir, name, index, Class) {
|
|
462
|
-
lodash.forEach(Class.button, val => {
|
|
463
|
-
if (!val.fnc)
|
|
464
|
-
return logger.error(`[${dir}][${name}] button.fnc错误:${Class.name}`);
|
|
465
|
-
this.PluginList[index].button.push({
|
|
466
|
-
reg: val.reg instanceof RegExp ? val.reg : new RegExp(val.reg),
|
|
467
|
-
fnc: val.fnc,
|
|
468
|
-
});
|
|
469
|
-
});
|
|
470
|
-
}
|
|
471
|
-
/**
|
|
472
|
-
* 执行初始化
|
|
473
|
-
*/
|
|
474
|
-
async addInit(Class) {
|
|
475
|
-
'init' in Class && typeof Class.init === 'function' && await Class.init();
|
|
476
|
-
}
|
|
477
|
-
/**
|
|
478
|
-
* 卸载插件
|
|
479
|
-
*/
|
|
480
|
-
uninstallApp(dir, name) {
|
|
481
|
-
const index = [];
|
|
482
|
-
Object.keys(this.PluginList).forEach(key => {
|
|
483
|
-
const info = this.PluginList[key];
|
|
484
|
-
/** 停止定时任务 */
|
|
485
|
-
info.task.forEach(val => val.schedule?.cancel());
|
|
486
|
-
if (info.file.dir === dir && info.file.name === name) {
|
|
487
|
-
index.push(key);
|
|
488
|
-
delete this.PluginList[key];
|
|
561
|
+
});
|
|
562
|
+
});
|
|
489
563
|
}
|
|
490
564
|
});
|
|
491
|
-
/** 删除handler */
|
|
492
|
-
index.forEach(key => handler.del(key));
|
|
493
565
|
/** 重新排序 */
|
|
494
566
|
this.orderBy();
|
|
495
567
|
}
|
|
496
|
-
/**
|
|
497
|
-
* 监听单个文件热更新
|
|
498
|
-
*/
|
|
499
|
-
watch(dir, name) {
|
|
500
|
-
if (this.watcher.get(`${dir}.${name}`))
|
|
501
|
-
return;
|
|
502
|
-
const file = `./plugins/${dir}/${name}`;
|
|
503
|
-
const watcher = chokidar.watch(file);
|
|
504
|
-
/** 监听修改 */
|
|
505
|
-
watcher.on('change', async () => {
|
|
506
|
-
/** 卸载 */
|
|
507
|
-
this.uninstallApp(dir, name);
|
|
508
|
-
/** 载入插件 */
|
|
509
|
-
await this.createdApp(dir, name, true);
|
|
510
|
-
logger.mark(`[修改插件][${dir}][${name}]`);
|
|
511
|
-
});
|
|
512
|
-
/** 监听删除 */
|
|
513
|
-
watcher.on('unlink', async () => {
|
|
514
|
-
/** 卸载 */
|
|
515
|
-
this.uninstallApp(dir, name);
|
|
516
|
-
this.watcher.delete(`${dir}.${name}`);
|
|
517
|
-
logger.mark(`[卸载插件][${dir}][${name}]`);
|
|
518
|
-
/** 卸载之后停止监听 */
|
|
519
|
-
watcher.close();
|
|
520
|
-
});
|
|
521
|
-
this.watcher.set(`${dir}.${name}`, watcher);
|
|
522
|
-
}
|
|
523
568
|
/**
|
|
524
569
|
* 监听文件夹更新
|
|
525
570
|
*/
|
|
526
|
-
async watchDir(
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
const watcher = chokidar.watch(
|
|
571
|
+
async watchDir(plugin, _path) {
|
|
572
|
+
const root = path.join(this.dir, plugin, _path);
|
|
573
|
+
if (this.watcher.get(root))
|
|
574
|
+
return false;
|
|
575
|
+
const watcher = chokidar.watch(root);
|
|
531
576
|
await common.sleep(1000);
|
|
532
|
-
watcher.on('add', async (
|
|
577
|
+
watcher.on('add', async (files) => {
|
|
533
578
|
/** 排除掉不符合规则文件新增 */
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
logger.mark(`[新增插件][${dir}][${name}]`);
|
|
579
|
+
if (!this.ext.some(ext => files.endsWith(ext)))
|
|
580
|
+
return false;
|
|
581
|
+
const name = path.basename(files);
|
|
582
|
+
await this.createdApp(plugin, _path, name, `${"git" /* AppsType.Git */}`, true);
|
|
583
|
+
logger.mark(`[新增插件][${plugin}]${path ? `${common.getRelPath(_path)}` : ''}[${name}]`);
|
|
540
584
|
return true;
|
|
541
585
|
});
|
|
542
|
-
watcher.on('change', async (
|
|
586
|
+
watcher.on('change', async (files) => {
|
|
543
587
|
/** 排除掉不符合规则文件新增 */
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
const name = path.basename(_path);
|
|
588
|
+
if (!this.ext.some(ext => files.endsWith(ext)))
|
|
589
|
+
return false;
|
|
590
|
+
const name = path.basename(files);
|
|
548
591
|
/** 卸载 */
|
|
549
|
-
this.uninstallApp(
|
|
592
|
+
this.uninstallApp(plugin, _path, name);
|
|
550
593
|
/** 载入插件 */
|
|
551
|
-
await this.createdApp(
|
|
552
|
-
logger.mark(`[修改插件][${
|
|
594
|
+
await this.createdApp(plugin, _path, name, `${"git" /* AppsType.Git */}`, true);
|
|
595
|
+
logger.mark(`[修改插件][${plugin}]${path ? `${common.getRelPath(_path)}` : ''}[${name}]`);
|
|
553
596
|
return true;
|
|
554
597
|
});
|
|
555
|
-
watcher.on('unlink', async (
|
|
598
|
+
watcher.on('unlink', async (files) => {
|
|
556
599
|
/** 排除掉不符合规则文件新增 */
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
const name = path.basename(_path);
|
|
600
|
+
if (!this.ext.some(ext => files.endsWith(ext)))
|
|
601
|
+
return false;
|
|
602
|
+
const name = path.basename(files);
|
|
561
603
|
/** 卸载 */
|
|
562
|
-
this.uninstallApp(
|
|
563
|
-
logger.mark(`[卸载插件][${
|
|
604
|
+
this.uninstallApp(plugin, _path, name);
|
|
605
|
+
logger.mark(`[卸载插件][${plugin}]${path ? `${common.getRelPath(_path)}` : ''}[${name}]`);
|
|
564
606
|
return true;
|
|
565
607
|
});
|
|
566
|
-
|
|
567
|
-
const isExist = this.watcher.get(dir);
|
|
568
|
-
if (isExist) {
|
|
569
|
-
isExist.close();
|
|
570
|
-
this.watcher.delete(dir);
|
|
571
|
-
}
|
|
572
|
-
this.watcher.set(dir, watcher);
|
|
608
|
+
this.watcher.set(root, watcher);
|
|
573
609
|
return true;
|
|
574
610
|
}
|
|
575
611
|
}
|