node-karin 0.8.14 → 0.10.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 +2 -1
- package/lib/adapter/onebot/11/index.d.ts +2 -0
- package/lib/adapter/onebot/11/index.js +2 -0
- package/lib/event/review.handler.js +1 -0
- package/lib/render/client.js +15 -7
- package/lib/render/client_even.d.ts +30 -0
- package/lib/render/client_even.js +163 -0
- package/lib/types/adapter/api.d.ts +5 -1
- package/lib/utils/common.d.ts +13 -12
- package/lib/utils/common.js +42 -66
- package/package.json +1 -1
|
@@ -384,6 +384,7 @@ export declare class AdapterOneBot11 implements KarinAdapter {
|
|
|
384
384
|
uid: string;
|
|
385
385
|
uin: string;
|
|
386
386
|
nick: string;
|
|
387
|
+
role: Role;
|
|
387
388
|
age: number;
|
|
388
389
|
unique_title: string;
|
|
389
390
|
unique_title_expire_time: number;
|
|
@@ -406,6 +407,7 @@ export declare class AdapterOneBot11 implements KarinAdapter {
|
|
|
406
407
|
uid: string;
|
|
407
408
|
uin: string;
|
|
408
409
|
nick: string;
|
|
410
|
+
role: Role;
|
|
409
411
|
age: number;
|
|
410
412
|
unique_title: string;
|
|
411
413
|
unique_title_expire_time: number;
|
|
@@ -697,6 +697,7 @@ export class AdapterOneBot11 {
|
|
|
697
697
|
uid: target_uid_or_uin,
|
|
698
698
|
uin: target_uid_or_uin,
|
|
699
699
|
nick: info.nickname,
|
|
700
|
+
role: info.role,
|
|
700
701
|
age: info.age,
|
|
701
702
|
unique_title: info.title,
|
|
702
703
|
unique_title_expire_time: info.title_expire_time,
|
|
@@ -724,6 +725,7 @@ export class AdapterOneBot11 {
|
|
|
724
725
|
uid: user_id,
|
|
725
726
|
uin: user_id,
|
|
726
727
|
nick: v.nickname,
|
|
728
|
+
role: v.role,
|
|
727
729
|
age: v.age,
|
|
728
730
|
unique_title: v.title,
|
|
729
731
|
unique_title_expire_time: v.title_expire_time,
|
|
@@ -64,6 +64,7 @@ export const review = new (class Handler {
|
|
|
64
64
|
/** 同时启用 */
|
|
65
65
|
if (this.App.WhiteList.groups && this.App.BlackList.groups) {
|
|
66
66
|
this.GroupEnable = e => {
|
|
67
|
+
if (!e.group_id) { return false }
|
|
67
68
|
/** 白名单不为空 */
|
|
68
69
|
if (Array.isArray(this.Config.WhiteList.groups) && this.Config.WhiteList.groups.length) {
|
|
69
70
|
return this.Config.WhiteList.groups.includes(String(e.group_id))
|
package/lib/render/client.js
CHANGED
|
@@ -2,7 +2,7 @@ import fs from 'fs'
|
|
|
2
2
|
import WebSocket from 'ws'
|
|
3
3
|
import { render } from './app.js'
|
|
4
4
|
import { RenderBase } from './base.js'
|
|
5
|
-
import { randomUUID } from 'crypto'
|
|
5
|
+
import { createHash, randomUUID } from 'crypto'
|
|
6
6
|
import { listener } from '../core/index.js'
|
|
7
7
|
import { common, logger } from '../utils/index.js'
|
|
8
8
|
export class RenderClient extends RenderBase {
|
|
@@ -94,12 +94,20 @@ export class RenderClient extends RenderBase {
|
|
|
94
94
|
const filePath = decodeURIComponent(data.params.file)
|
|
95
95
|
logger.debug(`[渲染器:${this.id}][正向WS] 访问静态文件:${filePath}`)
|
|
96
96
|
const file = fs.readFileSync('.' + filePath)
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
97
|
+
const md5 = createHash('md5').update(file).digest('hex')
|
|
98
|
+
const params = data.params.md5?.includes(md5)
|
|
99
|
+
? {
|
|
100
|
+
echo: data.echo,
|
|
101
|
+
action: 'static',
|
|
102
|
+
status: 'ok',
|
|
103
|
+
data: { verifiedMd5: md5 },
|
|
104
|
+
}
|
|
105
|
+
: {
|
|
106
|
+
echo: data.echo,
|
|
107
|
+
action: 'static',
|
|
108
|
+
status: 'ok',
|
|
109
|
+
data: { file },
|
|
110
|
+
}
|
|
103
111
|
return this.ws.send(JSON.stringify(params))
|
|
104
112
|
}
|
|
105
113
|
/** 渲染结果 */
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import WebSocket from 'ws';
|
|
2
|
+
import { RenderBase } from './base.js';
|
|
3
|
+
import { KarinRenderType, RenderResult } from '../types/render.js';
|
|
4
|
+
export declare class RenderClientEven extends RenderBase {
|
|
5
|
+
url: string;
|
|
6
|
+
type: string;
|
|
7
|
+
id: string;
|
|
8
|
+
index: number;
|
|
9
|
+
retry: number;
|
|
10
|
+
reg: RegExp;
|
|
11
|
+
ws: WebSocket;
|
|
12
|
+
constructor(url: string);
|
|
13
|
+
/**
|
|
14
|
+
* 初始化
|
|
15
|
+
*/
|
|
16
|
+
start(): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* 创建连接
|
|
19
|
+
*/
|
|
20
|
+
link(): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* 接受消息
|
|
23
|
+
*/
|
|
24
|
+
message(str: string): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* 渲染标准方法
|
|
27
|
+
* @param options 渲染参数
|
|
28
|
+
*/
|
|
29
|
+
render<T extends KarinRenderType>(options: T): Promise<RenderResult<T>>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import axios from 'axios'
|
|
3
|
+
import WebSocket from 'ws'
|
|
4
|
+
import { render } from './app.js'
|
|
5
|
+
import { RenderBase } from './base.js'
|
|
6
|
+
import { createHash, randomUUID } from 'crypto'
|
|
7
|
+
import { listener } from '../core/index.js'
|
|
8
|
+
import { logger } from '../utils/index.js'
|
|
9
|
+
export class RenderClientEven extends RenderBase {
|
|
10
|
+
url
|
|
11
|
+
type
|
|
12
|
+
id
|
|
13
|
+
index
|
|
14
|
+
retry
|
|
15
|
+
reg
|
|
16
|
+
ws
|
|
17
|
+
constructor (url) {
|
|
18
|
+
super()
|
|
19
|
+
this.url = url
|
|
20
|
+
this.type = 'image'
|
|
21
|
+
this.id = 'puppeteer'
|
|
22
|
+
this.index = 0
|
|
23
|
+
this.retry = 0
|
|
24
|
+
this.reg = new RegExp(`(${process.cwd().replace(/\\/g, '\\\\')}|${process.cwd().replace(/\\/g, '/')})`, 'g')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 初始化
|
|
29
|
+
*/
|
|
30
|
+
async start () {
|
|
31
|
+
try {
|
|
32
|
+
const response = await axios.head(this.url)
|
|
33
|
+
if (response.status === 200) {
|
|
34
|
+
logger.mark(`[渲染器:${this.id}][WebSocket] 注册渲染器:${logger.green(this.url)}`)
|
|
35
|
+
try {
|
|
36
|
+
this.index = render.app({ id: this.id, type: this.type, render: this.render.bind(this) })
|
|
37
|
+
} catch (error) {
|
|
38
|
+
logger.error(`[渲染器:${this.id}] 注册渲染器失败:`, error)
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
logger.error(`[渲染器:${this.id}] 注册渲染器失败:渲染器发生错误`)
|
|
42
|
+
}
|
|
43
|
+
} catch (error) {
|
|
44
|
+
logger.error(`[渲染器:${this.id}] 注册渲染器失败:`, error)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 创建连接
|
|
50
|
+
*/
|
|
51
|
+
async link () {
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
54
|
+
return resolve()
|
|
55
|
+
}
|
|
56
|
+
/** 连接ws */
|
|
57
|
+
this.ws = new WebSocket(this.url)
|
|
58
|
+
/** 建立连接 */
|
|
59
|
+
this.ws.on('open', () => {
|
|
60
|
+
logger.mark(`[渲染器:${this.id}][WebSocket] 建立连接:${logger.green(this.url)}`)
|
|
61
|
+
/** 监听消息 */
|
|
62
|
+
this.ws.on('message', data => this.message(data.toString()))
|
|
63
|
+
resolve()
|
|
64
|
+
})
|
|
65
|
+
/** 监听断开 */
|
|
66
|
+
this.ws.once('close', async () => {
|
|
67
|
+
/** 停止监听 */
|
|
68
|
+
this.ws.removeAllListeners()
|
|
69
|
+
})
|
|
70
|
+
/** 监听错误 */
|
|
71
|
+
this.ws.on('error', async (e) => {
|
|
72
|
+
this.ws.close()
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 接受消息
|
|
79
|
+
*/
|
|
80
|
+
async message (str) {
|
|
81
|
+
const data = JSON.parse(str)
|
|
82
|
+
switch (data.action) {
|
|
83
|
+
/** 静态文件 */
|
|
84
|
+
case 'static': {
|
|
85
|
+
const filePath = decodeURIComponent(data.params.file)
|
|
86
|
+
logger.debug(`[渲染器:${this.id}][正向WS] 访问静态文件:${filePath}`)
|
|
87
|
+
const file = fs.readFileSync('.' + filePath)
|
|
88
|
+
const md5 = createHash('md5').update(file).digest('hex')
|
|
89
|
+
const params = data.params.md5?.includes(md5)
|
|
90
|
+
? {
|
|
91
|
+
echo: data.echo,
|
|
92
|
+
action: 'static',
|
|
93
|
+
status: 'ok',
|
|
94
|
+
data: { verifiedMd5: md5 },
|
|
95
|
+
}
|
|
96
|
+
: {
|
|
97
|
+
echo: data.echo,
|
|
98
|
+
action: 'static',
|
|
99
|
+
status: 'ok',
|
|
100
|
+
data: { file },
|
|
101
|
+
}
|
|
102
|
+
return this.ws.send(JSON.stringify(params))
|
|
103
|
+
}
|
|
104
|
+
/** 渲染结果 */
|
|
105
|
+
case 'renderRes': {
|
|
106
|
+
listener.emit(data.echo, data)
|
|
107
|
+
break
|
|
108
|
+
}
|
|
109
|
+
/** 超时 */
|
|
110
|
+
case 'timeout': {
|
|
111
|
+
logger.debug(`[渲染器:${this.id}][正向WS] 处理超时`)
|
|
112
|
+
break
|
|
113
|
+
}
|
|
114
|
+
/** 未知数据 */
|
|
115
|
+
default: {
|
|
116
|
+
logger.warn(`[渲染器:${this.id}] 收到未知数据:`, data)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 渲染标准方法
|
|
123
|
+
* @param options 渲染参数
|
|
124
|
+
*/
|
|
125
|
+
async render (options) {
|
|
126
|
+
/** 渲染模板 */
|
|
127
|
+
let file = options.file
|
|
128
|
+
let action = 'renderHtml'
|
|
129
|
+
if (options.file.includes('http') || options.vue) {
|
|
130
|
+
action = 'render'
|
|
131
|
+
} else {
|
|
132
|
+
file = this.dealTpl(options)
|
|
133
|
+
/** 判断是本地karin-puppeteer还是远程 */
|
|
134
|
+
if (!/127\.0\.0\.1|localhost/.test(this.url)) {
|
|
135
|
+
file = fs.readFileSync(file, 'utf-8').replace(this.reg, '')
|
|
136
|
+
} else {
|
|
137
|
+
action = 'render'
|
|
138
|
+
file = 'file://' + file
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (!file) {
|
|
142
|
+
logger.error(`[渲染器:${this.id}:${this.index}] 渲染文件不存在:${options.file}`)
|
|
143
|
+
return ''
|
|
144
|
+
}
|
|
145
|
+
/** 编码 */
|
|
146
|
+
file = encodeURIComponent(file)
|
|
147
|
+
const data = options
|
|
148
|
+
const echo = randomUUID()
|
|
149
|
+
/** 移除掉模板参数 */
|
|
150
|
+
if (data.data) { delete data.data }
|
|
151
|
+
data.file = file
|
|
152
|
+
const req = JSON.stringify({ echo, action, data })
|
|
153
|
+
logger.debug(`[渲染器:${this.id}:${this.index}][正向WS] 请求:${this.url} \nhtml: ${options.file} \ndata: ${JSON.stringify(data)}`)
|
|
154
|
+
await this.link()
|
|
155
|
+
this.ws.send(req)
|
|
156
|
+
return new Promise((resolve, reject) => {
|
|
157
|
+
listener.once(echo, (data) => {
|
|
158
|
+
if (data.ok) { return resolve(data.data) }
|
|
159
|
+
reject(new Error(JSON.stringify(data)))
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Contact, KarinElement, Sender } from '../index.js';
|
|
1
|
+
import { Contact, KarinElement, Role, Sender } from '../index.js';
|
|
2
2
|
/**
|
|
3
3
|
* - 基本消息结构
|
|
4
4
|
*/
|
|
@@ -211,6 +211,10 @@ export interface GroupMemberInfo {
|
|
|
211
211
|
* - 用户UIN
|
|
212
212
|
*/
|
|
213
213
|
uin: string;
|
|
214
|
+
/**
|
|
215
|
+
* - 用户角色
|
|
216
|
+
*/
|
|
217
|
+
role: Role;
|
|
214
218
|
/**
|
|
215
219
|
* - 用户昵称
|
|
216
220
|
*/
|
package/lib/utils/common.d.ts
CHANGED
|
@@ -102,28 +102,29 @@ declare class Common {
|
|
|
102
102
|
/**
|
|
103
103
|
* 将文件转换为不带前缀的base64字符串
|
|
104
104
|
* @param file - 文件路径或Buffer对象、可读流对象、http地址、base64://字符串
|
|
105
|
-
* @param -
|
|
106
|
-
* @param - 为true时,http地址会直接返回,否则会下载文件并转换为base64字符串
|
|
105
|
+
* @param options - 选项 http为true时返回http地址
|
|
107
106
|
* @returns 返回base64字符串
|
|
108
107
|
*/
|
|
109
|
-
base64(file:
|
|
108
|
+
base64(file: string | Buffer | Readable, options?: {
|
|
110
109
|
http: boolean;
|
|
111
110
|
}): Promise<string>;
|
|
111
|
+
/**
|
|
112
|
+
* 将文件转换为Buffer对象 仅支持标准格式
|
|
113
|
+
* @param file - 文件路径或Buffer对象、可读流对象、http地址、base64://字符串
|
|
114
|
+
* @param options - 选项 http为true时返回http地址
|
|
115
|
+
* @returns - 返回Buffer对象
|
|
116
|
+
*/
|
|
117
|
+
buffer<T extends {
|
|
118
|
+
http: boolean;
|
|
119
|
+
}>(file: string | Buffer | Readable, options?: T): Promise<T extends {
|
|
120
|
+
http: true;
|
|
121
|
+
} ? string : Buffer>;
|
|
112
122
|
/**
|
|
113
123
|
* 将数据流对象转换为Buffer对象
|
|
114
124
|
* @param {stream.Readable} stream - 要转换的数据流对象
|
|
115
125
|
* @returns {Promise<Buffer>} - 返回Buffer
|
|
116
126
|
*/
|
|
117
127
|
stream(stream: Readable): Promise<Buffer>;
|
|
118
|
-
/**
|
|
119
|
-
* 将文件转换为Buffer对象
|
|
120
|
-
* @param file - 文件路径或Buffer对象、可读流对象、http地址、base64://字符串
|
|
121
|
-
* @param options - 选项
|
|
122
|
-
* @returns - 返回Buffer对象
|
|
123
|
-
*/
|
|
124
|
-
buffer(file: any, options?: {
|
|
125
|
-
http: boolean;
|
|
126
|
-
}): Promise<Buffer | Error | string>;
|
|
127
128
|
/**
|
|
128
129
|
* 标准化发送的消息内容
|
|
129
130
|
* @param elements - 消息内容
|
package/lib/utils/common.js
CHANGED
|
@@ -33,12 +33,12 @@ class Common {
|
|
|
33
33
|
async downFile (fileUrl, savePath, param = {}) {
|
|
34
34
|
try {
|
|
35
35
|
this.mkdir(path.dirname(savePath))
|
|
36
|
-
logger
|
|
36
|
+
logger.info(`[下载文件] ${fileUrl}`)
|
|
37
37
|
const response = await axios.get(fileUrl, { ...param, responseType: 'stream' })
|
|
38
38
|
await this.streamPipeline(response.data, fs.createWriteStream(savePath))
|
|
39
39
|
return true
|
|
40
40
|
} catch (err) {
|
|
41
|
-
logger
|
|
41
|
+
logger.error(`下载文件错误:${err}`)
|
|
42
42
|
return false
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -242,49 +242,59 @@ class Common {
|
|
|
242
242
|
/**
|
|
243
243
|
* 将文件转换为不带前缀的base64字符串
|
|
244
244
|
* @param file - 文件路径或Buffer对象、可读流对象、http地址、base64://字符串
|
|
245
|
-
* @param -
|
|
246
|
-
* @param - 为true时,http地址会直接返回,否则会下载文件并转换为base64字符串
|
|
245
|
+
* @param options - 选项 http为true时返回http地址
|
|
247
246
|
* @returns 返回base64字符串
|
|
248
247
|
*/
|
|
249
248
|
async base64 (file, options = { http: false }) {
|
|
250
|
-
/**
|
|
249
|
+
/** 非字符串 */
|
|
251
250
|
if (typeof file !== 'string') {
|
|
252
|
-
|
|
253
|
-
if (
|
|
254
|
-
|
|
255
|
-
}
|
|
256
|
-
/** 可读流 */
|
|
257
|
-
if (file instanceof Readable) {
|
|
258
|
-
const data_1 = await this.stream(file)
|
|
259
|
-
return data_1.toString('base64')
|
|
260
|
-
}
|
|
261
|
-
/** 未知类型 */
|
|
262
|
-
throw new Error('未知类型')
|
|
251
|
+
if (Buffer.isBuffer(file)) { return file.toString('base64') }
|
|
252
|
+
if (file instanceof Readable) { return (await this.stream(file)).toString('base64') }
|
|
253
|
+
return file
|
|
263
254
|
}
|
|
264
255
|
/** base64:// */
|
|
265
|
-
if (file.startsWith('base64://')) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
/** url */
|
|
269
|
-
if (file.startsWith('http://') || file.startsWith('https://')) {
|
|
256
|
+
if (file.startsWith('base64://')) { return file.replace('base64://', '') }
|
|
257
|
+
/** http */
|
|
258
|
+
if (file.startsWith('http')) {
|
|
270
259
|
if (options.http) { return file }
|
|
271
260
|
const response = await axios.get(file, { responseType: 'arraybuffer' })
|
|
272
261
|
return Buffer.from(response.data, 'binary').toString('base64')
|
|
273
262
|
}
|
|
274
|
-
/** file:/// */
|
|
275
|
-
if (fs.existsSync(file.replace(/^file:\/\/\//, ''))) {
|
|
276
|
-
file = file.replace(/^file:\/\/\//, '')
|
|
277
|
-
return fs.readFileSync(file).toString('base64')
|
|
278
|
-
}
|
|
279
263
|
/** file:// */
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
264
|
+
const files = file.replace(/^file:\/\//, '')
|
|
265
|
+
if (fs.existsSync(files)) { return fs.readFileSync(file).toString('base64') }
|
|
266
|
+
/** 无前缀base64:// */
|
|
267
|
+
return Buffer.from(file, 'base64').toString('base64')
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* 将文件转换为Buffer对象 仅支持标准格式
|
|
272
|
+
* @param file - 文件路径或Buffer对象、可读流对象、http地址、base64://字符串
|
|
273
|
+
* @param options - 选项 http为true时返回http地址
|
|
274
|
+
* @returns - 返回Buffer对象
|
|
275
|
+
*/
|
|
276
|
+
async buffer (file, options) {
|
|
277
|
+
/** 非字符串 */
|
|
278
|
+
if (typeof file !== 'string') {
|
|
279
|
+
if (Buffer.isBuffer(file)) { return file }
|
|
280
|
+
if (file instanceof Readable) { return await this.stream(file) }
|
|
281
|
+
return file
|
|
282
|
+
}
|
|
283
|
+
/** base64 */
|
|
284
|
+
if (file.startsWith('base64://')) {
|
|
285
|
+
return Buffer.from(file.replace('base64://', ''), 'base64')
|
|
286
|
+
}
|
|
287
|
+
/** http */
|
|
288
|
+
if (file.startsWith('http')) {
|
|
289
|
+
if (options?.http) { return file }
|
|
290
|
+
const response = await axios.get(file, { responseType: 'arraybuffer' })
|
|
291
|
+
return Buffer.from(response.data)
|
|
283
292
|
}
|
|
293
|
+
/** file:// */
|
|
294
|
+
const files = file.replace(/^file:\/\//, '')
|
|
295
|
+
if (fs.existsSync(files)) { return fs.readFileSync(files) }
|
|
284
296
|
/** 无前缀base64:// */
|
|
285
|
-
|
|
286
|
-
if (buffer) { return file }
|
|
287
|
-
throw new Error('未知类型')
|
|
297
|
+
return Buffer.from(file, 'base64')
|
|
288
298
|
}
|
|
289
299
|
|
|
290
300
|
/**
|
|
@@ -301,40 +311,6 @@ class Common {
|
|
|
301
311
|
})
|
|
302
312
|
}
|
|
303
313
|
|
|
304
|
-
/**
|
|
305
|
-
* 将文件转换为Buffer对象
|
|
306
|
-
* @param file - 文件路径或Buffer对象、可读流对象、http地址、base64://字符串
|
|
307
|
-
* @param options - 选项
|
|
308
|
-
* @returns - 返回Buffer对象
|
|
309
|
-
*/
|
|
310
|
-
async buffer (file, options = { http: false }) {
|
|
311
|
-
if (typeof file !== 'string') {
|
|
312
|
-
if (Buffer.isBuffer(file)) { return file }
|
|
313
|
-
if (file instanceof Readable) { return this.stream(file) }
|
|
314
|
-
throw new Error('未知文件类型:' + file)
|
|
315
|
-
}
|
|
316
|
-
if (file.startsWith('base64://')) { return Buffer.from(file.replace('base64://', ''), 'base64') }
|
|
317
|
-
if (file.startsWith('http://') || file.startsWith('https://')) {
|
|
318
|
-
if (options.http) { return file }
|
|
319
|
-
const response = await axios.get(file, { responseType: 'arraybuffer' })
|
|
320
|
-
return Buffer.from(response.data)
|
|
321
|
-
}
|
|
322
|
-
/** file:/// */
|
|
323
|
-
if (fs.existsSync(file.replace(/^file:\/\/\//, ''))) {
|
|
324
|
-
file = file.replace(/^file:\/\/\//, '')
|
|
325
|
-
return fs.readFileSync(file)
|
|
326
|
-
}
|
|
327
|
-
/** file:// */
|
|
328
|
-
if (fs.existsSync(file.replace(/^file:\/\//, ''))) {
|
|
329
|
-
file = file.replace(/^file:\/\//, '')
|
|
330
|
-
return fs.readFileSync(file)
|
|
331
|
-
}
|
|
332
|
-
/** 无前缀base64:// */
|
|
333
|
-
const buffer = Buffer.from(file, 'base64')
|
|
334
|
-
if (buffer.toString('base64') === file) { return buffer }
|
|
335
|
-
throw new Error('未知类型')
|
|
336
|
-
}
|
|
337
|
-
|
|
338
314
|
/**
|
|
339
315
|
* 标准化发送的消息内容
|
|
340
316
|
* @param elements - 消息内容
|