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.
- package/config/defSet/config.yaml +3 -3
- package/config/view/config.yaml +5 -5
- package/lib/adapter/index.js +2 -2
- package/lib/cli/index.d.ts +7 -3
- package/lib/cli/index.js +258 -233
- package/lib/cli/init.js +15 -14
- package/lib/cli/karin.js +15 -15
- package/lib/cli/pkg.d.ts +4 -0
- package/lib/cli/pkg.js +14 -0
- package/lib/cli/start.js +8 -0
- package/lib/core/index.js +10 -10
- package/lib/core/init/config.d.ts +0 -4
- package/lib/core/init/config.js +0 -13
- package/lib/core/init/init.js +1 -0
- package/lib/core/listener/listener.js +1 -1
- package/lib/core/process/process.js +2 -6
- package/lib/core/server/server.js +13 -1
- package/lib/db/index.js +2 -2
- package/lib/db/level/level.js +0 -1
- package/lib/db/redis/redis_level.d.ts +2 -0
- package/lib/db/redis/redis_level.js +12 -11
- package/lib/event/index.js +5 -5
- package/lib/modules/art-template.js +1 -1
- package/lib/modules/axios.js +2 -2
- package/lib/modules/chalk.js +2 -2
- package/lib/modules/chokidar.js +2 -2
- package/lib/modules/commander.js +2 -2
- package/lib/modules/express.js +3 -3
- package/lib/modules/level.js +2 -2
- package/lib/modules/lodash.js +1 -1
- package/lib/modules/log4js.js +2 -2
- package/lib/modules/moment.js +1 -1
- package/lib/modules/node-schedule.js +2 -2
- package/lib/modules/redis.js +2 -2
- package/lib/modules/ws.js +3 -3
- package/lib/modules/yaml.js +2 -2
- package/lib/render/app.js +82 -81
- package/lib/render/base.js +54 -54
- package/lib/render/client.js +144 -142
- package/lib/render/client_even.js +140 -137
- package/lib/render/http.js +40 -41
- package/lib/render/index.js +6 -6
- package/lib/render/server.js +93 -88
- package/lib/render/wormhole.js +153 -151
- package/lib/types/config/config.d.ts +2 -2
- package/lib/types/index.js +13 -13
- package/lib/types/type/global.d.ts +2 -0
- package/lib/utils/index.d.ts +2 -0
- package/lib/utils/index.js +13 -11
- package/lib/utils/tools/exec.d.ts +5 -17
- package/lib/utils/tools/exec.js +28 -26
- package/lib/utils/tools/ffmpeg.d.ts +2 -2
- package/lib/utils/tools/restart.d.ts +15 -0
- package/lib/utils/tools/restart.js +39 -0
- package/lib/utils/tools/stop.d.ts +7 -0
- package/lib/utils/tools/stop.js +13 -0
- package/lib/utils/tools/update.d.ts +26 -84
- package/lib/utils/tools/update.js +40 -28
- package/package.json +6 -3
- package/lib/cli/dev.js +0 -3
- /package/lib/cli/{dev.d.ts → start.d.ts} +0 -0
|
@@ -1,153 +1,156 @@
|
|
|
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'
|
|
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
9
|
export class RenderClientEven extends RenderBase {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
/**
|
|
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
|
+
/**
|
|
28
27
|
* 初始化
|
|
29
28
|
*/
|
|
30
|
-
|
|
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)}`)
|
|
29
|
+
async start() {
|
|
35
30
|
try {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
const response = await axios.head(this.url);
|
|
32
|
+
if (response.status === 200) {
|
|
33
|
+
logger.mark(`[渲染器:${this.id}][WebSocket] 注册渲染器:${logger.green(this.url)}`);
|
|
34
|
+
try {
|
|
35
|
+
this.index = render.app({ id: this.id, type: this.type, render: this.render.bind(this) });
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
logger.error(`[渲染器:${this.id}] 注册渲染器失败:`, error);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
logger.error(`[渲染器:${this.id}] 注册渲染器失败:渲染器发生错误`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
logger.error(`[渲染器:${this.id}] 注册渲染器失败:`, error);
|
|
39
47
|
}
|
|
40
|
-
} else {
|
|
41
|
-
logger.error(`[渲染器:${this.id}] 注册渲染器失败:渲染器发生错误`)
|
|
42
|
-
}
|
|
43
|
-
} catch (error) {
|
|
44
|
-
logger.error(`[渲染器:${this.id}] 注册渲染器失败:`, error)
|
|
45
48
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
+
/**
|
|
49
50
|
* 创建连接
|
|
50
51
|
*/
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
/**
|
|
52
|
+
async link() {
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
55
|
+
return resolve();
|
|
56
|
+
}
|
|
57
|
+
/** 连接ws */
|
|
58
|
+
this.ws = new WebSocket(this.url);
|
|
59
|
+
/** 建立连接 */
|
|
60
|
+
this.ws.on('open', () => {
|
|
61
|
+
logger.mark(`[渲染器:${this.id}][WebSocket] 建立连接:${logger.green(this.url)}`);
|
|
62
|
+
/** 监听消息 */
|
|
63
|
+
this.ws.on('message', data => this.message(data.toString()));
|
|
64
|
+
resolve();
|
|
65
|
+
});
|
|
66
|
+
/** 监听断开 */
|
|
67
|
+
this.ws.once('close', async () => {
|
|
68
|
+
/** 停止监听 */
|
|
69
|
+
this.ws.removeAllListeners();
|
|
70
|
+
});
|
|
71
|
+
/** 监听错误 */
|
|
72
|
+
this.ws.on('error', async (e) => {
|
|
73
|
+
this.ws.close();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
78
|
* 接受消息
|
|
79
79
|
*/
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
+
? { echo: data.echo, action: 'static', status: 'ok', data: { verifiedMd5: md5 } }
|
|
91
|
+
: { echo: data.echo, action: 'static', status: 'ok', data: { file } };
|
|
92
|
+
return this.ws.send(JSON.stringify(params));
|
|
93
|
+
}
|
|
94
|
+
/** 渲染结果 */
|
|
95
|
+
case 'renderRes': {
|
|
96
|
+
listener.emit(data.echo, data);
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
/** 超时 */
|
|
100
|
+
case 'timeout': {
|
|
101
|
+
logger.debug(`[渲染器:${this.id}][正向WS] 处理超时`);
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
/** 未知数据 */
|
|
105
|
+
default: {
|
|
106
|
+
logger.warn(`[渲染器:${this.id}] 收到未知数据:`, data);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
108
109
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
/**
|
|
110
|
+
/**
|
|
112
111
|
* 渲染标准方法
|
|
113
112
|
* @param options 渲染参数
|
|
114
113
|
*/
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
114
|
+
async render(options) {
|
|
115
|
+
/** 渲染模板 */
|
|
116
|
+
let file = options.file;
|
|
117
|
+
let action = 'renderHtml';
|
|
118
|
+
if (options.file.includes('http') || options.vue) {
|
|
119
|
+
action = 'render';
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
file = this.dealTpl(options);
|
|
123
|
+
/** 判断是本地karin-puppeteer还是远程 */
|
|
124
|
+
if (!/127\.0\.0\.1|localhost/.test(this.url)) {
|
|
125
|
+
file = fs.readFileSync(file, 'utf-8').replace(this.reg, '');
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
action = 'render';
|
|
129
|
+
file = 'file://' + file;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (!file) {
|
|
133
|
+
logger.error(`[渲染器:${this.id}:${this.index}] 渲染文件不存在:${options.file}`);
|
|
134
|
+
return '';
|
|
135
|
+
}
|
|
136
|
+
/** 编码 */
|
|
137
|
+
file = encodeURIComponent(file);
|
|
138
|
+
const data = options;
|
|
139
|
+
const echo = randomUUID();
|
|
140
|
+
/** 移除掉模板参数 */
|
|
141
|
+
if (data.data)
|
|
142
|
+
delete data.data;
|
|
143
|
+
data.file = file;
|
|
144
|
+
const req = JSON.stringify({ echo, action, data });
|
|
145
|
+
logger.debug(`[渲染器:${this.id}:${this.index}][正向WS] 请求:${this.url} \nhtml: ${options.file} \ndata: ${JSON.stringify(data)}`);
|
|
146
|
+
await this.link();
|
|
147
|
+
this.ws.send(req);
|
|
148
|
+
return new Promise((resolve, reject) => {
|
|
149
|
+
listener.once(echo, (data) => {
|
|
150
|
+
if (data.ok)
|
|
151
|
+
return resolve(data.data);
|
|
152
|
+
reject(new Error(JSON.stringify(data)));
|
|
153
|
+
});
|
|
154
|
+
});
|
|
134
155
|
}
|
|
135
|
-
/** 编码 */
|
|
136
|
-
file = encodeURIComponent(file)
|
|
137
|
-
const data = options
|
|
138
|
-
const echo = randomUUID()
|
|
139
|
-
/** 移除掉模板参数 */
|
|
140
|
-
if (data.data) { delete data.data }
|
|
141
|
-
data.file = file
|
|
142
|
-
const req = JSON.stringify({ echo, action, data })
|
|
143
|
-
logger.debug(`[渲染器:${this.id}:${this.index}][正向WS] 请求:${this.url} \nhtml: ${options.file} \ndata: ${JSON.stringify(data)}`)
|
|
144
|
-
await this.link()
|
|
145
|
-
this.ws.send(req)
|
|
146
|
-
return new Promise((resolve, reject) => {
|
|
147
|
-
listener.once(echo, (data) => {
|
|
148
|
-
if (data.ok) { return resolve(data.data) }
|
|
149
|
-
reject(new Error(JSON.stringify(data)))
|
|
150
|
-
})
|
|
151
|
-
})
|
|
152
|
-
}
|
|
153
156
|
}
|
package/lib/render/http.js
CHANGED
|
@@ -1,51 +1,50 @@
|
|
|
1
|
-
import axios from 'axios'
|
|
2
|
-
import { RenderBase } from './base.js'
|
|
3
|
-
import logger from '../utils/core/logger.js'
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { RenderBase } from './base.js';
|
|
3
|
+
import logger from '../utils/core/logger.js';
|
|
4
4
|
export class HttpRenderer extends RenderBase {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
id;
|
|
6
|
+
host;
|
|
7
|
+
url;
|
|
8
|
+
token;
|
|
9
|
+
/**
|
|
10
10
|
* 构造函数
|
|
11
11
|
* @param host - 静态服务器地址
|
|
12
12
|
* @param url - 渲染接口
|
|
13
13
|
* @param token - token
|
|
14
14
|
*/
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
/**
|
|
15
|
+
constructor(host, url, token) {
|
|
16
|
+
super();
|
|
17
|
+
this.id = 'puppeteer';
|
|
18
|
+
this.host = host;
|
|
19
|
+
this.url = url;
|
|
20
|
+
this.token = token;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
24
23
|
* 渲染
|
|
25
24
|
*/
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
25
|
+
async render(options) {
|
|
26
|
+
const name = options.name || 'render';
|
|
27
|
+
let file = options.file;
|
|
28
|
+
/** 非http渲染模板并转为http静态资源 */
|
|
29
|
+
if (!options.file.includes('http') && !options.vue) {
|
|
30
|
+
const isLocalhost = this.host.includes('127.0.0.1') || this.host.includes('localhost');
|
|
31
|
+
file = this.dealTpl(options, isLocalhost);
|
|
32
|
+
if (!file) {
|
|
33
|
+
logger.error(`[渲染器:${this.id}] 模板文件不存在:${name}`);
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
options.file = isLocalhost ? 'file://' + file : `${this.host}/api/renderHtml?html=${file}`;
|
|
37
|
+
}
|
|
38
|
+
delete options.data;
|
|
39
|
+
const data = options;
|
|
40
|
+
const headers = {
|
|
41
|
+
Authorization: this.token,
|
|
42
|
+
};
|
|
43
|
+
logger.debug(`[渲染器:${this.id}][POST] \n请求:${this.url} \nhtml: ${options.file} \ndata: ${JSON.stringify(data)}`);
|
|
44
|
+
const res = await axios({ method: 'post', url: this.url, headers, data });
|
|
45
|
+
if (res.status === 200 && res.data.ok) {
|
|
46
|
+
return res.data.data;
|
|
47
|
+
}
|
|
48
|
+
throw new Error(`渲染失败:${JSON.stringify(res.data)}`);
|
|
48
49
|
}
|
|
49
|
-
throw new Error(`渲染失败:${JSON.stringify(res.data)}`)
|
|
50
|
-
}
|
|
51
50
|
}
|
package/lib/render/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export * from './app.js'
|
|
2
|
-
export * from './base.js'
|
|
3
|
-
export * from './client.js'
|
|
4
|
-
export * from './http.js'
|
|
5
|
-
export * from './server.js'
|
|
6
|
-
export * from './wormhole.js'
|
|
1
|
+
export * from './app.js';
|
|
2
|
+
export * from './base.js';
|
|
3
|
+
export * from './client.js';
|
|
4
|
+
export * from './http.js';
|
|
5
|
+
export * from './server.js';
|
|
6
|
+
export * from './wormhole.js';
|
package/lib/render/server.js
CHANGED
|
@@ -1,96 +1,101 @@
|
|
|
1
|
-
import { render } from './app.js'
|
|
2
|
-
import { RenderBase } from './base.js'
|
|
3
|
-
import { randomUUID } from 'crypto'
|
|
4
|
-
import { logger } from '../utils/index.js'
|
|
5
|
-
import { listener } from '../core/index.js'
|
|
1
|
+
import { render } from './app.js';
|
|
2
|
+
import { RenderBase } from './base.js';
|
|
3
|
+
import { randomUUID } from 'crypto';
|
|
4
|
+
import { logger } from '../utils/index.js';
|
|
5
|
+
import { listener } from '../core/index.js';
|
|
6
6
|
class Puppeteer extends RenderBase {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async server (socket, request) {
|
|
23
|
-
this.socket = socket
|
|
24
|
-
this.id = request.headers['renderer-id']
|
|
25
|
-
this.type = request.headers['renderer-type']
|
|
26
|
-
/** 注册渲染器 */
|
|
27
|
-
this.host = request.headers.host
|
|
28
|
-
this.url = `ws://${this.host + request.url}`
|
|
29
|
-
logger.info(`[渲染器:${this.id}] 收到新的连接请求:` + logger.green(this.url))
|
|
30
|
-
/** 监听上报事件 */
|
|
31
|
-
this.socket.on('message', data => {
|
|
32
|
-
const json = JSON.parse(data.toString())
|
|
33
|
-
if (json.echo) {
|
|
34
|
-
listener.emit(json.echo, json)
|
|
35
|
-
} else if (json.action === 'heartbeat') {
|
|
36
|
-
logger.debug(`[渲染器:${this.id}] 收到心跳:${this.url}`)
|
|
37
|
-
} else {
|
|
38
|
-
logger.warn(`[渲染器:${this.id}] 收到未知数据:`, data)
|
|
39
|
-
}
|
|
40
|
-
})
|
|
41
|
-
/** 监听断开 */
|
|
42
|
-
this.socket.on('close', () => {
|
|
43
|
-
logger.warn(`[渲染器:${this.id}] 连接断开:${this.url}`)
|
|
44
|
-
/** 卸载渲染器 */
|
|
45
|
-
this.index && render.unapp(this.index)
|
|
46
|
-
this.index = 0
|
|
47
|
-
})
|
|
48
|
-
/** 注册渲染器 */
|
|
49
|
-
try {
|
|
50
|
-
const index = render.app({
|
|
51
|
-
id: this.id,
|
|
52
|
-
type: this.type,
|
|
53
|
-
render: this.render.bind(this),
|
|
54
|
-
})
|
|
55
|
-
this.index = index
|
|
56
|
-
} catch (error) {
|
|
57
|
-
logger.error(`[渲染器:${this.id}] 注册渲染器失败:`, error)
|
|
58
|
-
/** 断开连接 */
|
|
59
|
-
this.socket.close()
|
|
7
|
+
socket;
|
|
8
|
+
id;
|
|
9
|
+
type;
|
|
10
|
+
host;
|
|
11
|
+
url;
|
|
12
|
+
index;
|
|
13
|
+
constructor() {
|
|
14
|
+
super();
|
|
15
|
+
this.id = 0;
|
|
16
|
+
this.index = 0;
|
|
17
|
+
this.type = '';
|
|
18
|
+
this.host = '';
|
|
19
|
+
this.url = '';
|
|
60
20
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
21
|
+
async server(socket, request) {
|
|
22
|
+
this.socket = socket;
|
|
23
|
+
this.id = request.headers['renderer-id'];
|
|
24
|
+
this.type = request.headers['renderer-type'];
|
|
25
|
+
/** 注册渲染器 */
|
|
26
|
+
this.host = request.headers.host;
|
|
27
|
+
this.url = `ws://${this.host + request.url}`;
|
|
28
|
+
logger.info(`[渲染器:${this.id}] 收到新的连接请求:` + logger.green(this.url));
|
|
29
|
+
/** 监听上报事件 */
|
|
30
|
+
this.socket.on('message', data => {
|
|
31
|
+
const json = JSON.parse(data.toString());
|
|
32
|
+
if (json.echo) {
|
|
33
|
+
listener.emit(json.echo, json);
|
|
34
|
+
}
|
|
35
|
+
else if (json.action === 'heartbeat') {
|
|
36
|
+
logger.debug(`[渲染器:${this.id}] 收到心跳:${this.url}`);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
logger.warn(`[渲染器:${this.id}] 收到未知数据:`, data);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
/** 监听断开 */
|
|
43
|
+
this.socket.on('close', () => {
|
|
44
|
+
logger.warn(`[渲染器:${this.id}] 连接断开:${this.url}`);
|
|
45
|
+
/** 卸载渲染器 */
|
|
46
|
+
this.index && render.unapp(this.index);
|
|
47
|
+
this.index = 0;
|
|
48
|
+
});
|
|
49
|
+
/** 注册渲染器 */
|
|
50
|
+
try {
|
|
51
|
+
const index = render.app({
|
|
52
|
+
id: this.id,
|
|
53
|
+
type: this.type,
|
|
54
|
+
render: this.render.bind(this),
|
|
55
|
+
});
|
|
56
|
+
this.index = index;
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
logger.error(`[渲染器:${this.id}] 注册渲染器失败:`, error);
|
|
60
|
+
/** 断开连接 */
|
|
61
|
+
this.socket.close();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
64
65
|
* 渲染模板
|
|
65
66
|
* @param options 模板参数
|
|
66
67
|
*/
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
async render(options) {
|
|
69
|
+
/** 渲染模板 */
|
|
70
|
+
let file = '';
|
|
71
|
+
if (options.file.includes('http') || options.vue) {
|
|
72
|
+
file = options.file;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
file = 'file://' + this.dealTpl(options);
|
|
76
|
+
}
|
|
77
|
+
if (!file)
|
|
78
|
+
throw new Error(`[渲染器:${this.id}] 模板文件不存在:${options.name}`);
|
|
79
|
+
const echo = randomUUID();
|
|
80
|
+
const action = 'render';
|
|
81
|
+
const data = options;
|
|
82
|
+
/** 移除掉模板参数 */
|
|
83
|
+
if (data.data)
|
|
84
|
+
delete data.data;
|
|
85
|
+
data.file = file;
|
|
86
|
+
logger.debug(`[渲染器:${this.id}][反向WS] \n请求:${this.url} \nhtml: ${options.file} \ndata: ${JSON.stringify(data)}`);
|
|
87
|
+
this.socket.send(JSON.stringify({ echo, action, data }));
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
listener.once(echo, data => {
|
|
90
|
+
if (data.ok)
|
|
91
|
+
return resolve(data.data);
|
|
92
|
+
reject(new Error(JSON.stringify(data)));
|
|
93
|
+
});
|
|
94
|
+
});
|
|
74
95
|
}
|
|
75
|
-
if (!file) { throw new Error(`[渲染器:${this.id}] 模板文件不存在:${options.name}`) }
|
|
76
|
-
const echo = randomUUID()
|
|
77
|
-
const action = 'render'
|
|
78
|
-
const data = options
|
|
79
|
-
/** 移除掉模板参数 */
|
|
80
|
-
if (data.data) { delete data.data }
|
|
81
|
-
data.file = file
|
|
82
|
-
logger.debug(`[渲染器:${this.id}][反向WS] \n请求:${this.url} \nhtml: ${options.file} \ndata: ${JSON.stringify(data)}`)
|
|
83
|
-
this.socket.send(JSON.stringify({ echo, action, data }))
|
|
84
|
-
return new Promise((resolve, reject) => {
|
|
85
|
-
listener.once(echo, data => {
|
|
86
|
-
if (data.ok) { return resolve(data.data) }
|
|
87
|
-
reject(new Error(JSON.stringify(data)))
|
|
88
|
-
})
|
|
89
|
-
})
|
|
90
|
-
}
|
|
91
96
|
}
|
|
92
97
|
export const RenderServer = {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
98
|
+
type: 'render',
|
|
99
|
+
path: '/puppeteer',
|
|
100
|
+
adapter: Puppeteer,
|
|
101
|
+
};
|