node-karin 0.4.1 → 0.5.0
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/config.yaml +11 -0
- package/lib/adapter/input/index.d.ts +63 -0
- package/lib/adapter/input/index.js +188 -0
- package/lib/adapter/onebot/onebot11.d.ts +12 -138
- package/lib/adapter/onebot/onebot11.js +66 -49
- package/lib/core/index.d.ts +1 -0
- package/lib/core/index.js +1 -0
- package/lib/core/listener.js +6 -2
- package/lib/core/server.js +26 -0
- package/lib/event/event.handler.js +1 -1
- package/lib/event/event.js +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/types/adapter.d.ts +1 -1
- package/lib/types/config.d.ts +21 -0
- package/lib/utils/common.d.ts +5 -6
- package/lib/utils/common.js +3 -4
- package/lib/utils/config.d.ts +5 -1
- package/lib/utils/config.js +26 -14
- package/lib/utils/yamlEditor.d.ts +1 -1
- package/package.json +2 -1
|
@@ -17,6 +17,17 @@ multi_progress: false
|
|
|
17
17
|
# 控制台触发插件日志颜色 十六进制 默认#FFFF00 不支持热更新
|
|
18
18
|
log_color: "#E1D919"
|
|
19
19
|
|
|
20
|
+
# input适配器配置 以下所有配置均不支持热更新
|
|
21
|
+
AdapterInput:
|
|
22
|
+
# 是否启用
|
|
23
|
+
enable: true
|
|
24
|
+
# 是否将语音、图片、视频消息转为文件 转为文件后可通过url访问
|
|
25
|
+
msgToFile: true
|
|
26
|
+
# url访问token 如果为 AdapterInput 每次启动后会重新生成
|
|
27
|
+
token: "AdapterInput"
|
|
28
|
+
# 访问ip
|
|
29
|
+
ip: 127.0.0.1
|
|
30
|
+
|
|
20
31
|
# ffmpeg配置 用于音视频处理
|
|
21
32
|
ffmpeg_path:
|
|
22
33
|
ffprobe_path:
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { KarinAdapter } from '../../types/adapter.js';
|
|
2
|
+
import { contact, KarinElement } from '../../types/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* - 标准输入输出适配器
|
|
5
|
+
*/
|
|
6
|
+
export declare class AdapterInput implements KarinAdapter {
|
|
7
|
+
#private;
|
|
8
|
+
socket: WebSocket;
|
|
9
|
+
account: KarinAdapter['account'];
|
|
10
|
+
adapter: KarinAdapter['adapter'];
|
|
11
|
+
version: KarinAdapter['version'];
|
|
12
|
+
constructor();
|
|
13
|
+
get self_id(): string;
|
|
14
|
+
stdin(): void;
|
|
15
|
+
logger(level: 'info' | 'error' | 'trace' | 'debug' | 'mark' | 'warn' | 'fatal', ...args: any[]): void;
|
|
16
|
+
GetVersion(): Promise<{
|
|
17
|
+
name: string;
|
|
18
|
+
app_name: string;
|
|
19
|
+
version: string;
|
|
20
|
+
}>;
|
|
21
|
+
SendMessage(_contact: contact, elements: Array<KarinElement>): Promise<{
|
|
22
|
+
message_id: string;
|
|
23
|
+
}>;
|
|
24
|
+
getAvatarUrl(): string;
|
|
25
|
+
getGroupAvatar(): string;
|
|
26
|
+
GetCurrentAccount(): Promise<{
|
|
27
|
+
account_uid: string;
|
|
28
|
+
account_uin: string;
|
|
29
|
+
account_name: string;
|
|
30
|
+
}>;
|
|
31
|
+
GetEssenceMessageList(): Promise<any>;
|
|
32
|
+
DownloadForwardMessage(): Promise<any>;
|
|
33
|
+
SetEssenceMessage(): Promise<any>;
|
|
34
|
+
DeleteEssenceMessage(): Promise<any>;
|
|
35
|
+
SetFriendApplyResult(): Promise<any>;
|
|
36
|
+
SetGroupApplyResultRequest(): Promise<any>;
|
|
37
|
+
SetInvitedJoinGroupResult(): Promise<any>;
|
|
38
|
+
ReactMessageWithEmojiRequest(): Promise<any>;
|
|
39
|
+
UploadPrivateFile(): Promise<any>;
|
|
40
|
+
UploadGroupFile(): Promise<any>;
|
|
41
|
+
UploadForwardMessage(): Promise<any>;
|
|
42
|
+
sendForwardMessage(): Promise<any>;
|
|
43
|
+
SendMessageByResId(): Promise<any>;
|
|
44
|
+
RecallMessage(): Promise<any>;
|
|
45
|
+
GetMessage(): Promise<any>;
|
|
46
|
+
GetHistoryMessage(): Promise<any>;
|
|
47
|
+
VoteUser(): Promise<any>;
|
|
48
|
+
KickMember(): Promise<any>;
|
|
49
|
+
BanMember(): Promise<any>;
|
|
50
|
+
SetGroupWholeBan(): Promise<any>;
|
|
51
|
+
SetGroupAdmin(): Promise<any>;
|
|
52
|
+
ModifyMemberCard(): Promise<any>;
|
|
53
|
+
ModifyGroupName(): Promise<any>;
|
|
54
|
+
LeaveGroup(): Promise<any>;
|
|
55
|
+
SetGroupUniqueTitle(): Promise<any>;
|
|
56
|
+
GetStrangerProfileCard(): Promise<any>;
|
|
57
|
+
GetFriendList(): Promise<any>;
|
|
58
|
+
GetGroupInfo(): Promise<any>;
|
|
59
|
+
GetGroupList(): Promise<any>;
|
|
60
|
+
GetGroupMemberInfo(): Promise<any>;
|
|
61
|
+
GetGroupMemberList(): Promise<any>;
|
|
62
|
+
GetGroupHonor(): Promise<any>;
|
|
63
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import { randomUUID } from 'crypto';
|
|
3
|
+
import { listener } from '../../core/index.js';
|
|
4
|
+
import { KarinMessage } from '../../event/index.js';
|
|
5
|
+
import { config, common, YamlEditor } from '../../utils/index.js';
|
|
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
|
+
/**
|
|
34
|
+
* - 标准输入输出适配器
|
|
35
|
+
*/
|
|
36
|
+
export class AdapterInput {
|
|
37
|
+
#stdin;
|
|
38
|
+
socket;
|
|
39
|
+
account;
|
|
40
|
+
adapter;
|
|
41
|
+
version;
|
|
42
|
+
constructor() {
|
|
43
|
+
this.#stdin = false;
|
|
44
|
+
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: '' };
|
|
46
|
+
this.version = { name: 'input', app_name: 'input', version: '1.0.0' };
|
|
47
|
+
}
|
|
48
|
+
get self_id() {
|
|
49
|
+
return this.account.uid;
|
|
50
|
+
}
|
|
51
|
+
stdin() {
|
|
52
|
+
if (this.#stdin)
|
|
53
|
+
return;
|
|
54
|
+
this.#stdin = true;
|
|
55
|
+
process.stdin.on('data', data => this.#input(data.toString()));
|
|
56
|
+
process.once('stdin.close', () => process.stdin.removeAllListeners('data'));
|
|
57
|
+
}
|
|
58
|
+
logger(level, ...args) {
|
|
59
|
+
logger.bot(level, this.account.uid || this.account.uin, ...args);
|
|
60
|
+
}
|
|
61
|
+
async #input(elements) {
|
|
62
|
+
const message = {
|
|
63
|
+
event: 'message',
|
|
64
|
+
self_id: 'input',
|
|
65
|
+
user_id: 'input',
|
|
66
|
+
time: Date.now(),
|
|
67
|
+
message_id: `input.${Date.now()}`,
|
|
68
|
+
message_seq: '',
|
|
69
|
+
sender: {
|
|
70
|
+
uid: 'input',
|
|
71
|
+
uin: 'input',
|
|
72
|
+
nick: 'input',
|
|
73
|
+
role: 'member',
|
|
74
|
+
},
|
|
75
|
+
elements: [{ type: 'text', text: elements }],
|
|
76
|
+
contact: {
|
|
77
|
+
scene: 'private',
|
|
78
|
+
peer: 'input',
|
|
79
|
+
sub_peer: '',
|
|
80
|
+
},
|
|
81
|
+
group_id: '',
|
|
82
|
+
raw_message: elements,
|
|
83
|
+
};
|
|
84
|
+
const e = new KarinMessage(message);
|
|
85
|
+
e.bot = this;
|
|
86
|
+
/**
|
|
87
|
+
* 快速回复 开发者不应该使用这个方法,应该使用由karin封装过后的reply方法
|
|
88
|
+
*/
|
|
89
|
+
e.replyCallback = async (elements) => {
|
|
90
|
+
this.SendMessage(e.contact, elements);
|
|
91
|
+
return { message_id: e.message_id };
|
|
92
|
+
};
|
|
93
|
+
listener.emit('message', e);
|
|
94
|
+
}
|
|
95
|
+
async #MsgToFile(type, file) {
|
|
96
|
+
if (!msgToFile)
|
|
97
|
+
return '';
|
|
98
|
+
// 判断是否为string 如果是则继续判断是否为url、path
|
|
99
|
+
if (typeof file === 'string') {
|
|
100
|
+
if (file.startsWith('http'))
|
|
101
|
+
return file;
|
|
102
|
+
if (common.exists(file))
|
|
103
|
+
return file;
|
|
104
|
+
}
|
|
105
|
+
const buffer = await common.buffer(file);
|
|
106
|
+
// 生成文件名 根据type生成不同的文件后缀
|
|
107
|
+
const name = `${Date.now()}.${type === 'image' ? 'jpg' : type === 'voice' ? 'mp3' : 'file'}`;
|
|
108
|
+
// 写入文件
|
|
109
|
+
fs.writeFileSync(`./temp/input/${name}`, buffer);
|
|
110
|
+
return `[${type === 'image' ? '图片' : '语音'}: http://${ip}:${config.Server.http.port}/api/input?name=${name}&token=${token} ]`;
|
|
111
|
+
}
|
|
112
|
+
async GetVersion() {
|
|
113
|
+
const data = this.version;
|
|
114
|
+
delete data.name;
|
|
115
|
+
return data;
|
|
116
|
+
}
|
|
117
|
+
async SendMessage(_contact, elements) {
|
|
118
|
+
const text = [];
|
|
119
|
+
for (const v of elements) {
|
|
120
|
+
switch (v.type) {
|
|
121
|
+
case 'at':
|
|
122
|
+
text.push(`@${v.uid}`);
|
|
123
|
+
break;
|
|
124
|
+
case 'face':
|
|
125
|
+
text.push(`[表情:${v.id}]`);
|
|
126
|
+
break;
|
|
127
|
+
case 'text':
|
|
128
|
+
text.push(v.text);
|
|
129
|
+
break;
|
|
130
|
+
case 'image':
|
|
131
|
+
case 'voice':
|
|
132
|
+
text.push(await this.#MsgToFile(v.type, v.file));
|
|
133
|
+
break;
|
|
134
|
+
default:
|
|
135
|
+
text.push(`[未知消息类型:${JSON.stringify(v)}]`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
this.logger('info', text.join(''));
|
|
139
|
+
return { message_id: 'input' };
|
|
140
|
+
}
|
|
141
|
+
getAvatarUrl() {
|
|
142
|
+
return 'https://p.qlogo.cn/gh/967068507/967068507/0';
|
|
143
|
+
}
|
|
144
|
+
getGroupAvatar() {
|
|
145
|
+
return 'https://p.qlogo.cn/gh/967068507/967068507/0';
|
|
146
|
+
}
|
|
147
|
+
async GetCurrentAccount() {
|
|
148
|
+
return { account_uid: 'input', account_uin: 'input', account_name: 'input' };
|
|
149
|
+
}
|
|
150
|
+
async GetEssenceMessageList() { throw new Error('Method not implemented.'); }
|
|
151
|
+
async DownloadForwardMessage() { throw new Error('Method not implemented.'); }
|
|
152
|
+
async SetEssenceMessage() { throw new Error('Method not implemented.'); }
|
|
153
|
+
async DeleteEssenceMessage() { throw new Error('Method not implemented.'); }
|
|
154
|
+
async SetFriendApplyResult() { throw new Error('Method not implemented.'); }
|
|
155
|
+
async SetGroupApplyResultRequest() { throw new Error('Method not implemented.'); }
|
|
156
|
+
async SetInvitedJoinGroupResult() { throw new Error('Method not implemented.'); }
|
|
157
|
+
async ReactMessageWithEmojiRequest() { throw new Error('Method not implemented.'); }
|
|
158
|
+
async UploadPrivateFile() { throw new Error('Method not implemented.'); }
|
|
159
|
+
async UploadGroupFile() { throw new Error('Method not implemented.'); }
|
|
160
|
+
async UploadForwardMessage() { throw new Error('Method not implemented.'); }
|
|
161
|
+
async sendForwardMessage() { throw new Error('Method not implemented.'); }
|
|
162
|
+
async SendMessageByResId() { throw new Error('Method not implemented.'); }
|
|
163
|
+
async RecallMessage() { throw new Error('Method not implemented.'); }
|
|
164
|
+
async GetMessage() { throw new Error('Method not implemented.'); }
|
|
165
|
+
async GetHistoryMessage() { throw new Error('Method not implemented.'); }
|
|
166
|
+
async VoteUser() { throw new Error('Method not implemented.'); }
|
|
167
|
+
async KickMember() { throw new Error('Method not implemented.'); }
|
|
168
|
+
async BanMember() { throw new Error('Method not implemented.'); }
|
|
169
|
+
async SetGroupWholeBan() { throw new Error('Method not implemented.'); }
|
|
170
|
+
async SetGroupAdmin() { throw new Error('Method not implemented.'); }
|
|
171
|
+
async ModifyMemberCard() { throw new Error('Method not implemented.'); }
|
|
172
|
+
async ModifyGroupName() { throw new Error('Method not implemented.'); }
|
|
173
|
+
async LeaveGroup() { throw new Error('Method not implemented.'); }
|
|
174
|
+
async SetGroupUniqueTitle() { throw new Error('Method not implemented.'); }
|
|
175
|
+
async GetStrangerProfileCard() { throw new Error('Method not implemented.'); }
|
|
176
|
+
async GetFriendList() { throw new Error('Method not implemented.'); }
|
|
177
|
+
async GetGroupInfo() { throw new Error('Method not implemented.'); }
|
|
178
|
+
async GetGroupList() { throw new Error('Method not implemented.'); }
|
|
179
|
+
async GetGroupMemberInfo() { throw new Error('Method not implemented.'); }
|
|
180
|
+
async GetGroupMemberList() { throw new Error('Method not implemented.'); }
|
|
181
|
+
async GetGroupHonor() { throw new Error('Method not implemented.'); }
|
|
182
|
+
}
|
|
183
|
+
if (enable) {
|
|
184
|
+
const bot = new AdapterInput();
|
|
185
|
+
bot.stdin();
|
|
186
|
+
/** 注册bot */
|
|
187
|
+
listener.emit('bot', { type: 'internal', bot });
|
|
188
|
+
}
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import WebSocket from 'ws';
|
|
2
2
|
import { IncomingMessage } from 'http';
|
|
3
3
|
import { KarinAdapter } from '../../types/adapter.js';
|
|
4
|
-
import {
|
|
4
|
+
import { contact, OneBot11Api, KarinElement, OneBot11Segment, CustomNodeSegment, OneBot11ApiParamsType, GroupInfo, KarinNodeElement } from '../../types/index.js';
|
|
5
5
|
/**
|
|
6
6
|
* @class OneBot11
|
|
7
7
|
* @extends KarinAdapter
|
|
8
8
|
*/
|
|
9
9
|
export declare class OneBot11 implements KarinAdapter {
|
|
10
10
|
#private;
|
|
11
|
-
/**
|
|
12
|
-
* 机器人QQ号
|
|
13
|
-
*/
|
|
14
|
-
self_id: string;
|
|
15
11
|
/**
|
|
16
12
|
* - 重连次数 仅正向ws使用
|
|
17
13
|
*/
|
|
@@ -30,6 +26,7 @@ export declare class OneBot11 implements KarinAdapter {
|
|
|
30
26
|
* @param connect - WebSocket连接地址
|
|
31
27
|
*/
|
|
32
28
|
client(connect: string): Promise<void>;
|
|
29
|
+
get self_id(): string;
|
|
33
30
|
/**
|
|
34
31
|
* 获取当前登录号信息
|
|
35
32
|
*/
|
|
@@ -38,121 +35,14 @@ export declare class OneBot11 implements KarinAdapter {
|
|
|
38
35
|
get isInit(): Promise<unknown>;
|
|
39
36
|
/**
|
|
40
37
|
* onebot11转karin
|
|
41
|
-
* @param {Array<{type: string, data: any}>} data onebot11格式消息
|
|
42
38
|
* @return karin格式消息
|
|
43
39
|
* */
|
|
44
|
-
AdapterConvertKarin(data: Array<OneBot11Segment>):
|
|
40
|
+
AdapterConvertKarin(data: Array<OneBot11Segment>): Array<KarinElement>;
|
|
45
41
|
/**
|
|
46
42
|
* karin转onebot11
|
|
47
43
|
* @param data karin格式消息
|
|
48
|
-
* @return {Array<{type: string, data: any}>} onebot11格式消息
|
|
49
44
|
* */
|
|
50
|
-
KarinConvertAdapter(data: Array<KarinElement>):
|
|
51
|
-
type: string;
|
|
52
|
-
data: {
|
|
53
|
-
text: string;
|
|
54
|
-
id?: undefined;
|
|
55
|
-
qq?: undefined;
|
|
56
|
-
file?: undefined;
|
|
57
|
-
data?: undefined;
|
|
58
|
-
magic?: undefined;
|
|
59
|
-
type?: undefined;
|
|
60
|
-
};
|
|
61
|
-
} | {
|
|
62
|
-
type: string;
|
|
63
|
-
data: {
|
|
64
|
-
id: number;
|
|
65
|
-
text?: undefined;
|
|
66
|
-
qq?: undefined;
|
|
67
|
-
file?: undefined;
|
|
68
|
-
data?: undefined;
|
|
69
|
-
magic?: undefined;
|
|
70
|
-
type?: undefined;
|
|
71
|
-
};
|
|
72
|
-
} | {
|
|
73
|
-
type: string;
|
|
74
|
-
data: {
|
|
75
|
-
qq: string;
|
|
76
|
-
text?: undefined;
|
|
77
|
-
id?: undefined;
|
|
78
|
-
file?: undefined;
|
|
79
|
-
data?: undefined;
|
|
80
|
-
magic?: undefined;
|
|
81
|
-
type?: undefined;
|
|
82
|
-
};
|
|
83
|
-
} | {
|
|
84
|
-
type: string;
|
|
85
|
-
data: {
|
|
86
|
-
id: string;
|
|
87
|
-
text?: undefined;
|
|
88
|
-
qq?: undefined;
|
|
89
|
-
file?: undefined;
|
|
90
|
-
data?: undefined;
|
|
91
|
-
magic?: undefined;
|
|
92
|
-
type?: undefined;
|
|
93
|
-
};
|
|
94
|
-
} | {
|
|
95
|
-
type: "file" | "video" | "image";
|
|
96
|
-
data: {
|
|
97
|
-
file: string;
|
|
98
|
-
text?: undefined;
|
|
99
|
-
id?: undefined;
|
|
100
|
-
qq?: undefined;
|
|
101
|
-
data?: undefined;
|
|
102
|
-
magic?: undefined;
|
|
103
|
-
type?: undefined;
|
|
104
|
-
};
|
|
105
|
-
} | {
|
|
106
|
-
type: "json" | "xml";
|
|
107
|
-
data: {
|
|
108
|
-
data: string;
|
|
109
|
-
text?: undefined;
|
|
110
|
-
id?: undefined;
|
|
111
|
-
qq?: undefined;
|
|
112
|
-
file?: undefined;
|
|
113
|
-
magic?: undefined;
|
|
114
|
-
type?: undefined;
|
|
115
|
-
};
|
|
116
|
-
} | {
|
|
117
|
-
type: string;
|
|
118
|
-
data: {
|
|
119
|
-
file: string;
|
|
120
|
-
magic: boolean;
|
|
121
|
-
text?: undefined;
|
|
122
|
-
id?: undefined;
|
|
123
|
-
qq?: undefined;
|
|
124
|
-
data?: undefined;
|
|
125
|
-
type?: undefined;
|
|
126
|
-
};
|
|
127
|
-
} | {
|
|
128
|
-
type: "markdown";
|
|
129
|
-
data: {
|
|
130
|
-
content: string;
|
|
131
|
-
custom_template_id: string;
|
|
132
|
-
params: Array<{
|
|
133
|
-
key: string;
|
|
134
|
-
values: Array<string>;
|
|
135
|
-
}>;
|
|
136
|
-
text?: undefined;
|
|
137
|
-
id?: undefined;
|
|
138
|
-
qq?: undefined;
|
|
139
|
-
file?: undefined;
|
|
140
|
-
data?: undefined;
|
|
141
|
-
magic?: undefined;
|
|
142
|
-
type?: undefined;
|
|
143
|
-
};
|
|
144
|
-
} | {
|
|
145
|
-
type: string;
|
|
146
|
-
data: {
|
|
147
|
-
type: number;
|
|
148
|
-
id: number;
|
|
149
|
-
text?: undefined;
|
|
150
|
-
qq?: undefined;
|
|
151
|
-
file?: undefined;
|
|
152
|
-
data?: undefined;
|
|
153
|
-
magic?: undefined;
|
|
154
|
-
};
|
|
155
|
-
})[];
|
|
45
|
+
KarinConvertAdapter(data: Array<KarinElement>): Array<OneBot11Segment>;
|
|
156
46
|
/**
|
|
157
47
|
* 专属当前Bot的日志打印方法
|
|
158
48
|
*/
|
|
@@ -202,36 +92,30 @@ export declare class OneBot11 implements KarinAdapter {
|
|
|
202
92
|
* @param elements - nodes
|
|
203
93
|
* @returns - 资源id
|
|
204
94
|
* */
|
|
205
|
-
UploadForwardMessage(contact:
|
|
206
|
-
scene: Scene;
|
|
207
|
-
peer: string;
|
|
208
|
-
}, elements: any[]): Promise<any>;
|
|
95
|
+
UploadForwardMessage(contact: contact, elements: KarinNodeElement[]): Promise<any>;
|
|
209
96
|
/**
|
|
210
97
|
* 通过资源id发送转发消息
|
|
211
98
|
* @param contact - 联系人信息
|
|
212
99
|
* @param id - 资源id
|
|
213
100
|
* */
|
|
214
|
-
SendMessageByResId(contact: {
|
|
215
|
-
scene: Scene;
|
|
216
|
-
peer: string;
|
|
217
|
-
}, id: any): Promise<{
|
|
101
|
+
SendMessageByResId(contact: contact, id: string): Promise<{
|
|
218
102
|
message_id: any;
|
|
219
103
|
message_time: number;
|
|
220
104
|
}>;
|
|
221
105
|
/**
|
|
222
106
|
* 撤回消息
|
|
223
|
-
* @param
|
|
107
|
+
* @param _contact - ob11无需提供contact参数
|
|
224
108
|
* @param message_id - 消息ID
|
|
225
109
|
* @returns {Promise<null>}
|
|
226
110
|
*/
|
|
227
111
|
RecallMessage(_contact: contact, message_id: string): Promise<any>;
|
|
228
112
|
/**
|
|
229
113
|
* 获取消息
|
|
230
|
-
* @param
|
|
114
|
+
* @param _contact - ob11无需提供contact参数
|
|
231
115
|
* @param message_id - 消息ID
|
|
232
116
|
* @returns {Promise<object>} - 消息内容
|
|
233
117
|
*/
|
|
234
|
-
GetMessage(_contact:
|
|
118
|
+
GetMessage(_contact: contact, message_id: string): Promise<any>;
|
|
235
119
|
/**
|
|
236
120
|
* 获取msg_id获取历史消息
|
|
237
121
|
* @description 此api各平台实现不同,暂时废弃
|
|
@@ -242,7 +126,7 @@ export declare class OneBot11 implements KarinAdapter {
|
|
|
242
126
|
message_seq: any;
|
|
243
127
|
contact: contact;
|
|
244
128
|
sender: any;
|
|
245
|
-
elements:
|
|
129
|
+
elements: KarinElement[];
|
|
246
130
|
}[]>;
|
|
247
131
|
/**
|
|
248
132
|
* 获取合并转发消息
|
|
@@ -340,18 +224,8 @@ export declare class OneBot11 implements KarinAdapter {
|
|
|
340
224
|
* 获取群信息
|
|
341
225
|
* @param group_id - 群号
|
|
342
226
|
* @param no_cache - 是否不使用缓存
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
GetGroupInfo(group_id: string, no_cache?: boolean): Promise<{
|
|
346
|
-
group_id: any;
|
|
347
|
-
group_name: any;
|
|
348
|
-
group_remark: any;
|
|
349
|
-
max_member_count: any;
|
|
350
|
-
member_count: any;
|
|
351
|
-
group_uin: any;
|
|
352
|
-
admins: any;
|
|
353
|
-
owner: any;
|
|
354
|
-
}>;
|
|
227
|
+
*/
|
|
228
|
+
GetGroupInfo(group_id: string, no_cache?: boolean): Promise<GroupInfo>;
|
|
355
229
|
/**
|
|
356
230
|
* 获取群列表
|
|
357
231
|
*/
|
|
@@ -12,10 +12,6 @@ export class OneBot11 {
|
|
|
12
12
|
* 是否初始化
|
|
13
13
|
*/
|
|
14
14
|
#init = false;
|
|
15
|
-
/**
|
|
16
|
-
* 机器人QQ号
|
|
17
|
-
*/
|
|
18
|
-
self_id;
|
|
19
15
|
/**
|
|
20
16
|
* - 重连次数 仅正向ws使用
|
|
21
17
|
*/
|
|
@@ -25,7 +21,6 @@ export class OneBot11 {
|
|
|
25
21
|
adapter;
|
|
26
22
|
version;
|
|
27
23
|
constructor() {
|
|
28
|
-
this.self_id = '';
|
|
29
24
|
this.index = 0;
|
|
30
25
|
this.account = { uid: '', uin: '', name: '' };
|
|
31
26
|
this.adapter = { id: 'QQ', name: 'OneBot11', type: 'ws', sub_type: 'internal', start_time: Date.now(), connect: '' };
|
|
@@ -108,6 +103,9 @@ export class OneBot11 {
|
|
|
108
103
|
await this.getSelf();
|
|
109
104
|
this.#init = true;
|
|
110
105
|
}
|
|
106
|
+
get self_id() {
|
|
107
|
+
return this.account.uid || this.account.uin;
|
|
108
|
+
}
|
|
111
109
|
/**
|
|
112
110
|
* 获取当前登录号信息
|
|
113
111
|
*/
|
|
@@ -537,7 +535,6 @@ export class OneBot11 {
|
|
|
537
535
|
}
|
|
538
536
|
/**
|
|
539
537
|
* onebot11转karin
|
|
540
|
-
* @param {Array<{type: string, data: any}>} data onebot11格式消息
|
|
541
538
|
* @return karin格式消息
|
|
542
539
|
* */
|
|
543
540
|
AdapterConvertKarin(data) {
|
|
@@ -593,12 +590,9 @@ export class OneBot11 {
|
|
|
593
590
|
/**
|
|
594
591
|
* karin转onebot11
|
|
595
592
|
* @param data karin格式消息
|
|
596
|
-
* @return {Array<{type: string, data: any}>} onebot11格式消息
|
|
597
593
|
* */
|
|
598
594
|
KarinConvertAdapter(data) {
|
|
599
595
|
const elements = [];
|
|
600
|
-
// const selfUin = this.account.uin
|
|
601
|
-
// const selfNick = this.account.name
|
|
602
596
|
for (const i of data) {
|
|
603
597
|
switch (i.type) {
|
|
604
598
|
case 'text':
|
|
@@ -619,37 +613,35 @@ export class OneBot11 {
|
|
|
619
613
|
elements.push({ type: i.type, data: { file: i.file } });
|
|
620
614
|
break;
|
|
621
615
|
}
|
|
622
|
-
case 'xml':
|
|
616
|
+
case 'xml': {
|
|
617
|
+
elements.push({ type: 'xml', data: { data: i.data } });
|
|
618
|
+
break;
|
|
619
|
+
}
|
|
623
620
|
case 'json': {
|
|
624
|
-
elements.push({ type:
|
|
621
|
+
elements.push({ type: 'json', data: { data: i.data } });
|
|
625
622
|
break;
|
|
626
623
|
}
|
|
627
|
-
// case 'node': {
|
|
628
|
-
// let { type, user_id = selfUin, nickname = selfNick, content } = i
|
|
629
|
-
// content = this.KarinConvertAdapter(content)
|
|
630
|
-
// elements.push({ type, data: { uin: user_id, name: nickname, content } })
|
|
631
|
-
// break
|
|
632
|
-
// }
|
|
633
624
|
case 'forward': {
|
|
634
625
|
elements.push({ type: 'forward', data: { id: i.res_id } });
|
|
635
626
|
break;
|
|
636
627
|
}
|
|
628
|
+
case 'record':
|
|
637
629
|
case 'voice': {
|
|
638
630
|
elements.push({ type: 'record', data: { file: i.file, magic: i.magic || false } });
|
|
639
631
|
break;
|
|
640
632
|
}
|
|
641
633
|
case 'music': {
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
634
|
+
if (i.id) {
|
|
635
|
+
elements.push({ type: 'music', data: { type: i.platform, id: i.id } });
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
const { url, audio, title, author, pic } = i;
|
|
639
|
+
elements.push({ type: 'music', data: { type: 'custom', url, audio, title, content: author, image: pic } });
|
|
640
|
+
}
|
|
648
641
|
break;
|
|
649
642
|
}
|
|
650
643
|
case 'button': {
|
|
651
|
-
|
|
652
|
-
// elements.push({ type: 'button', data: { buttons: i.buttons } })
|
|
644
|
+
elements.push({ type: 'button', data: i.data });
|
|
653
645
|
break;
|
|
654
646
|
}
|
|
655
647
|
case 'markdown': {
|
|
@@ -657,19 +649,51 @@ export class OneBot11 {
|
|
|
657
649
|
elements.push({ type, data: { ...data } });
|
|
658
650
|
break;
|
|
659
651
|
}
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
652
|
+
case 'rows': {
|
|
653
|
+
for (const val of i.rows) {
|
|
654
|
+
elements.push({ type: 'button', data: val.data });
|
|
655
|
+
}
|
|
656
|
+
break;
|
|
657
|
+
}
|
|
666
658
|
case 'poke': {
|
|
667
659
|
elements.push({ type: 'poke', data: { type: i.poke_type, id: i.id } });
|
|
668
660
|
break;
|
|
669
661
|
}
|
|
662
|
+
case 'bubble_face': {
|
|
663
|
+
elements.push({ type: 'bubble_face', data: { id: i.id, count: i.count } });
|
|
664
|
+
break;
|
|
665
|
+
}
|
|
666
|
+
case 'contact': {
|
|
667
|
+
elements.push({ type: 'contact', data: { type: i.scene, id: i.peer } });
|
|
668
|
+
break;
|
|
669
|
+
}
|
|
670
|
+
case 'location': {
|
|
671
|
+
elements.push({ type: 'location', data: { lat: i.lat, lon: i.lon, title: i.title, content: i.address } });
|
|
672
|
+
break;
|
|
673
|
+
}
|
|
674
|
+
case 'long_msg':
|
|
675
|
+
case 'basketball':
|
|
676
|
+
case 'dice':
|
|
677
|
+
case 'market_face':
|
|
678
|
+
case 'rps': {
|
|
679
|
+
elements.push({ type: i.type, data: { id: i.id } });
|
|
680
|
+
break;
|
|
681
|
+
}
|
|
682
|
+
case 'gift': {
|
|
683
|
+
elements.push({ type: 'gift', data: { qq: i.qq, id: i.id } });
|
|
684
|
+
break;
|
|
685
|
+
}
|
|
686
|
+
case 'share': {
|
|
687
|
+
elements.push({ type: 'share', data: { url: i.url, title: i.title, content: i.content, image: i.image } });
|
|
688
|
+
break;
|
|
689
|
+
}
|
|
690
|
+
case 'weather': {
|
|
691
|
+
elements.push({ type: 'weather', data: { city: i.city, type: i.type } });
|
|
692
|
+
break;
|
|
693
|
+
}
|
|
670
694
|
default: {
|
|
671
695
|
elements.push(i);
|
|
672
|
-
|
|
696
|
+
break;
|
|
673
697
|
}
|
|
674
698
|
}
|
|
675
699
|
}
|
|
@@ -750,7 +774,14 @@ export class OneBot11 {
|
|
|
750
774
|
}
|
|
751
775
|
const { scene, peer } = contact;
|
|
752
776
|
const message_type = scene === 'group' ? 'group_id' : 'user_id';
|
|
753
|
-
const messages =
|
|
777
|
+
const messages = [];
|
|
778
|
+
const selfUin = this.account.uin;
|
|
779
|
+
const selfNick = this.account.name;
|
|
780
|
+
for (const i of elements) {
|
|
781
|
+
const { type, user_id, nickname, content: contents } = i;
|
|
782
|
+
const content = this.KarinConvertAdapter(contents);
|
|
783
|
+
messages.push({ type, data: { uin: user_id || selfUin, name: nickname || selfNick, content } });
|
|
784
|
+
}
|
|
754
785
|
const params = { [message_type]: String(peer), messages };
|
|
755
786
|
return await this.SendApi('send_forward_msg', params);
|
|
756
787
|
}
|
|
@@ -770,7 +801,7 @@ export class OneBot11 {
|
|
|
770
801
|
}
|
|
771
802
|
/**
|
|
772
803
|
* 撤回消息
|
|
773
|
-
* @param
|
|
804
|
+
* @param _contact - ob11无需提供contact参数
|
|
774
805
|
* @param message_id - 消息ID
|
|
775
806
|
* @returns {Promise<null>}
|
|
776
807
|
*/
|
|
@@ -779,7 +810,7 @@ export class OneBot11 {
|
|
|
779
810
|
}
|
|
780
811
|
/**
|
|
781
812
|
* 获取消息
|
|
782
|
-
* @param
|
|
813
|
+
* @param _contact - ob11无需提供contact参数
|
|
783
814
|
* @param message_id - 消息ID
|
|
784
815
|
* @returns {Promise<object>} - 消息内容
|
|
785
816
|
*/
|
|
@@ -991,22 +1022,8 @@ export class OneBot11 {
|
|
|
991
1022
|
* 获取群信息
|
|
992
1023
|
* @param group_id - 群号
|
|
993
1024
|
* @param no_cache - 是否不使用缓存
|
|
994
|
-
* @returns {Promise<IGroupInfo>} - 群信息
|
|
995
1025
|
*/
|
|
996
1026
|
async GetGroupInfo(group_id, no_cache = false) {
|
|
997
|
-
/**
|
|
998
|
-
* @type {{
|
|
999
|
-
* group_id: number,
|
|
1000
|
-
* group_name: string,
|
|
1001
|
-
* group_memo: string,
|
|
1002
|
-
* group_remark: string,
|
|
1003
|
-
* group_create_time: number,
|
|
1004
|
-
* group_level: number,
|
|
1005
|
-
* member_count: number,
|
|
1006
|
-
* max_member_count: number,
|
|
1007
|
-
* admins: number[]
|
|
1008
|
-
* }}
|
|
1009
|
-
*/
|
|
1010
1027
|
const groupInfo = await this.SendApi('get_group_info', { group_id, no_cache });
|
|
1011
1028
|
return {
|
|
1012
1029
|
group_id: groupInfo.group_id,
|
package/lib/core/index.d.ts
CHANGED
package/lib/core/index.js
CHANGED
package/lib/core/listener.js
CHANGED
|
@@ -2,6 +2,8 @@ import { EventEmitter } from 'events'
|
|
|
2
2
|
import { pluginLoader } from './plugin.loader.js'
|
|
3
3
|
import { common, logger, config } from '../utils/index.js'
|
|
4
4
|
import { MessageHandler } from '../event/message.handler.js'
|
|
5
|
+
import NoticeHandler from '../event/notice.handler.js'
|
|
6
|
+
import RequestHandler from '../event/request.handler.js'
|
|
5
7
|
/**
|
|
6
8
|
* 监听器管理
|
|
7
9
|
*/
|
|
@@ -33,11 +35,13 @@ class Listeners extends EventEmitter {
|
|
|
33
35
|
this.addAdapter(data)
|
|
34
36
|
})
|
|
35
37
|
this.on('bot', data => {
|
|
36
|
-
this.addBot(data)
|
|
38
|
+
if (!this.addBot(data)) { return }
|
|
37
39
|
logger.info(`[机器人][注册][${data.type}] ` + logger.green(`[account:${data.bot.account.uid || data.bot.account.uin}(${data.bot.account.name})]`))
|
|
38
40
|
this.emit('karin:online', data.bot.account.uid || data.bot.account.uin)
|
|
39
41
|
})
|
|
40
42
|
this.on('message', data => new MessageHandler(data))
|
|
43
|
+
this.on('notice', data => new NoticeHandler(data))
|
|
44
|
+
this.on('request', data => new RequestHandler(data))
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
/**
|
|
@@ -47,7 +51,7 @@ class Listeners extends EventEmitter {
|
|
|
47
51
|
this.index++
|
|
48
52
|
const index = this.index
|
|
49
53
|
if (!data.bot) {
|
|
50
|
-
logger.error('[Bot管理][注册] 注册失败: Bot实例不能为空')
|
|
54
|
+
logger.error('[Bot管理][注册] 注册失败: Bot实例不能为空', JSON.stringify(data))
|
|
51
55
|
return false
|
|
52
56
|
}
|
|
53
57
|
this.list.push({ index, type: data.type, bot: data.bot })
|
package/lib/core/server.js
CHANGED
|
@@ -76,6 +76,32 @@ export const server = new (class Server {
|
|
|
76
76
|
process.exit()
|
|
77
77
|
}
|
|
78
78
|
})
|
|
79
|
+
/** 控制台适配器 */
|
|
80
|
+
this.app.get('/api/input', (req, res) => {
|
|
81
|
+
const name = req.query.name
|
|
82
|
+
const token = req.query.token
|
|
83
|
+
if (!name || !token) {
|
|
84
|
+
logger.error('[HTTP][input] 缺少参数', req.query)
|
|
85
|
+
return res.status(403).json({ error: '禁止访问', message: '缺少参数' })
|
|
86
|
+
}
|
|
87
|
+
// 禁止键入向上级目录
|
|
88
|
+
if (name.includes('/')) {
|
|
89
|
+
logger.error('[HTTP][input] 无效的文件名', name)
|
|
90
|
+
return res.status(403).json({ error: '禁止访问', message: '无效的文件名' })
|
|
91
|
+
}
|
|
92
|
+
const CfgToken = config.Config.AdapterInput.token
|
|
93
|
+
if (CfgToken === 'AdapterInput' || CfgToken !== token) {
|
|
94
|
+
logger.error('[HTTP][input] 无效的令牌', token)
|
|
95
|
+
return res.status(403).json({ error: '禁止访问', message: '无效的令牌' })
|
|
96
|
+
}
|
|
97
|
+
const file = process.cwd() + `/temp/input/${name}`
|
|
98
|
+
if (!fs.existsSync(file)) {
|
|
99
|
+
logger.error('[HTTP][input] 文件不存在', file)
|
|
100
|
+
return res.status(404).json({ error: '文件不存在', message: '找不到指定文件' })
|
|
101
|
+
}
|
|
102
|
+
logger.info(`${logger.yellow('[HTTP][input]')} ${logger.green(token)} file:${file}`)
|
|
103
|
+
res.sendFile(file)
|
|
104
|
+
})
|
|
79
105
|
/** 监听端口 */
|
|
80
106
|
const { host, port } = config.Server.http
|
|
81
107
|
this.server.listen(port, host, () => {
|
|
@@ -120,7 +120,7 @@ export default class EventHandler {
|
|
|
120
120
|
if (this.e.isGroup) {
|
|
121
121
|
review.GroupMsgPrint(this.e) && logger.bot('info', this.e.self_id, `${logger.green(`Send Group ${this.e.group_id}: `)}${ReplyLog}`)
|
|
122
122
|
} else {
|
|
123
|
-
logger.bot('info', this.e.self_id, `${logger.green(`Send private ${this.e.user_id}: `)}${ReplyLog}`)
|
|
123
|
+
this.e.self_id === 'input' && logger.bot('info', this.e.self_id, `${logger.green(`Send private ${this.e.user_id}: `)}${ReplyLog}`)
|
|
124
124
|
}
|
|
125
125
|
let message_id = ''
|
|
126
126
|
try {
|
package/lib/event/event.js
CHANGED
|
@@ -101,7 +101,7 @@ export class KarinEvent {
|
|
|
101
101
|
constructor ({ event, self_id, user_id, group_id = '', time, contact, sender, sub_event, event_id }) {
|
|
102
102
|
this.self_id = self_id
|
|
103
103
|
this.user_id = user_id
|
|
104
|
-
this.group_id = group_id
|
|
104
|
+
this.group_id = contact.scene === 'group' ? (contact.peer || group_id) : group_id
|
|
105
105
|
this.time = time
|
|
106
106
|
this.event = event
|
|
107
107
|
this.event_id = event_id
|
package/lib/index.d.ts
CHANGED
|
@@ -29,13 +29,14 @@ export declare const Renderer: {
|
|
|
29
29
|
export declare const Cfg: {
|
|
30
30
|
dir: string;
|
|
31
31
|
_path: string;
|
|
32
|
-
|
|
32
|
+
npmCfgDir: string;
|
|
33
33
|
change: Map<string, any>;
|
|
34
34
|
watcher: Map<string, any>;
|
|
35
35
|
review: boolean;
|
|
36
36
|
logger: import("log4js").Logger;
|
|
37
37
|
initCfg(): Promise<void>;
|
|
38
38
|
getPlugins(): string[];
|
|
39
|
+
checkPath(path: string): void;
|
|
39
40
|
dirPath(name: string, plugins: string[]): Promise<void>;
|
|
40
41
|
timeout(type?: "ws" | "grpc"): number;
|
|
41
42
|
readonly redis: import("./types/index.js").Redis;
|
package/lib/types/adapter.d.ts
CHANGED
package/lib/types/config.d.ts
CHANGED
|
@@ -130,6 +130,27 @@ export interface Config {
|
|
|
130
130
|
* 管理员列表
|
|
131
131
|
*/
|
|
132
132
|
admin: string[];
|
|
133
|
+
/**
|
|
134
|
+
*
|
|
135
|
+
*/
|
|
136
|
+
AdapterInput: {
|
|
137
|
+
/**
|
|
138
|
+
* - 是否开启input适配器
|
|
139
|
+
*/
|
|
140
|
+
enable: boolean;
|
|
141
|
+
/**
|
|
142
|
+
* - 是否将语音、图片、视频消息转为文件 转为文件后可通过url访问
|
|
143
|
+
*/
|
|
144
|
+
msgToFile: boolean;
|
|
145
|
+
/**
|
|
146
|
+
* - url访问token 如果为 AdapterInput 每次启动后会重新生成
|
|
147
|
+
*/
|
|
148
|
+
token: string;
|
|
149
|
+
/**
|
|
150
|
+
* - ip地址
|
|
151
|
+
*/
|
|
152
|
+
ip: string;
|
|
153
|
+
};
|
|
133
154
|
/**
|
|
134
155
|
* 黑名单相关
|
|
135
156
|
*/
|
package/lib/utils/common.d.ts
CHANGED
|
@@ -77,7 +77,7 @@ export declare const common: {
|
|
|
77
77
|
* @param - 为true时,http地址会直接返回,否则会下载文件并转换为base64字符串
|
|
78
78
|
* @returns 返回base64字符串
|
|
79
79
|
*/
|
|
80
|
-
base64(file:
|
|
80
|
+
base64(file: any, options?: {
|
|
81
81
|
http: boolean;
|
|
82
82
|
}): Promise<string>;
|
|
83
83
|
/**
|
|
@@ -88,12 +88,11 @@ export declare const common: {
|
|
|
88
88
|
stream(stream: Readable): Promise<Buffer>;
|
|
89
89
|
/**
|
|
90
90
|
* 将文件转换为Buffer对象
|
|
91
|
-
* @param
|
|
92
|
-
* @param
|
|
93
|
-
* @
|
|
94
|
-
* @returns {Promise<Buffer>} - 返回Buffer对象
|
|
91
|
+
* @param file - 文件路径或Buffer对象、可读流对象、http地址、base64://字符串
|
|
92
|
+
* @param options - 选项
|
|
93
|
+
* @returns - 返回Buffer对象
|
|
95
94
|
*/
|
|
96
|
-
buffer(file:
|
|
95
|
+
buffer(file: any, options?: {
|
|
97
96
|
http: boolean;
|
|
98
97
|
}): Promise<Buffer | Error | string>;
|
|
99
98
|
/**
|
package/lib/utils/common.js
CHANGED
|
@@ -233,10 +233,9 @@ export const common = new (class Common {
|
|
|
233
233
|
|
|
234
234
|
/**
|
|
235
235
|
* 将文件转换为Buffer对象
|
|
236
|
-
* @param
|
|
237
|
-
* @param
|
|
238
|
-
* @
|
|
239
|
-
* @returns {Promise<Buffer>} - 返回Buffer对象
|
|
236
|
+
* @param file - 文件路径或Buffer对象、可读流对象、http地址、base64://字符串
|
|
237
|
+
* @param options - 选项
|
|
238
|
+
* @returns - 返回Buffer对象
|
|
240
239
|
*/
|
|
241
240
|
async buffer (file, options = { http: false }) {
|
|
242
241
|
if (typeof file !== 'string') {
|
package/lib/utils/config.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { Redis, App, Config, Server, Package, GroupCfg } from '../types/index.js
|
|
|
6
6
|
export declare const config: {
|
|
7
7
|
dir: string;
|
|
8
8
|
_path: string;
|
|
9
|
-
|
|
9
|
+
npmCfgDir: string;
|
|
10
10
|
change: Map<string, any>;
|
|
11
11
|
watcher: Map<string, any>;
|
|
12
12
|
review: boolean;
|
|
@@ -14,6 +14,10 @@ export declare const config: {
|
|
|
14
14
|
/** 初始化配置 */
|
|
15
15
|
initCfg(): Promise<void>;
|
|
16
16
|
getPlugins(): string[];
|
|
17
|
+
/**
|
|
18
|
+
* 检查路径是否存在 不存在则创建
|
|
19
|
+
*/
|
|
20
|
+
checkPath(path: string): void;
|
|
17
21
|
/**
|
|
18
22
|
* 为每一个插件建立对应的文件夹
|
|
19
23
|
*/
|
package/lib/utils/config.js
CHANGED
|
@@ -6,7 +6,7 @@ import { fs, yaml as Yaml, chokidar } from '../modules.js'
|
|
|
6
6
|
export const config = new (class Cfg {
|
|
7
7
|
dir
|
|
8
8
|
_path
|
|
9
|
-
|
|
9
|
+
npmCfgDir
|
|
10
10
|
change
|
|
11
11
|
watcher
|
|
12
12
|
review
|
|
@@ -14,7 +14,7 @@ export const config = new (class Cfg {
|
|
|
14
14
|
constructor () {
|
|
15
15
|
this.dir = karinDir
|
|
16
16
|
this._path = process.cwd() + '/config'
|
|
17
|
-
this.
|
|
17
|
+
this.npmCfgDir = this.dir + '/config/defSet'
|
|
18
18
|
/** 缓存 */
|
|
19
19
|
this.change = new Map()
|
|
20
20
|
/** 监听文件 */
|
|
@@ -26,18 +26,23 @@ export const config = new (class Cfg {
|
|
|
26
26
|
|
|
27
27
|
/** 初始化配置 */
|
|
28
28
|
async initCfg () {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
const list = [
|
|
30
|
+
this._path,
|
|
31
|
+
this._path + '/config',
|
|
32
|
+
process.cwd() + '/temp/input',
|
|
33
|
+
'./plugins',
|
|
34
|
+
'./plugins/karin-plugin-example',
|
|
35
|
+
]
|
|
36
|
+
list.forEach(path => this.checkPath(path))
|
|
37
|
+
if (this.npmCfgDir !== (this._path + '/defSet').replace(/\\/g, '/')) {
|
|
38
|
+
const files = fs.readdirSync(this.npmCfgDir).filter(file => file.endsWith('.yaml'))
|
|
39
|
+
files.forEach(file => {
|
|
40
|
+
const path = `${this._path}/config/${file}`
|
|
41
|
+
const pathDef = `${this.npmCfgDir}/${file}`
|
|
42
|
+
if (!fs.existsSync(path)) { fs.copyFileSync(pathDef, path) }
|
|
43
|
+
})
|
|
37
44
|
}
|
|
38
45
|
// 创建插件文件夹文件夹
|
|
39
|
-
if (!fs.existsSync('./plugins')) { fs.mkdirSync('./plugins') }
|
|
40
|
-
if (!fs.existsSync('./plugins/karin-plugin-example')) { fs.mkdirSync('./plugins/karin-plugin-example') }
|
|
41
46
|
const plugins = this.getPlugins()
|
|
42
47
|
this.dirPath('data', plugins)
|
|
43
48
|
this.dirPath('temp', plugins)
|
|
@@ -52,15 +57,22 @@ export const config = new (class Cfg {
|
|
|
52
57
|
return files.filter(file => file.isDirectory() && (file.name.startsWith('karin-plugin-'))).map(dir => dir.name)
|
|
53
58
|
}
|
|
54
59
|
|
|
60
|
+
/**
|
|
61
|
+
* 检查路径是否存在 不存在则创建
|
|
62
|
+
*/
|
|
63
|
+
checkPath (path) {
|
|
64
|
+
if (!fs.existsSync(path)) { fs.mkdirSync(path) }
|
|
65
|
+
}
|
|
66
|
+
|
|
55
67
|
/**
|
|
56
68
|
* 为每一个插件建立对应的文件夹
|
|
57
69
|
*/
|
|
58
70
|
async dirPath (name, plugins) {
|
|
59
71
|
name = `./${name}`
|
|
60
|
-
|
|
72
|
+
this.checkPath(name)
|
|
61
73
|
for (const plugin of plugins) {
|
|
62
74
|
const path = `${name}/${plugin}`
|
|
63
|
-
|
|
75
|
+
this.checkPath(path)
|
|
64
76
|
}
|
|
65
77
|
}
|
|
66
78
|
|
|
@@ -14,7 +14,7 @@ export declare class YamlEditor {
|
|
|
14
14
|
* @param path - 路径,用点号分隔,例如:'a.b.c'
|
|
15
15
|
* @param value - 要设置的值
|
|
16
16
|
*/
|
|
17
|
-
set(path: string | string[], value: string): null | undefined;
|
|
17
|
+
set(path: string | string[], value: string | boolean): null | undefined;
|
|
18
18
|
/**
|
|
19
19
|
* 向指定路径添加新值
|
|
20
20
|
* @param path - 路径,用点号分隔,例如:'a.b.c'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-karin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "基于 Kritor 进行开发的nodejs机器人框架",
|
|
6
6
|
"homepage": "https://github.com/KarinJS/Karin",
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"@grpc/grpc-js": "1.10.10",
|
|
61
61
|
"@grpc/proto-loader": "0.7.13",
|
|
62
|
+
"@inquirer/prompts": "^5.0.7",
|
|
62
63
|
"art-template": "4.13.2",
|
|
63
64
|
"axios": "1.7.2",
|
|
64
65
|
"chalk": "5.3.0",
|