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
@@ -1,154 +1,156 @@
1
- import fs from 'fs'
2
- import path from 'path'
3
- import { URL } from 'url'
4
- import WebSocket from 'ws'
5
- import { render } from './index.js'
6
- import { HttpRenderer } from './http.js'
7
- import { config } from '../utils/index.js'
8
- let ws
9
- let reConnect
10
- const chunkSize = 1024 * 1024 * 3 // 文件分片大小
11
- export function Wormhole () {
12
- let heartbeat
13
- let index = 0
14
- reConnect = undefined
15
- const wsUrl = config.Server.HttpRender.WormholeClient
16
- ws = new WebSocket(wsUrl)
17
- ws.on('open', function open () {
18
- logger.info('连接到wormhole服务器' + wsUrl)
19
- // 发送心跳
20
- heartbeat = setInterval(() => {
21
- ws.send(JSON.stringify({ type: 'heartbeat', date: new Date() }))
22
- }, 30000) // 每30秒发送一次心跳
23
- })
24
- ws.on('message', msg => {
25
- let data = ''
26
- try {
27
- data = JSON.parse(msg.toString())
28
- } catch (error) {
29
- logger.warn(`收到非法消息${data}`)
30
- }
31
- const echo = data.echo
32
- switch (data.type) {
33
- case 'msg': {
34
- const { post, token, WormholeClient } = config.Server.HttpRender
35
- const parsedUrl = new URL(WormholeClient)
36
- const { hostname, port, pathname } = parsedUrl
37
- const ishttps = WormholeClient.includes('wss://')
38
- const host = `${ishttps ? 'https' : 'http'}://${hostname}${port ? `:${port}` : ''}${pathname.replace(/ws\/(?=[^ws/]*$)/, 'web/')}${data.date}`
39
- logger.mark(`web渲染器已连接,地址:${host}`)
40
- /** 注册渲染器 */
41
- const rd = new HttpRenderer(host, post, token)
42
- index = render.app({ id: 'puppeteer', type: 'image', render: rd.render.bind(rd) })
43
- break
44
- }
45
- case 'web':
46
- if (data.path) {
47
- const filePath = data.path
48
- const query = data.query
49
- if (query.html) {
50
- ws.send(JSON.stringify({ type: 'web', command: 'redirect', path: filePath, target: query.html.startsWith('/') ? query.html.slice(1) : query.html, echo }))
51
- return
52
- }
53
- const list = ['.css', '.html', '.ttf', '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.ico', '.woff', '.woff2']
54
- if (!list.some(ext => path.extname(filePath).endsWith(ext))) {
55
- logger.warn(`拦截非资源文件${filePath}`)
56
- ws.send(JSON.stringify({ type: 'web', state: 'error', error: '非资源文件', echo }))
57
- return
58
- }
59
- /** 判断一下是否为html 如果是需要特殊处理 */
60
- if (path.extname(filePath) === '.html') {
61
- let html = filePath
62
- /** 获取文件路径 对路径进行处理,去掉../、./ */
63
- html = `./${html.replace(/\\/g, '/').replace(/(\.\/|\.\.\/)/g, '')}`
64
- /** 判断是否为html文件且路径存在 */
65
- if (!fs.existsSync(html)) {
66
- return ws.send(JSON.stringify({ type: 'web', state: 'error', error: '文件不存在', echo }))
67
- }
68
- let content = fs.readFileSync(html, 'utf-8')
69
- /** 处理所有绝对路径、相对路径 */
70
- content = content.replace(new RegExp(`(${process.cwd()}|${process.cwd().replace(/\\/g, '/')})`, 'g'), '')
71
- // 保存到本地
72
- // filePath = './1.html'
73
- // fs.writeFileSync(filePath, content, 'utf-8')
74
- return ws.send(JSON.stringify({
75
- type: 'web',
76
- path: data.path,
77
- command: 'resource',
78
- data: Buffer.from(content),
79
- state: 'complete',
80
- part: 0,
81
- echo,
82
- }))
83
- }
84
- logger.info(`获取网页文件数据:${filePath}`)
85
- // 获取文件
86
- const stream = fs.createReadStream(filePath, { highWaterMark: chunkSize })
87
- let part = 0
88
- stream.on('data', chunk => {
89
- part++
90
- const message = {
91
- type: 'web',
92
- path: data.path,
93
- command: 'resource',
94
- data: chunk,
95
- state: 'part',
96
- part,
97
- echo,
98
- }
99
- ws.send(JSON.stringify(message))
100
- })
101
- stream.on('end', () => {
102
- part++
103
- // 如果是最后一片段,则更新状态为 'complete'
104
- if (stream.readableEnded) {
105
- ws.send(JSON.stringify({
106
- type: 'web',
107
- path: data.path,
108
- command: 'resource',
109
- data: '',
110
- state: 'complete',
111
- part,
112
- echo,
113
- }))
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { URL } from 'url';
4
+ import WebSocket from 'ws';
5
+ import { render } from './index.js';
6
+ import { HttpRenderer } from './http.js';
7
+ import { config } from '../utils/index.js';
8
+ let ws;
9
+ let reConnect;
10
+ const chunkSize = 1024 * 1024 * 3; // 文件分片大小
11
+ export function Wormhole() {
12
+ let heartbeat;
13
+ let index = 0;
14
+ reConnect = undefined;
15
+ const wsUrl = config.Server.HttpRender.WormholeClient;
16
+ ws = new WebSocket(wsUrl);
17
+ ws.on('open', function open() {
18
+ logger.info('连接到wormhole服务器' + wsUrl);
19
+ // 发送心跳
20
+ heartbeat = setInterval(() => {
21
+ ws.send(JSON.stringify({ type: 'heartbeat', date: new Date() }));
22
+ }, 30000); // 每30秒发送一次心跳
23
+ });
24
+ ws.on('message', msg => {
25
+ let data = '';
26
+ try {
27
+ data = JSON.parse(msg.toString());
28
+ }
29
+ catch (error) {
30
+ logger.warn(`收到非法消息${data}`);
31
+ }
32
+ const echo = data.echo;
33
+ switch (data.type) {
34
+ case 'msg': {
35
+ const { post, token, WormholeClient } = config.Server.HttpRender;
36
+ const parsedUrl = new URL(WormholeClient);
37
+ const { hostname, port, pathname } = parsedUrl;
38
+ const ishttps = WormholeClient.includes('wss://');
39
+ const host = `${ishttps ? 'https' : 'http'}://${hostname}${port ? `:${port}` : ''}${pathname.replace(/ws\/(?=[^ws/]*$)/, 'web/')}${data.date}`;
40
+ logger.mark(`web渲染器已连接,地址:${host}`);
41
+ /** 注册渲染器 */
42
+ const rd = new HttpRenderer(host, post, token);
43
+ index = render.app({ id: 'puppeteer', type: 'image', render: rd.render.bind(rd) });
44
+ break;
114
45
  }
115
- })
116
- stream.on('error', err => {
117
- ws.send(JSON.stringify({ type: 'web', state: 'error', error: err.message, echo }))
118
- })
119
- } else {
120
- ws.send(JSON.stringify({ type: 'web', state: 'error', error: '错误的文件路径', echo }))
46
+ case 'web':
47
+ if (data.path) {
48
+ const filePath = data.path;
49
+ const query = data.query;
50
+ if (query.html) {
51
+ ws.send(JSON.stringify({ type: 'web', command: 'redirect', path: filePath, target: query.html.startsWith('/') ? query.html.slice(1) : query.html, echo }));
52
+ return;
53
+ }
54
+ const list = ['.css', '.html', '.ttf', '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.ico', '.woff', '.woff2'];
55
+ if (!list.some(ext => path.extname(filePath).endsWith(ext))) {
56
+ logger.warn(`拦截非资源文件${filePath}`);
57
+ ws.send(JSON.stringify({ type: 'web', state: 'error', error: '非资源文件', echo }));
58
+ return;
59
+ }
60
+ /** 判断一下是否为html 如果是需要特殊处理 */
61
+ if (path.extname(filePath) === '.html') {
62
+ let html = filePath;
63
+ /** 获取文件路径 对路径进行处理,去掉../、./ */
64
+ html = `./${html.replace(/\\/g, '/').replace(/(\.\/|\.\.\/)/g, '')}`;
65
+ /** 判断是否为html文件且路径存在 */
66
+ if (!fs.existsSync(html)) {
67
+ return ws.send(JSON.stringify({ type: 'web', state: 'error', error: '文件不存在', echo }));
68
+ }
69
+ let content = fs.readFileSync(html, 'utf-8');
70
+ /** 处理所有绝对路径、相对路径 */
71
+ content = content.replace(new RegExp(`(${process.cwd()}|${process.cwd().replace(/\\/g, '/')})`, 'g'), '');
72
+ // 保存到本地
73
+ // filePath = './1.html'
74
+ // fs.writeFileSync(filePath, content, 'utf-8')
75
+ return ws.send(JSON.stringify({
76
+ type: 'web',
77
+ path: data.path,
78
+ command: 'resource',
79
+ data: Buffer.from(content),
80
+ state: 'complete',
81
+ part: 0,
82
+ echo,
83
+ }));
84
+ }
85
+ logger.info(`获取网页文件数据:${filePath}`);
86
+ // 获取文件
87
+ const stream = fs.createReadStream(filePath, { highWaterMark: chunkSize });
88
+ let part = 0;
89
+ stream.on('data', chunk => {
90
+ part++;
91
+ const message = {
92
+ type: 'web',
93
+ path: data.path,
94
+ command: 'resource',
95
+ data: chunk,
96
+ state: 'part',
97
+ part,
98
+ echo,
99
+ };
100
+ ws.send(JSON.stringify(message));
101
+ });
102
+ stream.on('end', () => {
103
+ part++;
104
+ // 如果是最后一片段,则更新状态为 'complete'
105
+ if (stream.readableEnded) {
106
+ ws.send(JSON.stringify({
107
+ type: 'web',
108
+ path: data.path,
109
+ command: 'resource',
110
+ data: '',
111
+ state: 'complete',
112
+ part,
113
+ echo,
114
+ }));
115
+ }
116
+ });
117
+ stream.on('error', err => {
118
+ ws.send(JSON.stringify({ type: 'web', state: 'error', error: err.message, echo }));
119
+ });
120
+ }
121
+ else {
122
+ ws.send(JSON.stringify({ type: 'web', state: 'error', error: '错误的文件路径', echo }));
123
+ }
124
+ break;
125
+ default:
126
+ logger.warn(`未知消息类型${JSON.stringify(data)}`);
127
+ break;
128
+ }
129
+ });
130
+ ws.on('close', function close() {
131
+ /** 卸载渲染器 */
132
+ index && render.unapp(index);
133
+ index = 0;
134
+ if (heartbeat) {
135
+ clearInterval(heartbeat);
136
+ heartbeat = null;
137
+ }
138
+ logger.warn('连接关闭,10秒后尝试重新连接');
139
+ if (!reConnect) {
140
+ reConnect = setTimeout(Wormhole, 10000);
141
+ }
142
+ });
143
+ ws.on('error', function error() {
144
+ /** 卸载渲染器 */
145
+ index && render.unapp(index);
146
+ index = 0;
147
+ if (heartbeat) {
148
+ clearInterval(heartbeat);
149
+ heartbeat = null;
150
+ }
151
+ logger.warn('连接错误,10秒后尝试重新连接');
152
+ if (!reConnect) {
153
+ reConnect = setTimeout(Wormhole, 10000);
121
154
  }
122
- break
123
- default:
124
- logger.warn(`未知消息类型${JSON.stringify(data)}`)
125
- break
126
- }
127
- })
128
- ws.on('close', function close () {
129
- /** 卸载渲染器 */
130
- index && render.unapp(index)
131
- index = 0
132
- if (heartbeat) {
133
- clearInterval(heartbeat)
134
- heartbeat = null
135
- }
136
- logger.warn('连接关闭,10秒后尝试重新连接')
137
- if (!reConnect) {
138
- reConnect = setTimeout(Wormhole, 10000)
139
- }
140
- })
141
- ws.on('error', function error () {
142
- /** 卸载渲染器 */
143
- index && render.unapp(index)
144
- index = 0
145
- if (heartbeat) {
146
- clearInterval(heartbeat)
147
- heartbeat = null
148
- }
149
- logger.warn('连接错误,10秒后尝试重新连接')
150
- if (!reConnect) {
151
- reConnect = setTimeout(Wormhole, 10000)
152
- }
153
- })
155
+ });
154
156
  }
@@ -121,9 +121,9 @@ export interface Config {
121
121
  */
122
122
  log_color: string;
123
123
  /**
124
- * 关闭后台进程失败后是否继续启动 继续启动会导致多进程
124
+ * 重启是否调用pm2 如果不调用则会直接关机 此配置适合有进程守护的程序
125
125
  */
126
- multi_progress: boolean;
126
+ pm2Restart: boolean;
127
127
  /**
128
128
  * ffmpeg配置
129
129
  */
@@ -1,13 +1,13 @@
1
- export * from './adapter/base.js'
2
- export * from './config/config.js'
3
- export * from './element/element.js'
4
- export * from './element/qqbot.js'
5
- export * from './event/index.js'
6
- export * from './logger/logger.js'
7
- export * from './render/render.js'
8
- export * from './plugin/app.js'
9
- export * from './plugin/plugin.js'
10
- export * from './event/reply.js'
11
- export * from './adapter/api.js'
12
- export * from './onebot11/index.js'
13
- export * from './event/index.js'
1
+ export * from './adapter/base.js';
2
+ export * from './config/config.js';
3
+ export * from './element/element.js';
4
+ export * from './element/qqbot.js';
5
+ export * from './event/index.js';
6
+ export * from './logger/logger.js';
7
+ export * from './render/render.js';
8
+ export * from './plugin/app.js';
9
+ export * from './plugin/plugin.js';
10
+ export * from './event/reply.js';
11
+ export * from './adapter/api.js';
12
+ export * from './onebot11/index.js';
13
+ export * from './event/index.js';
@@ -14,6 +14,8 @@ declare global {
14
14
  karin_app_lang: `${Lang}`;
15
15
  /** 运行器 "node" | "tsx" | "pm2" */
16
16
  karin_app_runner: `${Runner}`;
17
+ /** 版本 */
18
+ karin_app_version: string;
17
19
  }
18
20
  }
19
21
  }
@@ -9,3 +9,5 @@ export * from './tools/update.js';
9
9
  export * from './config/yamlEditor.js';
10
10
  export * from './core/logger.js';
11
11
  export * from './config/updateVersion.js';
12
+ export * from './tools/restart.js';
13
+ export * from './tools/stop.js';
@@ -1,11 +1,13 @@
1
- export * from './tools/button.js'
2
- export * from './common/common.js'
3
- export * from './config/config.js'
4
- export * from './tools/ffmpeg.js'
5
- export * from './core/handler.js'
6
- export * from './tools/exec.js'
7
- export * from './core/segment.js'
8
- export * from './tools/update.js'
9
- export * from './config/yamlEditor.js'
10
- export * from './core/logger.js'
11
- export * from './config/updateVersion.js'
1
+ export * from './tools/button.js';
2
+ export * from './common/common.js';
3
+ export * from './config/config.js';
4
+ export * from './tools/ffmpeg.js';
5
+ export * from './core/handler.js';
6
+ export * from './tools/exec.js';
7
+ export * from './core/segment.js';
8
+ export * from './tools/update.js';
9
+ export * from './config/yamlEditor.js';
10
+ export * from './core/logger.js';
11
+ export * from './config/updateVersion.js';
12
+ export * from './tools/restart.js';
13
+ export * from './tools/stop.js';
@@ -1,32 +1,20 @@
1
+ import { ExecOptions } from 'child_process';
1
2
  /**
2
3
  * 执行 shell 命令
3
4
  * @param cmd 命令
4
5
  * @param log 是否打印日志
5
6
  * @param options 选项
6
7
  */
7
- export declare const exec: (cmd: string, log?: boolean, options?: {
8
- cwd: string;
9
- encoding: string;
10
- }) => Promise<{
11
- /**
12
- * - 执行状态
13
- */
8
+ export declare const exec: (cmd: string, log?: boolean, options?: ExecOptions) => Promise<{
14
9
  status: "ok" | "failed";
15
- /**
16
- * - 错误信息
17
- */
18
10
  error: Error | null;
19
- stdout: string | "";
20
- stderr: string | "";
11
+ stdout: string;
12
+ stderr: string;
21
13
  }>;
22
14
  /**
23
15
  * 执行 shell 命令
24
16
  * @param cmd 命令
25
- * @param log 是否打印日志
26
17
  * @param options 选项
27
18
  */
28
- export declare const execs: (cmd: string, options?: {
29
- cwd: string;
30
- encoding: string;
31
- }) => Promise<string>;
19
+ export declare const execs: (cmd: string, options?: ExecOptions) => Promise<string>;
32
20
  export default exec;
@@ -6,41 +6,43 @@ import { exec as execCmd } from 'child_process';
6
6
  * @param log 是否打印日志
7
7
  * @param options 选项
8
8
  */
9
- export const exec = (cmd, log = true, options = { cwd: process.cwd(), encoding: 'utf-8' }) => {
9
+ export const exec = async (cmd, log = true, options = { cwd: process.cwd() }) => {
10
+ const logType = (status) => ({
11
+ start: '[exec][开始执行]',
12
+ ok: '[exec][执行成功]',
13
+ failed: '[exec][执行失败]',
14
+ })[status];
15
+ const logMessage = (status, details = '') => {
16
+ if (log) {
17
+ const colorFunc = {
18
+ start: logger.yellow,
19
+ ok: logger.green,
20
+ failed: logger.red,
21
+ }[status];
22
+ logger.info([
23
+ colorFunc(logType(status)),
24
+ `cmd: ${cmd}`,
25
+ `cwd: ${options.cwd}`,
26
+ details,
27
+ '--------',
28
+ ].join('\n'));
29
+ }
30
+ };
31
+ logMessage('start');
10
32
  return new Promise(resolve => {
11
- const logMessage = (level, message) => {
12
- if (log)
13
- logger[level](message);
14
- };
15
- const logType = (status) => {
16
- switch (status) {
17
- case '开始执行':
18
- return logger.yellow('[exec][开始执行]');
19
- case 'ok':
20
- return logger.green('[exec][执行成功]');
21
- case 'failed':
22
- return logger.red('[exec][执行失败]');
23
- }
24
- };
25
- const formatMessage = (status, details) => [logType(status), `cmd: ${cmd}`, `cwd: ${options.cwd || process.cwd()}`, details, '--------'].join('\n');
26
- logMessage('info', formatMessage('开始执行', ''));
27
- execCmd(cmd, options, (error, stdout, stderr) => {
28
- if (error) {
29
- logMessage('error', formatMessage('failed', `Error: ${error.message || error.stack || error.toString()}`));
30
- return resolve({ status: 'failed', error, stdout, stderr });
31
- }
32
- logMessage('mark', formatMessage('ok', `stdout: ${stdout}\nstderr: ${stderr}`));
33
- resolve({ status: 'ok', error, stdout, stderr });
33
+ execCmd(cmd, options, (error, stdout = '', stderr = '') => {
34
+ const status = error ? 'failed' : 'ok';
35
+ logMessage(status, error ? `Error: ${error.message}` : `stdout: ${stdout}\nstderr: ${stderr}`);
36
+ resolve({ status, error, stdout, stderr });
34
37
  });
35
38
  });
36
39
  };
37
40
  /**
38
41
  * 执行 shell 命令
39
42
  * @param cmd 命令
40
- * @param log 是否打印日志
41
43
  * @param options 选项
42
44
  */
43
- export const execs = (cmd, options = { cwd: process.cwd(), encoding: 'utf-8' }) => {
45
+ export const execs = (cmd, options = { cwd: process.cwd() }) => {
44
46
  return new Promise((resolve, reject) => {
45
47
  execCmd(cmd, options, (error, stdout) => {
46
48
  if (error)
@@ -7,6 +7,6 @@ export declare function ffmpeg(): Promise<false | ((cmd: string, log?: boolean,
7
7
  }) => Promise<{
8
8
  status: "ok" | "failed";
9
9
  error: Error | null;
10
- stdout: string | "";
11
- stderr: string | "";
10
+ stdout: string;
11
+ stderr: string;
12
12
  }>)>;
@@ -0,0 +1,15 @@
1
+ import { Contact } from '../../types/index.js';
2
+ /**
3
+ * 重启Bot
4
+ * @param self_id - 机器人的id 传e.self_id
5
+ * @param contact - 事件联系人信息 也就是从哪来的这条消息 传e.contact即可
6
+ * @param message_id - 消息id 传e.message_id
7
+ * @param isFront - 是否为前台重启 默认是
8
+ */
9
+ export declare const restart: (self_id: string, contact: Contact, message_id: string, isFront?: boolean) => Promise<{
10
+ status: string;
11
+ data: string;
12
+ } | {
13
+ status: string;
14
+ data: Error | null;
15
+ }>;
@@ -0,0 +1,39 @@
1
+ import exec from './exec.js';
2
+ import { level } from '../../db/index.js';
3
+ import { config } from '../config/config.js';
4
+ /**
5
+ * 重启Bot
6
+ * @param self_id - 机器人的id 传e.self_id
7
+ * @param contact - 事件联系人信息 也就是从哪来的这条消息 传e.contact即可
8
+ * @param message_id - 消息id 传e.message_id
9
+ * @param isFront - 是否为前台重启 默认是
10
+ */
11
+ export const restart = async (self_id, contact, message_id, isFront = true) => {
12
+ const options = {
13
+ id: self_id,
14
+ contact,
15
+ message_id,
16
+ time: Date.now(),
17
+ };
18
+ const key = `karin:restart:${options.id}`;
19
+ await level.set(key, options);
20
+ if (isFront) {
21
+ if (!process.send)
22
+ return { status: 'failed', data: '前台重启失败,当前环境不支持,仅支持【npx karin start】启动的环境' };
23
+ process.send({ action: 'result', env: process.env });
24
+ process.exit();
25
+ }
26
+ if (!config.Config.pm2Restart)
27
+ process.exit();
28
+ if (process.env.pm_id) {
29
+ const pm2 = await exec('npx karin rs');
30
+ if (pm2.status === 'ok')
31
+ process.exit();
32
+ return { status: 'failed', data: pm2.error };
33
+ }
34
+ /** 调用pm2启动 */
35
+ const pm2 = await exec('npx karin pm2');
36
+ if (pm2.status === 'ok')
37
+ process.exit();
38
+ return { status: 'failed', data: pm2.error };
39
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * 停止Bot
3
+ */
4
+ export declare const stop: () => Promise<{
5
+ status: string;
6
+ data: Error | null;
7
+ }>;
@@ -0,0 +1,13 @@
1
+ import exec from './exec.js';
2
+ /**
3
+ * 停止Bot
4
+ */
5
+ export const stop = async () => {
6
+ if (process.env.pm_id) {
7
+ const pm2 = await exec('pm2 delete ' + process.env.pm_id);
8
+ if (pm2.status === 'ok')
9
+ process.exit();
10
+ return { status: 'failed', data: pm2.error };
11
+ }
12
+ process.exit();
13
+ };