node-karin 0.6.7 → 0.6.10
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/lib/adapter/input/index.d.ts +1 -0
- package/lib/adapter/input/index.js +35 -34
- package/lib/adapter/kritor/grpc.d.ts +0 -1
- package/lib/adapter/kritor/grpc.js +3 -3
- package/lib/adapter/kritor/index.js +7 -2
- package/lib/adapter/onebot/onebot11.d.ts +3 -3
- package/lib/adapter/onebot/onebot11.js +23 -40
- package/lib/core/karin.js +16 -28
- package/lib/core/listener.js +5 -6
- package/lib/core/plugin.d.ts +2 -2
- package/lib/core/plugin.loader.d.ts +47 -10
- package/lib/core/plugin.loader.js +172 -100
- package/lib/core/process.js +1 -1
- package/lib/core/server.d.ts +1 -1
- package/lib/core/server.js +4 -1
- package/lib/db/redis.js +4 -5
- package/lib/index.d.ts +0 -1
- package/lib/types/adapter.d.ts +4 -0
- package/lib/types/plugin.d.ts +2 -5
- package/lib/types/render.d.ts +2 -1
- package/lib/types/reply.d.ts +4 -1
- package/lib/utils/handler.d.ts +1 -1
- package/lib/utils/handler.js +1 -1
- package/lib/utils/update.d.ts +0 -5
- package/lib/utils/update.js +0 -17
- package/package.json +3 -2
|
@@ -4,36 +4,11 @@ import { listener } from '../../core/index.js';
|
|
|
4
4
|
import { KarinMessage } from '../../event/index.js';
|
|
5
5
|
import { config, common, YamlEditor } from '../../utils/index.js';
|
|
6
6
|
const { enable, msgToFile, token: oldToken, ip } = config.Config.AdapterInput;
|
|
7
|
-
let token = oldToken;
|
|
8
|
-
if (oldToken === 'AdapterInput') {
|
|
9
|
-
try {
|
|
10
|
-
token = randomUUID();
|
|
11
|
-
const yaml = new YamlEditor('./config/config/config.yaml');
|
|
12
|
-
const data = yaml.get('AdapterInput');
|
|
13
|
-
if (!data) {
|
|
14
|
-
const yaml1 = new YamlEditor('./config/defSet/config.yaml');
|
|
15
|
-
const data1 = yaml1.get('AdapterInput');
|
|
16
|
-
data1.token = token;
|
|
17
|
-
yaml.set('AdapterInput', data1);
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
data.token = token;
|
|
21
|
-
yaml.set('AdapterInput', data);
|
|
22
|
-
}
|
|
23
|
-
yaml.save();
|
|
24
|
-
}
|
|
25
|
-
catch (e) {
|
|
26
|
-
logger.error('AdapterInput token更换失败,请手动更换token');
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
// 清空文件夹
|
|
30
|
-
fs.readdirSync('./temp/input').forEach((file) => {
|
|
31
|
-
fs.unlinkSync(`./temp/input/${file}`);
|
|
32
|
-
});
|
|
33
7
|
/**
|
|
34
8
|
* - 标准输入输出适配器
|
|
35
9
|
*/
|
|
36
10
|
export class AdapterInput {
|
|
11
|
+
token;
|
|
37
12
|
#stdin;
|
|
38
13
|
socket;
|
|
39
14
|
account;
|
|
@@ -41,8 +16,9 @@ export class AdapterInput {
|
|
|
41
16
|
version;
|
|
42
17
|
constructor() {
|
|
43
18
|
this.#stdin = false;
|
|
19
|
+
this.token = oldToken;
|
|
44
20
|
this.account = { uid: 'input', uin: 'input', name: 'input' };
|
|
45
|
-
this.adapter = { id: 'shell', name: 'input', type: 'internal', sub_type: 'internal', start_time: Date.now(), connect: '' };
|
|
21
|
+
this.adapter = { id: 'shell', name: 'input', type: 'internal', sub_type: 'internal', start_time: Date.now(), connect: '', index: 0 };
|
|
46
22
|
this.version = { name: 'input', app_name: 'input', version: '1.0.0' };
|
|
47
23
|
}
|
|
48
24
|
get self_id() {
|
|
@@ -52,6 +28,35 @@ export class AdapterInput {
|
|
|
52
28
|
if (this.#stdin)
|
|
53
29
|
return;
|
|
54
30
|
this.#stdin = true;
|
|
31
|
+
if (oldToken === 'AdapterInput') {
|
|
32
|
+
try {
|
|
33
|
+
this.token = randomUUID();
|
|
34
|
+
const yaml = new YamlEditor('./config/config/config.yaml');
|
|
35
|
+
const data = yaml.get('AdapterInput');
|
|
36
|
+
if (!data) {
|
|
37
|
+
const yaml1 = new YamlEditor('./config/defSet/config.yaml');
|
|
38
|
+
const data1 = yaml1.get('AdapterInput');
|
|
39
|
+
data1.token = this.token;
|
|
40
|
+
yaml.set('AdapterInput', data1);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
data.token = this.token;
|
|
44
|
+
yaml.set('AdapterInput', data);
|
|
45
|
+
}
|
|
46
|
+
yaml.save();
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
logger.error('AdapterInput token更换失败,请手动更换token');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// 清空文件夹
|
|
53
|
+
fs.readdirSync('./temp/input').forEach((file) => {
|
|
54
|
+
fs.unlinkSync(`./temp/input/${file}`);
|
|
55
|
+
});
|
|
56
|
+
/** 注册bot */
|
|
57
|
+
const index = listener.addBot({ bot: this, type: this.adapter.type });
|
|
58
|
+
if (index)
|
|
59
|
+
this.adapter.index = index;
|
|
55
60
|
process.stdin.on('data', data => this.#input(data.toString()));
|
|
56
61
|
process.once('stdin.close', () => process.stdin.removeAllListeners('data'));
|
|
57
62
|
}
|
|
@@ -108,7 +113,7 @@ export class AdapterInput {
|
|
|
108
113
|
const name = `${Date.now()}.${type === 'image' ? 'jpg' : type === 'voice' ? 'mp3' : 'file'}`;
|
|
109
114
|
// 写入文件
|
|
110
115
|
fs.writeFileSync(`./temp/input/${name}`, buffer);
|
|
111
|
-
return `[${type === 'image' ? '图片' : '语音'}: http://${ip}:${config.Server.http.port}/api/input?name=${name}&token=${token} ]`;
|
|
116
|
+
return `[${type === 'image' ? '图片' : '语音'}: http://${ip}:${config.Server.http.port}/api/input?name=${name}&token=${this.token} ]`;
|
|
112
117
|
}
|
|
113
118
|
async GetVersion() {
|
|
114
119
|
const data = this.version;
|
|
@@ -181,9 +186,5 @@ export class AdapterInput {
|
|
|
181
186
|
async GetGroupMemberList() { throw new Error('Method not implemented.'); }
|
|
182
187
|
async GetGroupHonor() { throw new Error('Method not implemented.'); }
|
|
183
188
|
}
|
|
184
|
-
if (enable)
|
|
185
|
-
|
|
186
|
-
bot.stdin();
|
|
187
|
-
/** 注册bot */
|
|
188
|
-
listener.emit('bot', { type: 'internal', bot });
|
|
189
|
-
}
|
|
189
|
+
if (enable)
|
|
190
|
+
new AdapterInput().stdin();
|
|
@@ -721,7 +721,9 @@ export class KritorGrpc {
|
|
|
721
721
|
const bot = new AdapterKritor(grpc, uid, uin + '');
|
|
722
722
|
this.BotMap.set(uid, bot);
|
|
723
723
|
/** 注册bot */
|
|
724
|
-
listener.
|
|
724
|
+
const index = listener.addBot({ type: bot.adapter.type, bot });
|
|
725
|
+
if (index)
|
|
726
|
+
bot.adapter.index = index;
|
|
725
727
|
},
|
|
726
728
|
};
|
|
727
729
|
this.#server.addService(coreProtoGrpcType.kritor.core.CoreService.service, authenticationServer);
|
|
@@ -977,5 +979,3 @@ export class KritorGrpc {
|
|
|
977
979
|
return elements;
|
|
978
980
|
}
|
|
979
981
|
}
|
|
980
|
-
export const grpcServer = new KritorGrpc();
|
|
981
|
-
grpcServer.init();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { kritor } from 'kritor-proto';
|
|
2
2
|
import { logger, config, segment } from '../../utils/index.js';
|
|
3
|
+
import { listener } from '../../core/index.js';
|
|
3
4
|
/**
|
|
4
5
|
* @extends KarinAdapter
|
|
5
6
|
*/
|
|
@@ -21,7 +22,7 @@ export default class AdapterKritor {
|
|
|
21
22
|
*/
|
|
22
23
|
grpc, uid, uin) {
|
|
23
24
|
this.account = { uid, uin, name: '' };
|
|
24
|
-
this.adapter = { id: 'QQ', name: 'Kritor', type: 'grpc', sub_type: 'server', start_time: Date.now(), connect: '' };
|
|
25
|
+
this.adapter = { id: 'QQ', name: 'Kritor', type: 'grpc', sub_type: 'server', start_time: Date.now(), connect: '', index: 0 };
|
|
25
26
|
this.version = { name: '', app_name: '', version: '' };
|
|
26
27
|
this.grpc = grpc;
|
|
27
28
|
/** 自增 */
|
|
@@ -29,7 +30,11 @@ export default class AdapterKritor {
|
|
|
29
30
|
/** 监听响应事件 */
|
|
30
31
|
this.grpc.on('data', data => this.grpc.emit(data.seq, data));
|
|
31
32
|
/** 监听关闭事件 */
|
|
32
|
-
this.grpc.
|
|
33
|
+
this.grpc.once('end', () => {
|
|
34
|
+
this.logger('warn', '[反向gRPC] 连接已断开');
|
|
35
|
+
this.grpc.removeAllListeners();
|
|
36
|
+
this.adapter.index && listener.delBot(this.adapter.index);
|
|
37
|
+
});
|
|
33
38
|
this.#init();
|
|
34
39
|
}
|
|
35
40
|
get self_id() {
|
|
@@ -31,8 +31,6 @@ export declare class AdapterOneBot11 implements KarinAdapter {
|
|
|
31
31
|
* 获取当前登录号信息
|
|
32
32
|
*/
|
|
33
33
|
getSelf(): Promise<void>;
|
|
34
|
-
/** 是否初始化 */
|
|
35
|
-
get isInit(): Promise<unknown>;
|
|
36
34
|
/**
|
|
37
35
|
* onebot11转karin
|
|
38
36
|
* @return karin格式消息
|
|
@@ -287,7 +285,9 @@ export declare class AdapterOneBot11 implements KarinAdapter {
|
|
|
287
285
|
SetInvitedJoinGroupResult(): Promise<void>;
|
|
288
286
|
UploadPrivateFile(): Promise<void>;
|
|
289
287
|
UploadGroupFile(): Promise<void>;
|
|
290
|
-
sendForwardMessage(): Promise<{
|
|
288
|
+
sendForwardMessage(contact: contact, elements: KarinNodeElement[]): Promise<{
|
|
289
|
+
message_id: any;
|
|
290
|
+
}>;
|
|
291
291
|
/**
|
|
292
292
|
* 发送API请求
|
|
293
293
|
* @param action - API断点
|
|
@@ -23,7 +23,7 @@ export class AdapterOneBot11 {
|
|
|
23
23
|
constructor() {
|
|
24
24
|
this.index = 0;
|
|
25
25
|
this.account = { uid: '', uin: '', name: '' };
|
|
26
|
-
this.adapter = { id: 'QQ', name: 'OneBot11', type: 'ws', sub_type: 'internal', start_time: Date.now(), connect: '' };
|
|
26
|
+
this.adapter = { id: 'QQ', name: 'OneBot11', type: 'ws', sub_type: 'internal', start_time: Date.now(), connect: '', index: 0 };
|
|
27
27
|
this.version = { name: '', app_name: '', version: '' };
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
@@ -54,15 +54,6 @@ export class AdapterOneBot11 {
|
|
|
54
54
|
this.index = 0;
|
|
55
55
|
this.#initListener(connect);
|
|
56
56
|
});
|
|
57
|
-
/** 监听断开 */
|
|
58
|
-
this.socket.on('close', async () => {
|
|
59
|
-
this.index++;
|
|
60
|
-
logger.warn(`[正向WS][重连次数:${this.index}] 连接断开,将在5秒后重连:${connect}`);
|
|
61
|
-
/** 停止全部监听 */
|
|
62
|
-
this.socket.removeAllListeners();
|
|
63
|
-
await common.sleep(5000);
|
|
64
|
-
this.client(connect);
|
|
65
|
-
});
|
|
66
57
|
}
|
|
67
58
|
/**
|
|
68
59
|
* 初始化监听事件
|
|
@@ -92,6 +83,8 @@ export class AdapterOneBot11 {
|
|
|
92
83
|
this.logger('warn', `[${type}] 连接断开:${connect}`);
|
|
93
84
|
/** 停止全部监听 */
|
|
94
85
|
this.socket.removeAllListeners();
|
|
86
|
+
/** 注销bot */
|
|
87
|
+
this.adapter.index && listener.delBot(this.adapter.index);
|
|
95
88
|
/** 正向ws需要重连 */
|
|
96
89
|
if (this.adapter.sub_type === 'client') {
|
|
97
90
|
this.index++;
|
|
@@ -129,20 +122,9 @@ export class AdapterOneBot11 {
|
|
|
129
122
|
this.account.name = data.account_name;
|
|
130
123
|
this.logger('info', `[加载完成][app_name:${this.version.name}][version:${this.version.version}] ` + logger.green(this.adapter.connect));
|
|
131
124
|
/** 注册bot */
|
|
132
|
-
listener.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
get isInit() {
|
|
136
|
-
return new Promise(resolve => {
|
|
137
|
-
const timer = setInterval(() => {
|
|
138
|
-
if (this.account.name) {
|
|
139
|
-
const { name, version } = this.version;
|
|
140
|
-
this.logger('info', `建立连接成功:[${name}(${version})] ${this.adapter.connect}`);
|
|
141
|
-
clearInterval(timer);
|
|
142
|
-
resolve(true);
|
|
143
|
-
}
|
|
144
|
-
}, 100);
|
|
145
|
-
});
|
|
125
|
+
const index = listener.addBot({ type: this.adapter.type, bot: this });
|
|
126
|
+
if (index)
|
|
127
|
+
this.adapter.index = index;
|
|
146
128
|
}
|
|
147
129
|
/**
|
|
148
130
|
* 处理事件
|
|
@@ -151,20 +133,17 @@ export class AdapterOneBot11 {
|
|
|
151
133
|
#event(data) {
|
|
152
134
|
switch (data.post_type) {
|
|
153
135
|
case 'meta_event': {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
this.logger('debug', `[生命周期]:${typeMap[sub_type]}`);
|
|
166
|
-
break;
|
|
167
|
-
}
|
|
136
|
+
if (data.meta_event_type === 'heartbeat') {
|
|
137
|
+
this.logger('trace', `[心跳]:${JSON.stringify(data.status)}`);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
const typeMap = {
|
|
141
|
+
enable: 'OneBot启用',
|
|
142
|
+
disable: 'OneBot停用',
|
|
143
|
+
connect: 'WebSocket连接成功',
|
|
144
|
+
};
|
|
145
|
+
const sub_type = data.sub_type;
|
|
146
|
+
this.logger('debug', `[生命周期]:${typeMap[sub_type]}`);
|
|
168
147
|
}
|
|
169
148
|
listener.emit('meta_event', data);
|
|
170
149
|
return;
|
|
@@ -1236,8 +1215,12 @@ export class AdapterOneBot11 {
|
|
|
1236
1215
|
async SetInvitedJoinGroupResult() { }
|
|
1237
1216
|
async UploadPrivateFile() { }
|
|
1238
1217
|
async UploadGroupFile() { }
|
|
1239
|
-
async sendForwardMessage() {
|
|
1240
|
-
|
|
1218
|
+
async sendForwardMessage(contact, elements) {
|
|
1219
|
+
let message_id = await this.UploadForwardMessage(contact, elements);
|
|
1220
|
+
if (this.version.name === 'Lagrange.OneBot') {
|
|
1221
|
+
message_id = await this.SendMessage(contact, [segment.forward(message_id)]);
|
|
1222
|
+
}
|
|
1223
|
+
return { message_id };
|
|
1241
1224
|
}
|
|
1242
1225
|
/**
|
|
1243
1226
|
* 发送API请求
|
package/lib/core/karin.js
CHANGED
|
@@ -11,44 +11,32 @@ export class Karin {
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
command (reg, second, options = {}) {
|
|
14
|
-
|
|
14
|
+
reg = typeof reg === 'string' ? new RegExp(reg) : reg
|
|
15
|
+
const fnc = typeof second === 'function'
|
|
16
|
+
? second
|
|
17
|
+
: async (e) => {
|
|
18
|
+
const element = typeof second === 'number' ? String(second) : second
|
|
19
|
+
if ('delay' in options && options.delay) { await common.sleep(options.delay) }
|
|
20
|
+
await e.reply(element, {
|
|
21
|
+
at: ('at' in options && options.at) || false,
|
|
22
|
+
reply: ('reply' in options && options.reply) || false,
|
|
23
|
+
recallMsg: ('recallMsg' in options && Number(options.recallMsg)) || 0,
|
|
24
|
+
})
|
|
25
|
+
return !('stop' in options && !options.stop)
|
|
26
|
+
}
|
|
15
27
|
const data = {
|
|
16
28
|
name: options.name || 'function',
|
|
17
29
|
priority: options.priority,
|
|
18
30
|
rule: [
|
|
19
31
|
{
|
|
20
|
-
reg
|
|
21
|
-
fnc
|
|
32
|
+
reg,
|
|
33
|
+
fnc,
|
|
22
34
|
permission: options.permission || 'all',
|
|
23
35
|
log: options.log ?? true,
|
|
24
36
|
},
|
|
25
37
|
],
|
|
26
38
|
}
|
|
27
|
-
|
|
28
|
-
case 'function': {
|
|
29
|
-
return PluginApp(data)
|
|
30
|
-
}
|
|
31
|
-
case 'string':
|
|
32
|
-
case 'number':
|
|
33
|
-
case 'object': {
|
|
34
|
-
const element = common.makeMessage(typeof second === 'number' ? String(second) : second)
|
|
35
|
-
const fnc = async (e) => {
|
|
36
|
-
if ('delay' in options && options.delay) { await common.sleep(options.delay) }
|
|
37
|
-
await e.reply(element, {
|
|
38
|
-
at: ('at' in options && options.at) || false,
|
|
39
|
-
reply: ('reply' in options && options.reply) || false,
|
|
40
|
-
recallMsg: ('recallMsg' in options && Number(options.recallMsg)) || 0,
|
|
41
|
-
})
|
|
42
|
-
if ('stop' in options && !options.stop) { return false }
|
|
43
|
-
return true
|
|
44
|
-
}
|
|
45
|
-
data.rule[0].fnc = fnc
|
|
46
|
-
return PluginApp(data)
|
|
47
|
-
}
|
|
48
|
-
default: {
|
|
49
|
-
throw new Error('command: second argument must be a function or string')
|
|
50
|
-
}
|
|
51
|
-
}
|
|
39
|
+
return PluginApp(data)
|
|
52
40
|
}
|
|
53
41
|
|
|
54
42
|
/**
|
package/lib/core/listener.js
CHANGED
|
@@ -31,14 +31,9 @@ class Listeners extends EventEmitter {
|
|
|
31
31
|
let path = data.path || '无'
|
|
32
32
|
if (path && data.type !== 'grpc') { path = `ws://127.0.0.1:/${config.Server.http.port}${data.path}` }
|
|
33
33
|
path = logger.green(path)
|
|
34
|
-
logger.info(`[适配器][注册][${data.type}] ` + path)
|
|
34
|
+
logger.info(`[适配器][注册][${data.type}]: ` + path)
|
|
35
35
|
this.addAdapter(data)
|
|
36
36
|
})
|
|
37
|
-
this.on('bot', data => {
|
|
38
|
-
if (!this.addBot(data)) { return }
|
|
39
|
-
logger.info(`[机器人][注册][${data.type}] ` + logger.green(`[account:${data.bot.account.uid || data.bot.account.uin}(${data.bot.account.name})]`))
|
|
40
|
-
this.emit('karin:online', data.bot.account.uid || data.bot.account.uin)
|
|
41
|
-
})
|
|
42
37
|
this.on('message', data => new MessageHandler(data))
|
|
43
38
|
this.on('notice', data => new NoticeHandler(data))
|
|
44
39
|
this.on('request', data => new RequestHandler(data))
|
|
@@ -55,6 +50,9 @@ class Listeners extends EventEmitter {
|
|
|
55
50
|
return false
|
|
56
51
|
}
|
|
57
52
|
this.list.push({ index, type: data.type, bot: data.bot })
|
|
53
|
+
logger.info(`[机器人][注册][${data.type}] ` + logger.green(`[account:${data.bot.account.uid || data.bot.account.uin}(${data.bot.account.name})]`))
|
|
54
|
+
this.emit('karin:online', data.bot.account.uid || data.bot.account.uin)
|
|
55
|
+
logger.debug('注册', this.list)
|
|
58
56
|
return index
|
|
59
57
|
}
|
|
60
58
|
|
|
@@ -64,6 +62,7 @@ class Listeners extends EventEmitter {
|
|
|
64
62
|
*/
|
|
65
63
|
delBot (index) {
|
|
66
64
|
this.list = this.list.filter(item => item.index !== index)
|
|
65
|
+
logger.debug('[机器人][卸载] ', this.list)
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
/**
|
package/lib/core/plugin.d.ts
CHANGED
|
@@ -4,8 +4,8 @@ import { PluginType, KarinElement, KarinNodeElement, EventType, KarinNoticeEvent
|
|
|
4
4
|
*/
|
|
5
5
|
export declare class Plugin implements PluginType {
|
|
6
6
|
e: EventType<this>;
|
|
7
|
-
init?: () =>
|
|
8
|
-
accept?: (e: any) => Promise<
|
|
7
|
+
init?: () => Promise<any>;
|
|
8
|
+
accept?: (e: any) => Promise<any>;
|
|
9
9
|
replyCallback: PluginType['replyCallback'];
|
|
10
10
|
/**
|
|
11
11
|
* @param name - 插件名称
|
|
@@ -2,11 +2,8 @@ import chokidar from 'chokidar';
|
|
|
2
2
|
import schedule from 'node-schedule';
|
|
3
3
|
import { Plugin } from './plugin.js';
|
|
4
4
|
import { PluginApps, PluginTask, dirName, fileName, AppInfo } from '../types/index.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*/
|
|
8
|
-
export declare const pluginLoader: {
|
|
9
|
-
dir: "./plugins";
|
|
5
|
+
declare class PluginLoader {
|
|
6
|
+
dir: './plugins';
|
|
10
7
|
dirPath: string;
|
|
11
8
|
/**
|
|
12
9
|
* - 插件索引ID
|
|
@@ -42,6 +39,10 @@ export declare const pluginLoader: {
|
|
|
42
39
|
* - 是否ts环境
|
|
43
40
|
*/
|
|
44
41
|
isTs: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* - 是否开发环境
|
|
44
|
+
*/
|
|
45
|
+
isDev: boolean;
|
|
45
46
|
/**
|
|
46
47
|
* - 最终缓存的插件列表 通过index索引
|
|
47
48
|
*/
|
|
@@ -70,10 +71,11 @@ export declare const pluginLoader: {
|
|
|
70
71
|
dir: dirName;
|
|
71
72
|
name?: fileName;
|
|
72
73
|
}>;
|
|
74
|
+
constructor();
|
|
73
75
|
/**
|
|
74
76
|
* 插件初始化
|
|
75
77
|
*/
|
|
76
|
-
load(): Promise<
|
|
78
|
+
load(): Promise<this>;
|
|
77
79
|
/**
|
|
78
80
|
* 获取所有插件
|
|
79
81
|
*/
|
|
@@ -83,13 +85,13 @@ export declare const pluginLoader: {
|
|
|
83
85
|
* @param path - 插件路径
|
|
84
86
|
* @param lang - 语言环境
|
|
85
87
|
*/
|
|
86
|
-
getIndex(path: string, lang:
|
|
88
|
+
getIndex(path: string, lang: 'js' | 'ts'): string | boolean;
|
|
87
89
|
/**
|
|
88
90
|
* 获取指定文件夹下的所有插件
|
|
89
91
|
* @param dir - 插件包名称
|
|
90
92
|
* @param isTs - 是否获取ts插件
|
|
91
93
|
*/
|
|
92
|
-
getApps(dir: dirName, isTs: boolean): void;
|
|
94
|
+
getApps(dir: dirName, isTs: boolean, isWatch?: boolean): void;
|
|
93
95
|
/**
|
|
94
96
|
* 排序并打印插件加兹安信息
|
|
95
97
|
* @param isPrint - 是否打印
|
|
@@ -99,9 +101,33 @@ export declare const pluginLoader: {
|
|
|
99
101
|
* 新增插件
|
|
100
102
|
* @param dir - 插件包路径
|
|
101
103
|
* @param name - 插件名称
|
|
102
|
-
* @param isOrderBy -
|
|
104
|
+
* @param isOrderBy - 是否为动态导入 默认为静态导入
|
|
103
105
|
*/
|
|
104
106
|
createdApp(dir: dirName, name: fileName, isOrderBy?: boolean): Promise<boolean>;
|
|
107
|
+
/**
|
|
108
|
+
* 新增rule
|
|
109
|
+
*/
|
|
110
|
+
addRule(dir: dirName, name: fileName, index: number, Class: Plugin): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* 新增task fnc模式
|
|
113
|
+
*/
|
|
114
|
+
addTaskFnc(dir: dirName, App: PluginApps): PluginTask[];
|
|
115
|
+
/**
|
|
116
|
+
* 新增task
|
|
117
|
+
*/
|
|
118
|
+
addTask(dir: dirName, name: fileName, index: number, Class: Plugin, App: new () => Plugin): Promise<void>;
|
|
119
|
+
/**
|
|
120
|
+
* 新增accept、handler
|
|
121
|
+
*/
|
|
122
|
+
addAccept(index: number, Class: Plugin): Promise<void>;
|
|
123
|
+
/**
|
|
124
|
+
* 新增button
|
|
125
|
+
*/
|
|
126
|
+
addButton(dir: dirName, name: fileName, index: number, Class: Plugin): Promise<void>;
|
|
127
|
+
/**
|
|
128
|
+
* 执行初始化
|
|
129
|
+
*/
|
|
130
|
+
addInit(Class: Plugin): Promise<void>;
|
|
105
131
|
/**
|
|
106
132
|
* 卸载插件
|
|
107
133
|
*/
|
|
@@ -114,4 +140,15 @@ export declare const pluginLoader: {
|
|
|
114
140
|
* 监听文件夹更新
|
|
115
141
|
*/
|
|
116
142
|
watchDir(dir: dirName): Promise<true | undefined>;
|
|
117
|
-
|
|
143
|
+
watcAdd(dir: dirName, name: fileName): Promise<boolean | undefined>;
|
|
144
|
+
/**
|
|
145
|
+
* 传入文件名称 返回是否符合当前环境规则
|
|
146
|
+
* @param name - 文件名称
|
|
147
|
+
*/
|
|
148
|
+
isApp(name: fileName): boolean;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* 加载插件
|
|
152
|
+
*/
|
|
153
|
+
export declare const pluginLoader: PluginLoader;
|
|
154
|
+
export {};
|
|
@@ -7,10 +7,7 @@ import { listener } from './listener.js'
|
|
|
7
7
|
import PluginApp from './plugin.app.js'
|
|
8
8
|
import { render } from '../render/index.js'
|
|
9
9
|
import { common, handler, logger } from '../utils/index.js'
|
|
10
|
-
|
|
11
|
-
* 加载插件
|
|
12
|
-
*/
|
|
13
|
-
export const pluginLoader = new (class PluginLoader {
|
|
10
|
+
class PluginLoader {
|
|
14
11
|
dir
|
|
15
12
|
dirPath
|
|
16
13
|
/**
|
|
@@ -41,6 +38,10 @@ export const pluginLoader = new (class PluginLoader {
|
|
|
41
38
|
* - 是否ts环境
|
|
42
39
|
*/
|
|
43
40
|
isTs
|
|
41
|
+
/**
|
|
42
|
+
* - 是否开发环境
|
|
43
|
+
*/
|
|
44
|
+
isDev
|
|
44
45
|
/**
|
|
45
46
|
* - 最终缓存的插件列表 通过index索引
|
|
46
47
|
*/
|
|
@@ -62,6 +63,7 @@ export const pluginLoader = new (class PluginLoader {
|
|
|
62
63
|
this.dir = './plugins'
|
|
63
64
|
this.dirPath = common.urlToPath(import.meta.url)
|
|
64
65
|
this.isTs = process.env.karin_app_lang === 'ts'
|
|
66
|
+
this.isDev = process.env.karin_app_mode === 'dev'
|
|
65
67
|
this.watcher = new Map()
|
|
66
68
|
this.watchList = []
|
|
67
69
|
this.FileList = []
|
|
@@ -79,7 +81,10 @@ export const pluginLoader = new (class PluginLoader {
|
|
|
79
81
|
async load () {
|
|
80
82
|
this.getPlugins()
|
|
81
83
|
listener.once('plugin.watch', () => {
|
|
82
|
-
for (const v of this.watchList) {
|
|
84
|
+
for (const v of this.watchList) {
|
|
85
|
+
v.name ? this.watch(v.dir, v.name) : this.watchDir(v.dir)
|
|
86
|
+
logger.debug(`[热更新][${v.dir}]${v.name ? `[${v.name}]` : ''} 监听中...`)
|
|
87
|
+
}
|
|
83
88
|
})
|
|
84
89
|
logger.info(logger.green('-----------'))
|
|
85
90
|
logger.info('加载插件中..')
|
|
@@ -115,21 +120,14 @@ export const pluginLoader = new (class PluginLoader {
|
|
|
115
120
|
*/
|
|
116
121
|
/** 非插件包 加载该文件夹下全部js 视语言环境加载ts */
|
|
117
122
|
if (!common.isPlugin(PluginPath)) {
|
|
118
|
-
this.
|
|
119
|
-
const list = fs.readdirSync(`${this.dir}/${dir}`, { withFileTypes: true })
|
|
120
|
-
for (const file of list) {
|
|
121
|
-
/** 忽略不符合规则的文件 */
|
|
122
|
-
const ext = this.isTs ? ['.js', '.ts'] : ['.js']
|
|
123
|
-
if (!ext.includes(path.extname(file.name))) { continue }
|
|
124
|
-
this.FileList.push({ dir, name: file.name })
|
|
125
|
-
}
|
|
123
|
+
this.getApps(dir, this.isTs, true)
|
|
126
124
|
continue
|
|
127
125
|
}
|
|
128
126
|
/** 入口文件 */
|
|
129
127
|
const index = this.getIndex(PluginPath, process.env.karin_app_lang)
|
|
130
128
|
if (index) {
|
|
131
|
-
this.watchList.push({ dir, name: index })
|
|
132
129
|
this.FileList.push({ dir, name: index })
|
|
130
|
+
this.isDev && this.watchList.push({ dir, name: index })
|
|
133
131
|
}
|
|
134
132
|
/** 检查是否存在karin.apps */
|
|
135
133
|
const pack = common.readJson(`${PluginPath}/package.json`)
|
|
@@ -181,8 +179,8 @@ export const pluginLoader = new (class PluginLoader {
|
|
|
181
179
|
* @param dir - 插件包名称
|
|
182
180
|
* @param isTs - 是否获取ts插件
|
|
183
181
|
*/
|
|
184
|
-
getApps (dir, isTs) {
|
|
185
|
-
this.watchList.push({ dir })
|
|
182
|
+
getApps (dir, isTs, isWatch = false) {
|
|
183
|
+
isWatch && this.watchList.push({ dir })
|
|
186
184
|
const ext = isTs ? ['.js', '.ts'] : ['.js']
|
|
187
185
|
const list = fs.readdirSync(`${this.dir}/${dir}`, { withFileTypes: true })
|
|
188
186
|
for (const file of list) {
|
|
@@ -234,10 +232,11 @@ export const pluginLoader = new (class PluginLoader {
|
|
|
234
232
|
* 新增插件
|
|
235
233
|
* @param dir - 插件包路径
|
|
236
234
|
* @param name - 插件名称
|
|
237
|
-
* @param isOrderBy -
|
|
235
|
+
* @param isOrderBy - 是否为动态导入 默认为静态导入
|
|
238
236
|
*/
|
|
239
237
|
async createdApp (dir, name, isOrderBy = false) {
|
|
240
238
|
try {
|
|
239
|
+
const list = []
|
|
241
240
|
let path = `${this.dirPath}plugins/${dir}/${name}`
|
|
242
241
|
if (isOrderBy) { path = path + `?${Date.now()}` }
|
|
243
242
|
const tmp = await import(path)
|
|
@@ -249,29 +248,9 @@ export const pluginLoader = new (class PluginLoader {
|
|
|
249
248
|
App.file.dir = dir
|
|
250
249
|
App.file.name = name
|
|
251
250
|
/** handler */
|
|
252
|
-
|
|
253
|
-
const task = []
|
|
254
|
-
/** 定时任务 */
|
|
255
|
-
lodash.forEach(App.task, val => {
|
|
256
|
-
task.push({
|
|
257
|
-
name: val.name,
|
|
258
|
-
cron: val.cron,
|
|
259
|
-
fnc: val.fnc,
|
|
260
|
-
log: val.log === false ? (log) => logger.debug(log) : (log) => logger.mark(log),
|
|
261
|
-
schedule: schedule.scheduleJob(val.cron, async () => {
|
|
262
|
-
try {
|
|
263
|
-
typeof val.log === 'function' && val.log(`[定时任务][${dir}][${val.name}] 开始执行`)
|
|
264
|
-
if (typeof val.fnc === 'function') { await val.fnc() }
|
|
265
|
-
typeof val.log === 'function' && val.log(`[定时任务][${dir}][${val.name}] 执行完毕`)
|
|
266
|
-
} catch (error) {
|
|
267
|
-
logger.error(`[定时任务][${dir}][${val.name}] 执行报错`)
|
|
268
|
-
logger.error(error)
|
|
269
|
-
}
|
|
270
|
-
}),
|
|
271
|
-
})
|
|
272
|
-
})
|
|
273
|
-
App.task = task
|
|
251
|
+
App.task = this.addTaskFnc(dir, App)
|
|
274
252
|
this.PluginList[index] = App
|
|
253
|
+
handler.add(index + '', App)
|
|
275
254
|
if (App.accept) { this.acceptIds.push(index) }
|
|
276
255
|
return true
|
|
277
256
|
}
|
|
@@ -279,72 +258,22 @@ export const pluginLoader = new (class PluginLoader {
|
|
|
279
258
|
const Class = new App()
|
|
280
259
|
if (!Class.name) { return logger.error(`[${dir}][${name}] 插件名称错误`) }
|
|
281
260
|
logger.debug(`载入插件 [${name}][${Class.name}]`)
|
|
282
|
-
|
|
283
|
-
file: {
|
|
284
|
-
dir,
|
|
285
|
-
name,
|
|
286
|
-
type: 'class',
|
|
287
|
-
fnc: App,
|
|
288
|
-
},
|
|
261
|
+
this.PluginList[index] = PluginApp({
|
|
262
|
+
file: { dir, name, type: 'class', fnc: App },
|
|
289
263
|
name: Class.name,
|
|
290
264
|
event: Class.event,
|
|
291
265
|
priority: Class.priority,
|
|
292
|
-
accept:
|
|
293
|
-
})
|
|
294
|
-
/** 定时任务 */
|
|
295
|
-
lodash.forEach(Class.task, val => {
|
|
296
|
-
if (!val.name) { return logger.error(`[${dir}][${name}] 定时任务name错误`) }
|
|
297
|
-
if (!val.cron) { return logger.error(`[${dir}][${name}] 定时任务cron错误:${Class.name}`) }
|
|
298
|
-
info.task.push({
|
|
299
|
-
name: val.name,
|
|
300
|
-
cron: val.cron,
|
|
301
|
-
fnc: val.fnc,
|
|
302
|
-
log: val.log === false ? (log) => logger.debug(log) : (log) => logger.mark(log),
|
|
303
|
-
schedule: schedule.scheduleJob(val.cron, async () => {
|
|
304
|
-
try {
|
|
305
|
-
typeof val.log === 'function' && val.log(`[定时任务][${dir}][${val.name}] 开始执行`)
|
|
306
|
-
if (typeof val.fnc === 'function') {
|
|
307
|
-
await val.fnc()
|
|
308
|
-
} else {
|
|
309
|
-
const cla = new App()
|
|
310
|
-
await cla[val.fnc]()
|
|
311
|
-
}
|
|
312
|
-
typeof val.log === 'function' && val.log(`[定时任务][${dir}][${val.name}] 执行完毕`)
|
|
313
|
-
} catch (error) {
|
|
314
|
-
logger.error(`[定时任务][${dir}][${val.name}] 执行报错`)
|
|
315
|
-
logger.error(error)
|
|
316
|
-
}
|
|
317
|
-
}),
|
|
318
|
-
})
|
|
319
|
-
})
|
|
320
|
-
/** rule */
|
|
321
|
-
lodash.forEach(Class.rule, val => {
|
|
322
|
-
if (!val.fnc) { return logger.error(`[${dir}][${name}] rule.fnc错误:${Class.name}`) }
|
|
323
|
-
info.rule.push({
|
|
324
|
-
reg: val.reg instanceof RegExp ? val.reg : new RegExp(val.reg),
|
|
325
|
-
fnc: val.fnc,
|
|
326
|
-
event: val.event,
|
|
327
|
-
permission: val.permission || 'all',
|
|
328
|
-
log: val.log === false ? (id, log) => logger.debug('mark', id, log) : (id, log) => logger.bot('mark', id, log),
|
|
329
|
-
})
|
|
330
|
-
})
|
|
331
|
-
/** button */
|
|
332
|
-
lodash.forEach(Class.button, val => {
|
|
333
|
-
if (!val.fnc) { return logger.error(`[${dir}][${name}] rule.fnc错误:${Class.name}`) }
|
|
334
|
-
info.button.push({
|
|
335
|
-
reg: val.reg instanceof RegExp ? val.reg : new RegExp(val.reg),
|
|
336
|
-
fnc: val.fnc,
|
|
337
|
-
})
|
|
266
|
+
accept: false,
|
|
338
267
|
})
|
|
339
|
-
/**
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
this.PluginList[index] = info
|
|
268
|
+
/** 异步收集 加载速度 */
|
|
269
|
+
list.push(this.addRule(dir, name, index, Class))
|
|
270
|
+
list.push(this.addTask(dir, name, index, Class, App))
|
|
271
|
+
list.push(this.addAccept(index, Class))
|
|
272
|
+
list.push(this.addButton(dir, name, index, Class))
|
|
273
|
+
list.push(this.addInit(Class))
|
|
346
274
|
return true
|
|
347
275
|
})
|
|
276
|
+
await Promise.all(list)
|
|
348
277
|
// rule收集并排序
|
|
349
278
|
if (isOrderBy) { this.orderBy() }
|
|
350
279
|
return true
|
|
@@ -366,6 +295,112 @@ export const pluginLoader = new (class PluginLoader {
|
|
|
366
295
|
}
|
|
367
296
|
}
|
|
368
297
|
|
|
298
|
+
/**
|
|
299
|
+
* 新增rule
|
|
300
|
+
*/
|
|
301
|
+
async addRule (dir, name, index, Class) {
|
|
302
|
+
lodash.forEach(Class.rule, val => {
|
|
303
|
+
if (!val.fnc) { return logger.error(`[${dir}][${name}] rule.fnc错误:${Class.name}`) }
|
|
304
|
+
this.PluginList[index].rule.push({
|
|
305
|
+
reg: val.reg instanceof RegExp ? val.reg : new RegExp(val.reg),
|
|
306
|
+
fnc: val.fnc,
|
|
307
|
+
event: val.event,
|
|
308
|
+
permission: val.permission || 'all',
|
|
309
|
+
log: val.log === false ? (id, log) => logger.debug('mark', id, log) : (id, log) => logger.bot('mark', id, log),
|
|
310
|
+
})
|
|
311
|
+
})
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* 新增task fnc模式
|
|
316
|
+
*/
|
|
317
|
+
addTaskFnc (dir, App) {
|
|
318
|
+
const task = []
|
|
319
|
+
lodash.forEach(App.task, val => {
|
|
320
|
+
task.push({
|
|
321
|
+
name: val.name,
|
|
322
|
+
cron: val.cron,
|
|
323
|
+
fnc: val.fnc,
|
|
324
|
+
log: val.log === false ? (log) => logger.debug(log) : (log) => logger.mark(log),
|
|
325
|
+
schedule: schedule.scheduleJob(val.cron, async () => {
|
|
326
|
+
try {
|
|
327
|
+
typeof val.log === 'function' && val.log(`[定时任务][${dir}][${val.name}] 开始执行`)
|
|
328
|
+
if (typeof val.fnc === 'function') { await val.fnc() }
|
|
329
|
+
typeof val.log === 'function' && val.log(`[定时任务][${dir}][${val.name}] 执行完毕`)
|
|
330
|
+
} catch (error) {
|
|
331
|
+
logger.error(`[定时任务][${dir}][${val.name}] 执行报错`)
|
|
332
|
+
logger.error(error)
|
|
333
|
+
}
|
|
334
|
+
}),
|
|
335
|
+
})
|
|
336
|
+
return true
|
|
337
|
+
})
|
|
338
|
+
return task
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* 新增task
|
|
343
|
+
*/
|
|
344
|
+
async addTask (dir, name, index, Class, App) {
|
|
345
|
+
/** 定时任务 */
|
|
346
|
+
lodash.forEach(Class.task, val => {
|
|
347
|
+
if (!val.name) { return logger.error(`[${dir}][${name}] 定时任务name错误`) }
|
|
348
|
+
if (!val.cron) { return logger.error(`[${dir}][${name}] 定时任务cron错误:${Class.name}`) }
|
|
349
|
+
this.PluginList[index].task.push({
|
|
350
|
+
name: val.name,
|
|
351
|
+
cron: val.cron,
|
|
352
|
+
fnc: val.fnc,
|
|
353
|
+
log: val.log === false ? (log) => logger.debug(log) : (log) => logger.mark(log),
|
|
354
|
+
schedule: schedule.scheduleJob(val.cron, async () => {
|
|
355
|
+
try {
|
|
356
|
+
typeof val.log === 'function' && val.log(`[定时任务][${dir}][${val.name}] 开始执行`)
|
|
357
|
+
if (typeof val.fnc === 'function') {
|
|
358
|
+
await val.fnc()
|
|
359
|
+
} else {
|
|
360
|
+
const cla = new App()
|
|
361
|
+
await cla[val.fnc]()
|
|
362
|
+
}
|
|
363
|
+
typeof val.log === 'function' && val.log(`[定时任务][${dir}][${val.name}] 执行完毕`)
|
|
364
|
+
} catch (error) {
|
|
365
|
+
logger.error(`[定时任务][${dir}][${val.name}] 执行报错`)
|
|
366
|
+
logger.error(error)
|
|
367
|
+
}
|
|
368
|
+
}),
|
|
369
|
+
})
|
|
370
|
+
})
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* 新增accept、handler
|
|
375
|
+
*/
|
|
376
|
+
async addAccept (index, Class) {
|
|
377
|
+
if (Class.accept && typeof Class.accept === 'function') {
|
|
378
|
+
this.PluginList[index].accept = true
|
|
379
|
+
this.acceptIds.push(index)
|
|
380
|
+
}
|
|
381
|
+
await handler.add(index + '', Class)
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* 新增button
|
|
386
|
+
*/
|
|
387
|
+
async addButton (dir, name, index, Class) {
|
|
388
|
+
lodash.forEach(Class.button, val => {
|
|
389
|
+
if (!val.fnc) { return logger.error(`[${dir}][${name}] button.fnc错误:${Class.name}`) }
|
|
390
|
+
this.PluginList[index].button.push({
|
|
391
|
+
reg: val.reg instanceof RegExp ? val.reg : new RegExp(val.reg),
|
|
392
|
+
fnc: val.fnc,
|
|
393
|
+
})
|
|
394
|
+
})
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* 执行初始化
|
|
399
|
+
*/
|
|
400
|
+
async addInit (Class) {
|
|
401
|
+
Class.init && await Class.init()
|
|
402
|
+
}
|
|
403
|
+
|
|
369
404
|
/**
|
|
370
405
|
* 卸载插件
|
|
371
406
|
*/
|
|
@@ -480,4 +515,41 @@ export const pluginLoader = new (class PluginLoader {
|
|
|
480
515
|
this.watcher.set(dir, watcher)
|
|
481
516
|
return true
|
|
482
517
|
}
|
|
483
|
-
|
|
518
|
+
|
|
519
|
+
async watcAdd (dir, name) {
|
|
520
|
+
const file = `${this.dir}/${dir}/`
|
|
521
|
+
const filePath = `${file}/${name}`
|
|
522
|
+
logger.debug(`[热更新][新增插件] ${filePath}`)
|
|
523
|
+
if (!this.isApp(name)) {
|
|
524
|
+
logger.debug(`[热更新][新增插件] ${filePath} 文件类型错误 不符合当前环境规则 已忽略`)
|
|
525
|
+
return false
|
|
526
|
+
}
|
|
527
|
+
/** 载入插件 */
|
|
528
|
+
const res = await this.createdApp(dir, name, true)
|
|
529
|
+
if (!res) { return }
|
|
530
|
+
/** 延迟1秒 等待卸载完成 */
|
|
531
|
+
await common.sleep(1000)
|
|
532
|
+
/** 新增插件之后重新监听文件夹 */
|
|
533
|
+
this.watcher.delete(dir)
|
|
534
|
+
this.watchDir(dir)
|
|
535
|
+
logger.mark(`[新增插件][${dir}][${name}]`)
|
|
536
|
+
return true
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* 传入文件名称 返回是否符合当前环境规则
|
|
541
|
+
* @param name - 文件名称
|
|
542
|
+
*/
|
|
543
|
+
isApp (name) {
|
|
544
|
+
/** 任何环境都支持js */
|
|
545
|
+
if (name.endsWith('.js')) { return true }
|
|
546
|
+
/** ts环境支持ts */
|
|
547
|
+
if (name.endsWith('.ts') && this.isTs) { return true }
|
|
548
|
+
/** 其他情况返回false */
|
|
549
|
+
return false
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* 加载插件
|
|
554
|
+
*/
|
|
555
|
+
export const pluginLoader = new PluginLoader()
|
package/lib/core/process.js
CHANGED
|
@@ -72,7 +72,7 @@ export default class Process {
|
|
|
72
72
|
* 走到这里说明后台关闭失败
|
|
73
73
|
* 根据配置文件判断是否继续
|
|
74
74
|
*/
|
|
75
|
-
logger.error(logger.red(
|
|
75
|
+
logger.error(logger.red(`后台进程关闭失败,请检查是否有进程正在占用端口${config.Server.http.port}`))
|
|
76
76
|
if (!config.Config.multi_progress) {
|
|
77
77
|
logger.error(logger.red('当前配置不允许多进程运行,程序即将退出'))
|
|
78
78
|
await this.exit(1)
|
package/lib/core/server.d.ts
CHANGED
package/lib/core/server.js
CHANGED
|
@@ -7,6 +7,7 @@ import express from 'express'
|
|
|
7
7
|
import { exec, config, logger, common } from '../utils/index.js'
|
|
8
8
|
import { render, HttpRenderer, Wormhole, RenderClient } from '../render/index.js'
|
|
9
9
|
import { AdapterOneBot11 } from '../adapter/onebot/onebot11.js'
|
|
10
|
+
import { KritorGrpc } from '../adapter/index.js'
|
|
10
11
|
export const server = new (class Server {
|
|
11
12
|
reg
|
|
12
13
|
list
|
|
@@ -28,8 +29,10 @@ export const server = new (class Server {
|
|
|
28
29
|
*/
|
|
29
30
|
async init () {
|
|
30
31
|
try {
|
|
31
|
-
|
|
32
|
+
/** 防止多进程端口冲突 启动失败 */
|
|
32
33
|
await Process.check()
|
|
34
|
+
/** 初始化gRPC服务器 */
|
|
35
|
+
new KritorGrpc().init()
|
|
33
36
|
this.WebSocketServer.on('connection', (socket, request) => {
|
|
34
37
|
const path = request.url
|
|
35
38
|
const headers = request.headers
|
package/lib/db/redis.js
CHANGED
|
@@ -37,7 +37,7 @@ class Redis {
|
|
|
37
37
|
}
|
|
38
38
|
/** 第一次连接失败尝试拉起 windows直接降级 */
|
|
39
39
|
if (process.platform === 'win32') {
|
|
40
|
-
logger.
|
|
40
|
+
// logger.info(`Redis 建立连接失败:${data}`)
|
|
41
41
|
return await this.LevelDB()
|
|
42
42
|
}
|
|
43
43
|
this.RunCmd = 'redis-server --save 900 1 --save 300 10 --daemonize yes' + (await this.aarch64())
|
|
@@ -50,10 +50,10 @@ class Redis {
|
|
|
50
50
|
logger.info('Redis 连接成功')
|
|
51
51
|
return data
|
|
52
52
|
}
|
|
53
|
-
logger.
|
|
53
|
+
logger.warn(`Redis 二次建立连接失败:${logger.red(data)}`)
|
|
54
54
|
return false
|
|
55
55
|
} catch (error) {
|
|
56
|
-
logger.
|
|
56
|
+
logger.warn(`Redis 启动失败:${logger.red(data)}`)
|
|
57
57
|
return await this.LevelDB()
|
|
58
58
|
}
|
|
59
59
|
}
|
|
@@ -63,9 +63,8 @@ class Redis {
|
|
|
63
63
|
*/
|
|
64
64
|
async LevelDB () {
|
|
65
65
|
try {
|
|
66
|
-
logger.
|
|
66
|
+
logger.info('使用LevelDB代替Redis实现基础Api')
|
|
67
67
|
const redis = new RedisLevel()
|
|
68
|
-
logger.info('LevelDB 降级成功')
|
|
69
68
|
return redis
|
|
70
69
|
} catch (error) {
|
|
71
70
|
logger.error('降级为 LevelDB 失败')
|
package/lib/index.d.ts
CHANGED
package/lib/types/adapter.d.ts
CHANGED
package/lib/types/plugin.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import schedule from 'node-schedule';
|
|
2
|
-
import {
|
|
3
|
-
import { Reply, replyCallback } from './reply.js';
|
|
2
|
+
import { Reply, replyCallback, replyForward } from './reply.js';
|
|
4
3
|
import { EventType, Event, Permission, SubEvent, KarinMessageEvent, KarinNoticeEvent, KarinRequestEvent } from './event.js';
|
|
5
4
|
/**
|
|
6
5
|
* - 插件根目录名称
|
|
@@ -175,9 +174,7 @@ export interface PluginType {
|
|
|
175
174
|
/**
|
|
176
175
|
* - 快速回复合并转发
|
|
177
176
|
*/
|
|
178
|
-
replyForward:
|
|
179
|
-
message_id?: string;
|
|
180
|
-
}>;
|
|
177
|
+
replyForward: replyForward;
|
|
181
178
|
/**
|
|
182
179
|
* - 构建上下文键
|
|
183
180
|
*/
|
package/lib/types/render.d.ts
CHANGED
package/lib/types/reply.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { KarinElement } from './element.js';
|
|
1
|
+
import { KarinElement, KarinNodeElement } from './element.js';
|
|
2
2
|
export type Reply = (
|
|
3
3
|
/**
|
|
4
4
|
* 发送的消息
|
|
@@ -38,3 +38,6 @@ elements: KarinElement[],
|
|
|
38
38
|
retry_count?: number) => Promise<{
|
|
39
39
|
message_id?: string;
|
|
40
40
|
}>;
|
|
41
|
+
export type replyForward = (msg: KarinNodeElement[]) => Promise<{
|
|
42
|
+
message_id?: string;
|
|
43
|
+
}>;
|
package/lib/utils/handler.d.ts
CHANGED
package/lib/utils/handler.js
CHANGED
|
@@ -10,7 +10,7 @@ export const handler = new (class EventHandler {
|
|
|
10
10
|
* @param index 插件索引
|
|
11
11
|
* @param Class 插件类
|
|
12
12
|
*/
|
|
13
|
-
add (index, Class) {
|
|
13
|
+
async add (index, Class) {
|
|
14
14
|
lodash.forEach(Class.handler, val => {
|
|
15
15
|
if (!val.key) { logger.error(`[Handler][Add]: [${Class.name}] 缺少 key`) }
|
|
16
16
|
if (!val.fnc) { logger.error(`[Handler][Add]: [${Class.name}] 缺少 fnc`) }
|
package/lib/utils/update.d.ts
CHANGED
package/lib/utils/update.js
CHANGED
|
@@ -6,23 +6,6 @@ export const update = new (class Update {
|
|
|
6
6
|
this.dir = './plugins'
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* 获取插件列表 拥有packageon才会被识别
|
|
11
|
-
* @returns {string[]}
|
|
12
|
-
*/
|
|
13
|
-
getPlugins () {
|
|
14
|
-
const list = []
|
|
15
|
-
const files = fs.readdirSync(this.dir, { withFileTypes: true })
|
|
16
|
-
/** 忽略非文件夹、非karin-plugin-开头的文件夹或/karin-adapter-开头的文件夹 */
|
|
17
|
-
files.forEach(file => {
|
|
18
|
-
if (!file.isDirectory()) { return }
|
|
19
|
-
if (!file.name.startsWith('karin-plugin-') && !file.name.startsWith('karin-adapter-')) { return }
|
|
20
|
-
if (!fs.existsSync(`${this.dir}/${file.name}/packageon`)) { return }
|
|
21
|
-
list.push(file.name)
|
|
22
|
-
})
|
|
23
|
-
return list
|
|
24
|
-
}
|
|
25
|
-
|
|
26
9
|
/**
|
|
27
10
|
* 更新框架或插件
|
|
28
11
|
* @param path - 插件相对路径
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-karin",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.10",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "基于 Kritor 进行开发的nodejs机器人框架",
|
|
6
6
|
"homepage": "https://github.com/KarinJS/Karin",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
],
|
|
37
37
|
"scripts": {
|
|
38
38
|
"app": "node .",
|
|
39
|
-
"build": "tsc --project tsconfig.json && tsc-alias -p tsconfig.json && npm run
|
|
39
|
+
"build": "tsc --project tsconfig.json && tsc-alias -p tsconfig.json && npm run cp && npm run fix",
|
|
40
40
|
"cp": "cp ./lib/modules.d.ts ./modules.d.ts && cp ./lib/modules.js ./modules.js",
|
|
41
41
|
"delete": "pm2 delete ./config/config/pm2.yaml",
|
|
42
42
|
"dev": "tsx ./lib/index.js --dev",
|
|
@@ -69,6 +69,7 @@
|
|
|
69
69
|
"lodash": "4.17.21",
|
|
70
70
|
"log4js": "6.9.1",
|
|
71
71
|
"moment": "2.30.1",
|
|
72
|
+
"node-karin": "^0.6.9",
|
|
72
73
|
"node-schedule": "2.1.1",
|
|
73
74
|
"redis": "4.6.14",
|
|
74
75
|
"ws": "8.16.0",
|