node-karin 0.11.13 → 0.11.15

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.
Files changed (61) hide show
  1. package/config/defSet/config.yaml +3 -3
  2. package/config/view/config.yaml +5 -5
  3. package/lib/adapter/index.js +2 -2
  4. package/lib/cli/index.d.ts +7 -3
  5. package/lib/cli/index.js +258 -233
  6. package/lib/cli/init.js +15 -14
  7. package/lib/cli/karin.js +15 -15
  8. package/lib/cli/pkg.d.ts +4 -0
  9. package/lib/cli/pkg.js +14 -0
  10. package/lib/cli/start.js +8 -0
  11. package/lib/core/index.js +10 -10
  12. package/lib/core/init/config.d.ts +0 -4
  13. package/lib/core/init/config.js +0 -13
  14. package/lib/core/init/init.js +1 -0
  15. package/lib/core/listener/listener.js +1 -1
  16. package/lib/core/process/process.js +2 -6
  17. package/lib/core/server/server.js +13 -1
  18. package/lib/db/index.js +2 -2
  19. package/lib/db/level/level.js +0 -1
  20. package/lib/db/redis/redis_level.d.ts +2 -0
  21. package/lib/db/redis/redis_level.js +12 -11
  22. package/lib/event/index.js +5 -5
  23. package/lib/modules/art-template.js +1 -1
  24. package/lib/modules/axios.js +2 -2
  25. package/lib/modules/chalk.js +2 -2
  26. package/lib/modules/chokidar.js +2 -2
  27. package/lib/modules/commander.js +2 -2
  28. package/lib/modules/express.js +3 -3
  29. package/lib/modules/level.js +2 -2
  30. package/lib/modules/lodash.js +1 -1
  31. package/lib/modules/log4js.js +2 -2
  32. package/lib/modules/moment.js +1 -1
  33. package/lib/modules/node-schedule.js +2 -2
  34. package/lib/modules/redis.js +2 -2
  35. package/lib/modules/ws.js +3 -3
  36. package/lib/modules/yaml.js +2 -2
  37. package/lib/render/app.js +82 -81
  38. package/lib/render/base.js +54 -54
  39. package/lib/render/client.js +144 -142
  40. package/lib/render/client_even.js +140 -137
  41. package/lib/render/http.js +40 -41
  42. package/lib/render/index.js +6 -6
  43. package/lib/render/server.js +93 -88
  44. package/lib/render/wormhole.js +153 -151
  45. package/lib/types/config/config.d.ts +2 -2
  46. package/lib/types/index.js +13 -13
  47. package/lib/types/type/global.d.ts +2 -0
  48. package/lib/utils/index.d.ts +2 -0
  49. package/lib/utils/index.js +13 -11
  50. package/lib/utils/tools/exec.d.ts +5 -17
  51. package/lib/utils/tools/exec.js +28 -26
  52. package/lib/utils/tools/ffmpeg.d.ts +2 -2
  53. package/lib/utils/tools/restart.d.ts +15 -0
  54. package/lib/utils/tools/restart.js +39 -0
  55. package/lib/utils/tools/stop.d.ts +7 -0
  56. package/lib/utils/tools/stop.js +13 -0
  57. package/lib/utils/tools/update.d.ts +26 -84
  58. package/lib/utils/tools/update.js +40 -28
  59. package/package.json +6 -3
  60. package/lib/cli/dev.js +0 -3
  61. /package/lib/cli/{dev.d.ts → start.d.ts} +0 -0
package/lib/render/app.js CHANGED
@@ -1,18 +1,17 @@
1
- import { logger } from '../utils/index.js'
1
+ import { logger } from '../utils/index.js';
2
2
  class Renderers {
3
- index
4
- Apps
5
- constructor () {
6
- /** 索引 */
7
- this.index = 0
8
- /**
3
+ index;
4
+ Apps;
5
+ constructor() {
6
+ /** 索引 */
7
+ this.index = 0;
8
+ /**
9
9
  * 渲染器列表
10
10
  * @type {APP[]}
11
11
  */
12
- this.Apps = []
13
- }
14
-
15
- /**
12
+ this.Apps = [];
13
+ }
14
+ /**
16
15
  * 注册渲染器
17
16
  * @param data 渲染器数据
18
17
  * @param data.id 渲染器ID
@@ -20,100 +19,102 @@ class Renderers {
20
19
  * @param ata.render 渲染器标准方法
21
20
  * @returns 渲染器索引
22
21
  */
23
- app (data) {
24
- this.index++
25
- const index = this.index
26
- const { id, type = 'image', render } = data
27
- if (!id) { throw new Error('[注册渲染器失败] 缺少渲染器ID') }
28
- if (!type) { throw new Error('[注册渲染器失败] 缺少渲染器类型') }
29
- if (!render) { throw new Error('[注册渲染器失败] 缺少渲染器标准方法') }
30
- const time = Date.now()
31
- const options = { index, id, type, render, time }
32
- this.Apps.push(options)
33
- logger.mark(`${logger.violet(`[渲染器:${index}]`)} 注册成功: ` + logger.green(id))
34
- return index
35
- }
36
-
37
- /**
22
+ app(data) {
23
+ this.index++;
24
+ const index = this.index;
25
+ const { id, type = 'image', render } = data;
26
+ if (!id)
27
+ throw new Error('[注册渲染器失败] 缺少渲染器ID');
28
+ if (!type)
29
+ throw new Error('[注册渲染器失败] 缺少渲染器类型');
30
+ if (!render)
31
+ throw new Error('[注册渲染器失败] 缺少渲染器标准方法');
32
+ const time = Date.now();
33
+ const options = { index, id, type, render, time };
34
+ this.Apps.push(options);
35
+ logger.mark(`${logger.violet(`[渲染器:${index}]`)} 注册成功: ` + logger.green(id));
36
+ return index;
37
+ }
38
+ /**
38
39
  * 卸载渲染器
39
40
  * @param index 渲染器索引
40
41
  * @returns 是否卸载成功
41
42
  */
42
- unapp (index) {
43
- const app = this.Apps.find(app => app.index === index)
44
- if (!app) {
45
- logger.error(`[卸载渲染器失败] 未找到渲染器索引:${index}`)
46
- return false
43
+ unapp(index) {
44
+ const app = this.Apps.find(app => app.index === index);
45
+ if (!app) {
46
+ logger.error(`[卸载渲染器失败] 未找到渲染器索引:${index}`);
47
+ return false;
48
+ }
49
+ this.Apps = this.Apps.filter(app => app.index !== index);
50
+ logger.mark(`[卸载渲染器] ${app.id}`);
51
+ return true;
47
52
  }
48
- this.Apps = this.Apps.filter(app => app.index !== index)
49
- logger.mark(`[卸载渲染器] ${app.id}`)
50
- return true
51
- }
52
-
53
- /**
53
+ /**
54
54
  * 返回渲染器实例 未键入id返回第一个
55
55
  * @param id 渲染器ID
56
56
  * @returns 渲染器实例
57
57
  */
58
- App (id = '') {
59
- if (this.Apps.length === 0) { throw new Error('[调用渲染器失败] 渲染器列表为空') }
60
- if (!id) { return this.Apps[0] }
61
- /** 筛选出id一致的渲染器 */
62
- const app = this.Apps.find(app => app.id === id)
63
- if (!app) { throw new Error(`[调用渲染器失败] 未找到渲染器:${id}`) }
64
- return app
65
- }
66
-
67
- /**
58
+ App(id = '') {
59
+ if (this.Apps.length === 0)
60
+ throw new Error('[调用渲染器失败] 渲染器列表为空');
61
+ if (!id)
62
+ return this.Apps[0];
63
+ /** 筛选出id一致的渲染器 */
64
+ const app = this.Apps.find(app => app.id === id);
65
+ if (!app)
66
+ throw new Error(`[调用渲染器失败] 未找到渲染器:${id}`);
67
+ return app;
68
+ }
69
+ /**
68
70
  * 调用标准渲染器
69
71
  */
70
- async render (options, id) {
71
- const res = this.App(id)
72
- if (typeof options.multiPage === 'number' || options.multiPage === true) {
73
- const result = await res.render(options)
74
- return result
75
- } else {
76
- const result = await res.render(options)
77
- return result
72
+ async render(options, id) {
73
+ const res = this.App(id);
74
+ if (typeof options.multiPage === 'number' || options.multiPage === true) {
75
+ const result = await res.render(options);
76
+ return result;
77
+ }
78
+ else {
79
+ const result = await res.render(options);
80
+ return result;
81
+ }
78
82
  }
79
- }
80
-
81
- /**
83
+ /**
82
84
  * 快速渲染
83
85
  * @param data html路径、http地址
84
86
  * @returns 返回图片base64或数组
85
87
  */
86
- async renderHtml (data) {
87
- return this.render({
88
- file: data,
89
- name: 'render',
90
- pageGotoParams: {
91
- waitUntil: 'networkidle2',
92
- },
93
- })
94
- }
95
-
96
- /**
88
+ async renderHtml(data) {
89
+ return this.render({
90
+ file: data,
91
+ name: 'render',
92
+ pageGotoParams: {
93
+ waitUntil: 'networkidle2',
94
+ },
95
+ });
96
+ }
97
+ /**
97
98
  * 快速分片渲染
98
99
  * @param data html路径、http地址
99
100
  * @param multiPage 分片高度 自动计算传true
100
101
  */
101
- async renderMultiHtml (data, multiPage) {
102
- return await this.render({
103
- file: data,
104
- name: 'render',
105
- multiPage,
106
- pageGotoParams: {
107
- waitUntil: 'networkidle2',
108
- },
109
- })
110
- }
102
+ async renderMultiHtml(data, multiPage) {
103
+ return await this.render({
104
+ file: data,
105
+ name: 'render',
106
+ multiPage,
107
+ pageGotoParams: {
108
+ waitUntil: 'networkidle2',
109
+ },
110
+ });
111
+ }
111
112
  }
112
113
  /**
113
114
  * 渲染器管理器
114
115
  */
115
- export const render = new Renderers()
116
+ export const render = new Renderers();
116
117
  /**
117
118
  * @description 即将废弃,请使用 `render`
118
119
  */
119
- export const Renderer = render
120
+ export const Renderer = render;
@@ -1,69 +1,69 @@
1
- import fs from 'fs'
2
- import chokidar from 'chokidar'
3
- import template from 'art-template'
4
- import { common, logger } from '../utils/index.js'
1
+ import fs from 'fs';
2
+ import chokidar from 'chokidar';
3
+ import template from 'art-template';
4
+ import { common, logger } from '../utils/index.js';
5
5
  /**
6
6
  * 渲染器基类 所有渲染器都应该继承这个类
7
7
  */
8
8
  export class RenderBase {
9
- dir
10
- html
11
- watcher
12
- constructor () {
13
- this.dir = './temp/html'
14
- this.html = {}
15
- this.watcher = {}
16
- common.mkdir(this.dir)
17
- }
18
-
19
- /**
9
+ dir;
10
+ html;
11
+ watcher;
12
+ constructor() {
13
+ this.dir = './temp/html';
14
+ this.html = {};
15
+ this.watcher = {};
16
+ common.mkdir(this.dir);
17
+ }
18
+ /**
20
19
  * 模板渲染
21
20
  * @param options 模板名称
22
21
  * @param isAbs 是否返回绝对路径
23
22
  */
24
- dealTpl (options, isAbs = true) {
25
- let { name, fileID, file: tplFile } = options
26
- fileID = fileID || name
27
- const filePath = `./temp/html/${name}/${fileID}.html`
28
- /** 读取html模板 */
29
- if (!this.html[tplFile]) {
30
- common.mkdir(`./temp/html/${name}`)
31
- try {
32
- this.html[tplFile] = fs.readFileSync(tplFile, 'utf8')
33
- } catch (error) {
34
- logger.error(`加载html错误:${tplFile}`)
35
- return ''
36
- }
37
- this.watch(tplFile)
23
+ dealTpl(options, isAbs = true) {
24
+ let { name, fileID, file: tplFile } = options;
25
+ fileID = fileID || name;
26
+ const filePath = `./temp/html/${name}/${fileID}.html`;
27
+ /** 读取html模板 */
28
+ if (!this.html[tplFile]) {
29
+ common.mkdir(`./temp/html/${name}`);
30
+ try {
31
+ this.html[tplFile] = fs.readFileSync(tplFile, 'utf8');
32
+ }
33
+ catch (error) {
34
+ logger.error(`加载html错误:${tplFile}`);
35
+ return '';
36
+ }
37
+ this.watch(tplFile);
38
+ }
39
+ /** 替换模板 */
40
+ const tmpHtml = template.render(this.html[tplFile], options.data);
41
+ /** 保存模板 */
42
+ fs.writeFileSync(filePath, tmpHtml);
43
+ logger.debug(`[图片生成][使用模板] ${filePath}`);
44
+ /** 是否返回绝对路径 */
45
+ if (isAbs)
46
+ return `${process.cwd()}/temp/html/${name}/${fileID}.html`;
47
+ return filePath;
38
48
  }
39
- /** 替换模板 */
40
- const tmpHtml = template.render(this.html[tplFile], options.data)
41
- /** 保存模板 */
42
- fs.writeFileSync(filePath, tmpHtml)
43
- logger.debug(`[图片生成][使用模板] ${filePath}`)
44
- /** 是否返回绝对路径 */
45
- if (isAbs) { return `${process.cwd()}/temp/html/${name}/${fileID}.html` }
46
- return filePath
47
- }
48
-
49
- /**
49
+ /**
50
50
  * 监听模板文件
51
51
  * @param tplFile 模板文件路径
52
52
  */
53
- watch (tplFile) {
54
- if (this.watcher[tplFile]) { return }
55
- const watcher = chokidar.watch(tplFile)
56
- watcher.on('change', () => {
57
- delete this.html[tplFile]
58
- logger.mark(`[修改html模板] ${tplFile}`)
59
- })
60
- this.watcher[tplFile] = watcher
61
- }
62
-
63
- /**
53
+ watch(tplFile) {
54
+ if (this.watcher[tplFile])
55
+ return;
56
+ const watcher = chokidar.watch(tplFile);
57
+ watcher.on('change', () => {
58
+ delete this.html[tplFile];
59
+ logger.mark(`[修改html模板] ${tplFile}`);
60
+ });
61
+ this.watcher[tplFile] = watcher;
62
+ }
63
+ /**
64
64
  * 渲染标准方法
65
65
  */
66
- async render (options) {
67
- throw new Error('未实现渲染方法')
68
- }
66
+ async render(options) {
67
+ throw new Error('未实现渲染方法');
68
+ }
69
69
  }
@@ -1,156 +1,158 @@
1
- import fs from 'fs'
2
- import WebSocket from 'ws'
3
- import { render } from './app.js'
4
- import { RenderBase } from './base.js'
5
- import { createHash, randomUUID } from 'crypto'
6
- import { listener } from '../core/index.js'
7
- import { common, logger } from '../utils/index.js'
1
+ import fs from 'fs';
2
+ import WebSocket from 'ws';
3
+ import { render } from './app.js';
4
+ import { RenderBase } from './base.js';
5
+ import { createHash, randomUUID } from 'crypto';
6
+ import { listener } from '../core/index.js';
7
+ import { common, logger } from '../utils/index.js';
8
8
  export class RenderClient extends RenderBase {
9
- url
10
- type
11
- id
12
- index
13
- retry
14
- reg
15
- ws
16
- constructor (url) {
17
- super()
18
- this.url = url
19
- this.type = 'image'
20
- this.id = 'puppeteer'
21
- this.index = 0
22
- this.retry = 0
23
- this.reg = new RegExp(`(${process.cwd().replace(/\\/g, '\\\\')}|${process.cwd().replace(/\\/g, '/')})`, 'g')
24
- }
25
-
26
- /**
9
+ url;
10
+ type;
11
+ id;
12
+ index;
13
+ retry;
14
+ reg;
15
+ ws;
16
+ constructor(url) {
17
+ super();
18
+ this.url = url;
19
+ this.type = 'image';
20
+ this.id = 'puppeteer';
21
+ this.index = 0;
22
+ this.retry = 0;
23
+ this.reg = new RegExp(`(${process.cwd().replace(/\\/g, '\\\\')}|${process.cwd().replace(/\\/g, '/')})`, 'g');
24
+ }
25
+ /**
27
26
  * 初始化
28
27
  */
29
- async start () {
30
- /** 连接ws */
31
- this.ws = new WebSocket(this.url)
32
- /** 建立连接 */
33
- this.ws.on('open', () => {
34
- logger.mark(`[渲染器:${this.id}][WebSocket] 建立连接:${logger.green(this.url)}`)
35
- /** 注册渲染器 */
36
- try {
37
- this.index = render.app({ id: this.id, type: this.type, render: this.render.bind(this) })
38
- this.retry = 0
39
- } catch (error) {
40
- logger.error(`[渲染器:${this.id}] 注册渲染器失败:`, error)
41
- /** 断开连接 */
42
- this.ws.close()
43
- }
44
- /** 心跳 */
45
- this.heartbeat()
46
- /** 监听消息 */
47
- this.ws.on('message', data => this.message(data.toString()))
48
- })
49
- /** 监听断开 */
50
- this.ws.once('close', async () => {
51
- this.retry++
52
- /** 停止监听 */
53
- this.ws.removeAllListeners()
54
- /** 卸载渲染器 */
55
- this.index && render.unapp(this.index) && (this.index = 0)
56
- logger.warn(`[渲染器:${this.id}][重连次数:${this.retry}] 连接断开,5秒后将尝试重连:${this.url}`)
57
- await common.sleep(5000)
58
- await this.start()
59
- })
60
- /** 监听错误 */
61
- this.ws.on('error', async (e) => {
62
- logger.debug(e)
63
- await common.sleep(5000)
64
- this.ws.close()
65
- })
66
- }
67
-
68
- /**
28
+ async start() {
29
+ /** 连接ws */
30
+ this.ws = new WebSocket(this.url);
31
+ /** 建立连接 */
32
+ this.ws.on('open', () => {
33
+ logger.mark(`[渲染器:${this.id}][WebSocket] 建立连接:${logger.green(this.url)}`);
34
+ /** 注册渲染器 */
35
+ try {
36
+ this.index = render.app({ id: this.id, type: this.type, render: this.render.bind(this) });
37
+ this.retry = 0;
38
+ }
39
+ catch (error) {
40
+ logger.error(`[渲染器:${this.id}] 注册渲染器失败:`, error);
41
+ /** 断开连接 */
42
+ this.ws.close();
43
+ }
44
+ /** 心跳 */
45
+ this.heartbeat();
46
+ /** 监听消息 */
47
+ this.ws.on('message', data => this.message(data.toString()));
48
+ });
49
+ /** 监听断开 */
50
+ this.ws.once('close', async () => {
51
+ this.retry++;
52
+ /** 停止监听 */
53
+ this.ws.removeAllListeners();
54
+ /** 卸载渲染器 */
55
+ this.index && render.unapp(this.index) && (this.index = 0);
56
+ logger.warn(`[渲染器:${this.id}][重连次数:${this.retry}] 连接断开,5秒后将尝试重连:${this.url}`);
57
+ await common.sleep(5000);
58
+ await this.start();
59
+ });
60
+ /** 监听错误 */
61
+ this.ws.on('error', async (e) => {
62
+ logger.debug(e);
63
+ await common.sleep(5000);
64
+ this.ws.close();
65
+ });
66
+ }
67
+ /**
69
68
  * 心跳
70
69
  */
71
- async heartbeat () {
72
- /** 无限循环 错误则停止 */
73
- while (true) {
74
- try {
75
- this.ws.send(JSON.stringify({ action: 'heartbeat' }))
76
- logger.debug(`[渲染器:${this.id}] 心跳:${this.url}`)
77
- } catch (e) {
78
- logger.debug(`[渲染器:${this.id}] 心跳失败:`, e)
79
- this.ws.close()
80
- break
81
- }
82
- await common.sleep(5000)
70
+ async heartbeat() {
71
+ /** 无限循环 错误则停止 */
72
+ while (true) {
73
+ try {
74
+ this.ws.send(JSON.stringify({ action: 'heartbeat' }));
75
+ logger.debug(`[渲染器:${this.id}] 心跳:${this.url}`);
76
+ }
77
+ catch (e) {
78
+ logger.debug(`[渲染器:${this.id}] 心跳失败:`, e);
79
+ this.ws.close();
80
+ break;
81
+ }
82
+ await common.sleep(5000);
83
+ }
83
84
  }
84
- }
85
-
86
- /**
85
+ /**
87
86
  * 接受消息
88
87
  */
89
- async message (str) {
90
- const data = JSON.parse(str)
91
- switch (data.action) {
92
- /** 静态文件 */
93
- case 'static': {
94
- const filePath = decodeURIComponent(data.params.file)
95
- logger.debug(`[渲染器:${this.id}][正向WS] 访问静态文件:${filePath}`)
96
- const file = fs.readFileSync('.' + filePath)
97
- const md5 = createHash('md5').update(file).digest('hex')
98
- const params = data.params.md5?.includes(md5)
99
- ? { echo: data.echo, action: 'static', status: 'ok', data: { verifiedMd5: md5 } }
100
- : { echo: data.echo, action: 'static', status: 'ok', data: { file } }
101
- return this.ws.send(JSON.stringify(params))
102
- }
103
- /** 渲染结果 */
104
- case 'renderRes': {
105
- listener.emit(data.echo, data)
106
- break
107
- }
108
- /** 未知数据 */
109
- default: {
110
- logger.warn(`[渲染器:${this.id}] 收到未知数据:`, data)
111
- }
88
+ async message(str) {
89
+ const data = JSON.parse(str);
90
+ switch (data.action) {
91
+ /** 静态文件 */
92
+ case 'static': {
93
+ const filePath = decodeURIComponent(data.params.file);
94
+ logger.debug(`[渲染器:${this.id}][正向WS] 访问静态文件:${filePath}`);
95
+ const file = fs.readFileSync('.' + filePath);
96
+ const md5 = createHash('md5').update(file).digest('hex');
97
+ const params = data.params.md5?.includes(md5)
98
+ ? { echo: data.echo, action: 'static', status: 'ok', data: { verifiedMd5: md5 } }
99
+ : { echo: data.echo, action: 'static', status: 'ok', data: { file } };
100
+ return this.ws.send(JSON.stringify(params));
101
+ }
102
+ /** 渲染结果 */
103
+ case 'renderRes': {
104
+ listener.emit(data.echo, data);
105
+ break;
106
+ }
107
+ /** 未知数据 */
108
+ default: {
109
+ logger.warn(`[渲染器:${this.id}] 收到未知数据:`, data);
110
+ }
111
+ }
112
112
  }
113
- }
114
-
115
- /**
113
+ /**
116
114
  * 渲染标准方法
117
115
  * @param options 渲染参数
118
116
  */
119
- async render (options) {
120
- /** 渲染模板 */
121
- let file = options.file
122
- let action = 'renderHtml'
123
- if (options.file.includes('http') || options.vue) {
124
- action = 'render'
125
- } else {
126
- file = this.dealTpl(options)
127
- /** 判断是本地karin-puppeteer还是远程 */
128
- if (!/127\.0\.0\.1|localhost/.test(this.url)) {
129
- file = fs.readFileSync(file, 'utf-8').replace(this.reg, '')
130
- } else {
131
- action = 'render'
132
- file = 'file://' + file
133
- }
134
- }
135
- if (!file) {
136
- logger.error(`[渲染器:${this.id}:${this.index}] 渲染文件不存在:${options.file}`)
137
- return ''
117
+ async render(options) {
118
+ /** 渲染模板 */
119
+ let file = options.file;
120
+ let action = 'renderHtml';
121
+ if (options.file.includes('http') || options.vue) {
122
+ action = 'render';
123
+ }
124
+ else {
125
+ file = this.dealTpl(options);
126
+ /** 判断是本地karin-puppeteer还是远程 */
127
+ if (!/127\.0\.0\.1|localhost/.test(this.url)) {
128
+ file = fs.readFileSync(file, 'utf-8').replace(this.reg, '');
129
+ }
130
+ else {
131
+ action = 'render';
132
+ file = 'file://' + file;
133
+ }
134
+ }
135
+ if (!file) {
136
+ logger.error(`[渲染器:${this.id}:${this.index}] 渲染文件不存在:${options.file}`);
137
+ return '';
138
+ }
139
+ /** 编码 */
140
+ file = encodeURIComponent(file);
141
+ const data = options;
142
+ const echo = randomUUID();
143
+ /** 移除掉模板参数 */
144
+ if (data.data)
145
+ delete data.data;
146
+ data.file = file;
147
+ const req = JSON.stringify({ echo, action, data });
148
+ logger.debug(`[渲染器:${this.id}:${this.index}][正向WS] 请求:${this.url} \nhtml: ${options.file} \ndata: ${JSON.stringify(data)}`);
149
+ this.ws.send(req);
150
+ return new Promise((resolve, reject) => {
151
+ listener.once(echo, (data) => {
152
+ if (data.ok)
153
+ return resolve(data.data);
154
+ reject(new Error(JSON.stringify(data)));
155
+ });
156
+ });
138
157
  }
139
- /** 编码 */
140
- file = encodeURIComponent(file)
141
- const data = options
142
- const echo = randomUUID()
143
- /** 移除掉模板参数 */
144
- if (data.data) { delete data.data }
145
- data.file = file
146
- const req = JSON.stringify({ echo, action, data })
147
- logger.debug(`[渲染器:${this.id}:${this.index}][正向WS] 请求:${this.url} \nhtml: ${options.file} \ndata: ${JSON.stringify(data)}`)
148
- this.ws.send(req)
149
- return new Promise((resolve, reject) => {
150
- listener.once(echo, (data) => {
151
- if (data.ok) { return resolve(data.data) }
152
- reject(new Error(JSON.stringify(data)))
153
- })
154
- })
155
- }
156
158
  }