chattransfer 0.0.0-stage → 2.0.11
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/LICENSE +21 -0
- package/README.ar.md +208 -0
- package/README.md +207 -2
- package/README.zh-CN.md +208 -0
- package/bin/chattransfer.js +41 -0
- package/frontend/README.md +5 -0
- package/frontend/dist/assets/browser-CjtO9Bzi.js +8 -0
- package/frontend/dist/assets/index-CiTzjW7h.js +976 -0
- package/frontend/dist/assets/index-Dw5X-Gok.css +1 -0
- package/frontend/dist/assets/logo-DQUxWwh1.png +0 -0
- package/frontend/dist/index.html +14 -0
- package/frontend/dist/pin.svg +1 -0
- package/frontend/dist/vite.svg +1 -0
- package/package.json +62 -4
- package/server/cli-options.js +69 -0
- package/server/config/loader.js +36 -0
- package/server/config.js +63 -0
- package/server/index.js +132 -0
- package/server/room-manager.js +75 -0
- package/server/routes/checkLogin.js +24 -0
- package/server/routes/files.js +49 -0
- package/server/routes/geneBUserQR.js +37 -0
- package/server/routes/geneQR.js +39 -0
- package/server/routes/getHomeDir.js +27 -0
- package/server/routes/getIndexInfo.js +42 -0
- package/server/routes/getIndexInfo2.js +42 -0
- package/server/routes/index.js +36 -0
- package/server/routes/openCachePath.js +63 -0
- package/server/routes/qr.js +63 -0
- package/server/routes/scanLogin.js +33 -0
- package/server/routes/session.js +15 -0
- package/server/routes/setCachePath.js +94 -0
- package/server/routes/system.js +107 -0
- package/server/services/message-history-service.js +476 -0
- package/server/services/message-service.js +31 -0
- package/server/socket/index.js +232 -0
- package/server/socket/session-manager.js +3 -0
- package/server/telemetry/amplitude-provider.js +17 -0
- package/server/telemetry/compat.js +17 -0
- package/server/telemetry/index.js +26 -0
- package/server/telemetry/noop-provider.js +7 -0
- package/server/tool.js +71 -0
- package/server/utils/app-root.js +11 -0
- package/server/utils/network.js +21 -0
- package/server/utils/request-url.js +15 -0
- package/server/utils/runtime-options.js +90 -0
- package/server/utils/runtime-paths.js +87 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const { geneQR } = require("../tool");
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 获取首页信息
|
|
6
|
+
* @param {*} app
|
|
7
|
+
* @param {*} AEnterUrl
|
|
8
|
+
* @param {*} BEnterUrl
|
|
9
|
+
*/
|
|
10
|
+
module.exports = (app, AEnterUrl,BEnterUrl) => {
|
|
11
|
+
|
|
12
|
+
app.get('/getIndexInfo', async (req, res) => {
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
|
|
16
|
+
const qrABase64Str = geneQR(AEnterUrl);
|
|
17
|
+
const qrBBase64Str = geneQR(BEnterUrl);
|
|
18
|
+
const response = {
|
|
19
|
+
code: 0,
|
|
20
|
+
message: '获取成功',
|
|
21
|
+
data: {
|
|
22
|
+
"title": "",
|
|
23
|
+
"lists": [
|
|
24
|
+
{
|
|
25
|
+
"qrurl":qrABase64Str,
|
|
26
|
+
"jupmUrl":AEnterUrl
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"qrurl": qrBBase64Str,
|
|
30
|
+
"jupmUrl":BEnterUrl
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
res.send(response);
|
|
36
|
+
|
|
37
|
+
} catch (err) {
|
|
38
|
+
console.log(err);
|
|
39
|
+
res.status(500).send(err);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const { geneQR } = require("../tool");
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 获取首页信息
|
|
6
|
+
* @param {*} app
|
|
7
|
+
* @param {*} AEnterUrl
|
|
8
|
+
* @param {*} BEnterUrl
|
|
9
|
+
*/
|
|
10
|
+
module.exports = (app,homeUrl, AEnterUrl,BEnterUrl) => {
|
|
11
|
+
|
|
12
|
+
app.get('/getIndexInfo2', async (req, res) => {
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
// http://192.168.1.4:50001/login?receiver=A
|
|
16
|
+
|
|
17
|
+
const receiver = req.query.receiver;
|
|
18
|
+
// 指向 Vue 路由 /login,而不是旧的 html 文件
|
|
19
|
+
let loginUrl = `${homeUrl}/login?receiver=${receiver}`;
|
|
20
|
+
const qrABase64Str = geneQR(loginUrl);
|
|
21
|
+
|
|
22
|
+
const response = {
|
|
23
|
+
code: 0,
|
|
24
|
+
message: '获取成功',
|
|
25
|
+
data: {
|
|
26
|
+
"title": "",
|
|
27
|
+
"lists": [
|
|
28
|
+
{
|
|
29
|
+
"qrurl":qrABase64Str,
|
|
30
|
+
"jupmUrl":loginUrl
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
res.send(response);
|
|
36
|
+
|
|
37
|
+
} catch (err) {
|
|
38
|
+
console.log(err);
|
|
39
|
+
res.status(500).send(err);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { trackEvent } = require('../telemetry/compat');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const fileUpload = require('express-fileupload');
|
|
6
|
+
const { getCachePath } = require('../config');
|
|
7
|
+
|
|
8
|
+
module.exports = function registerRoutes(app) {
|
|
9
|
+
const uploadsDir = getCachePath();
|
|
10
|
+
const tempDir = path.join(uploadsDir, 'tmp');
|
|
11
|
+
|
|
12
|
+
if (!fs.existsSync(tempDir)) {
|
|
13
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
app.use(fileUpload({
|
|
17
|
+
createParentPath: true,
|
|
18
|
+
useTempFiles: true,
|
|
19
|
+
tempFileDir: tempDir,
|
|
20
|
+
defParamCharset: 'utf8'
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
app.use(express.json());
|
|
24
|
+
|
|
25
|
+
app.use(require('./system'));
|
|
26
|
+
app.use(require('./session'));
|
|
27
|
+
app.use(require('./qr'));
|
|
28
|
+
app.use(require('./files'));
|
|
29
|
+
|
|
30
|
+
app.use(express.static(path.join(__dirname, '../../frontend/dist')));
|
|
31
|
+
app.use(express.static(uploadsDir));
|
|
32
|
+
|
|
33
|
+
app.get('*', (req, res) => {
|
|
34
|
+
res.sendFile(path.join(__dirname, '../../frontend/dist/index.html'));
|
|
35
|
+
});
|
|
36
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 打开用户缓存目录
|
|
3
|
+
* @param {*} app
|
|
4
|
+
* @param {*} homeDir
|
|
5
|
+
*/
|
|
6
|
+
module.exports = (app, uploadsDir) => {
|
|
7
|
+
app.post('/openCachePath', async (req, res) => {
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
let response = {
|
|
12
|
+
code: 0 ,
|
|
13
|
+
message: '打开成功!',
|
|
14
|
+
data: {
|
|
15
|
+
'platform':process.platform,
|
|
16
|
+
'path':uploadsDir
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
var exec = require('child_process').exec;
|
|
20
|
+
if(process.platform === 'darwin'){
|
|
21
|
+
exec('open ' + uploadsDir, (error, stdout, stderr) => {
|
|
22
|
+
|
|
23
|
+
if (error) {
|
|
24
|
+
console.error(`exec error: ${error}`);
|
|
25
|
+
response.code = -1;
|
|
26
|
+
response.message = '打开失败!' + error.message;
|
|
27
|
+
|
|
28
|
+
}else {
|
|
29
|
+
console.log(`stdout: ${stdout}`);
|
|
30
|
+
console.error(`stderr: ${stderr}`);
|
|
31
|
+
response.code = 0;
|
|
32
|
+
response.message = '打开成功!';
|
|
33
|
+
}
|
|
34
|
+
console.log('response:', response);
|
|
35
|
+
res.send(response);
|
|
36
|
+
});
|
|
37
|
+
} else if (process.platform === 'win32') {
|
|
38
|
+
exec(`explorer "${uploadsDir}"`, (error, stdout, stderr) => {
|
|
39
|
+
if (error) {
|
|
40
|
+
console.error(`exec error: ${error}`);
|
|
41
|
+
response.code = -1;
|
|
42
|
+
response.message = '打开失败!' + error.message;
|
|
43
|
+
} else {
|
|
44
|
+
response.code = 0;
|
|
45
|
+
response.message = '打开成功!';
|
|
46
|
+
}
|
|
47
|
+
res.send(response);
|
|
48
|
+
});
|
|
49
|
+
} else {
|
|
50
|
+
|
|
51
|
+
response.code = -1;
|
|
52
|
+
response.message = '暂不支持的平台';
|
|
53
|
+
console.log('response:', response);
|
|
54
|
+
res.send(response);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
} catch (err) {
|
|
59
|
+
console.log(err);
|
|
60
|
+
res.status(500).send(err);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const { geneQR } = require('../tool');
|
|
3
|
+
const { getRequestBaseUrl } = require('../utils/request-url');
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
|
|
6
|
+
router.get('/geneQR', (req, res) => {
|
|
7
|
+
const content = req.query.qrStr;
|
|
8
|
+
const qrImage = geneQR(content);
|
|
9
|
+
|
|
10
|
+
res.send({
|
|
11
|
+
code: qrImage ? 0 : -1,
|
|
12
|
+
message: qrImage ? 'ok' : 'failed',
|
|
13
|
+
data: qrImage ? { qr: qrImage, qrText: content } : {}
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
router.get('/geneBUserQR', (req, res) => {
|
|
18
|
+
res.send({ code: 0, message: 'ok' });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
router.get('/getIndexInfo', (req, res) => {
|
|
22
|
+
const homeUrl = getRequestBaseUrl(req);
|
|
23
|
+
const aUrl = `${homeUrl}/chat?sender=A&receiver=B`;
|
|
24
|
+
const bUrl = `${homeUrl}/chat?sender=B&receiver=A`;
|
|
25
|
+
|
|
26
|
+
res.send({
|
|
27
|
+
code: 0,
|
|
28
|
+
message: 'ok',
|
|
29
|
+
data: {
|
|
30
|
+
lists: [
|
|
31
|
+
{ qrurl: geneQR(aUrl), jupmUrl: aUrl },
|
|
32
|
+
{ qrurl: geneQR(bUrl), jupmUrl: bUrl }
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
router.get('/getIndexInfo2', (req, res) => {
|
|
39
|
+
const homeUrl = getRequestBaseUrl(req);
|
|
40
|
+
const loginUrl = `${homeUrl}/login?receiver=${req.query.receiver || 'group_chat'}`;
|
|
41
|
+
|
|
42
|
+
res.send({
|
|
43
|
+
code: 0,
|
|
44
|
+
message: 'ok',
|
|
45
|
+
data: {
|
|
46
|
+
lists: [{ qrurl: geneQR(loginUrl), jupmUrl: loginUrl }]
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
router.get('/scanLogin', (req, res) => {
|
|
52
|
+
const homeUrl = getRequestBaseUrl(req);
|
|
53
|
+
const receiver = req.query.receiver || 'group_chat';
|
|
54
|
+
const targetUrl = `${homeUrl}/chat?sender=${req.query.sender}&receiver=${receiver}`;
|
|
55
|
+
|
|
56
|
+
res.send({
|
|
57
|
+
code: 0,
|
|
58
|
+
message: 'ok',
|
|
59
|
+
data: { targetUrl }
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
module.exports = router;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const { geneQR } = require("../tool");
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 获取用户主目录
|
|
5
|
+
* @param {*} app
|
|
6
|
+
* @param {*} homeDir
|
|
7
|
+
*/
|
|
8
|
+
module.exports = (app,chatUrl,AEnterUrl,BEnterUrl) => {
|
|
9
|
+
app.get('/scanLogin', async (req, res) => {
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const fromUser = req.query.sender;
|
|
14
|
+
const receiver = req.query.receiver;
|
|
15
|
+
if (!receiver) {
|
|
16
|
+
receiver = 'A';
|
|
17
|
+
}
|
|
18
|
+
let targetUrl = `${chatUrl}?sender=${fromUser}&receiver=${receiver}`
|
|
19
|
+
console.log("targetUrl:",targetUrl);
|
|
20
|
+
let response = {
|
|
21
|
+
code: 0 ,
|
|
22
|
+
message: '扫码成功!',
|
|
23
|
+
data: {
|
|
24
|
+
targetUrl:targetUrl
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
res.send(response);
|
|
28
|
+
} catch (err) {
|
|
29
|
+
console.log(err);
|
|
30
|
+
res.status(500).send(err);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
const roomManager = require('../socket/session-manager');
|
|
4
|
+
|
|
5
|
+
router.get('/checkLogin', (req, res) => {
|
|
6
|
+
res.send({
|
|
7
|
+
code: 0,
|
|
8
|
+
message: 'ok',
|
|
9
|
+
data: {
|
|
10
|
+
users: roomManager.listUsers()
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
module.exports = router;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 设置自定义缓存目录
|
|
3
|
+
* 请求体: { path: string, migrate?: boolean }
|
|
4
|
+
* 生效方式: 修改后需重启进程(express.static / fileUpload 中间件运行时不可热切换)
|
|
5
|
+
* @param {*} app
|
|
6
|
+
* @param {*} uploadsDir 当前生效缓存目录
|
|
7
|
+
*/
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const express = require('express');
|
|
11
|
+
const { setCachePath } = require('../config.js');
|
|
12
|
+
const { getAppWritableRoot } = require('../tool.js');
|
|
13
|
+
|
|
14
|
+
module.exports = (app, uploadsDir) => {
|
|
15
|
+
app.post('/setCachePath', express.json(), async (req, res) => {
|
|
16
|
+
try {
|
|
17
|
+
const inputPath = req.body && req.body.path;
|
|
18
|
+
const migrate = req.body ? req.body.migrate !== false : true;
|
|
19
|
+
|
|
20
|
+
// 1. 参数校验
|
|
21
|
+
if (!inputPath || typeof inputPath !== 'string' || !inputPath.trim()) {
|
|
22
|
+
return res.send({ code: -1, message: '请输入缓存目录路径' });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 2. 必须绝对路径(先校验原始输入,再 resolve 规范化)
|
|
26
|
+
const trimmed = inputPath.trim();
|
|
27
|
+
if (!path.isAbsolute(trimmed)) {
|
|
28
|
+
return res.send({ code: -1, message: '请输入绝对路径' });
|
|
29
|
+
}
|
|
30
|
+
const newPath = path.resolve(trimmed);
|
|
31
|
+
|
|
32
|
+
// 3. 不能等于当前路径
|
|
33
|
+
if (newPath === path.resolve(uploadsDir)) {
|
|
34
|
+
return res.send({ code: -1, message: '新路径与当前路径相同' });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 4. 不能等于应用根目录(避免污染应用文件)
|
|
38
|
+
const appRoot = getAppWritableRoot();
|
|
39
|
+
if (newPath === path.resolve(appRoot)) {
|
|
40
|
+
return res.send({ code: -1, message: '不能使用应用根目录作为缓存目录' });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 5. 目录不存在则创建
|
|
44
|
+
try {
|
|
45
|
+
if (!fs.existsSync(newPath)) {
|
|
46
|
+
fs.mkdirSync(newPath, { recursive: true });
|
|
47
|
+
}
|
|
48
|
+
} catch (e) {
|
|
49
|
+
return res.send({ code: -1, message: '目录创建失败:' + e.message });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 6. 可写性测试:写临时文件再删
|
|
53
|
+
const testFile = path.join(newPath, '.chattransfer-write-test');
|
|
54
|
+
try {
|
|
55
|
+
fs.writeFileSync(testFile, 'ok', 'utf8');
|
|
56
|
+
fs.unlinkSync(testFile);
|
|
57
|
+
} catch (e) {
|
|
58
|
+
return res.send({ code: -1, message: '路径无效或不可写' });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 7. 迁移已有文件(递归复制旧目录内容到新目录)
|
|
62
|
+
if (migrate && fs.existsSync(uploadsDir)) {
|
|
63
|
+
try {
|
|
64
|
+
fs.cpSync(uploadsDir, newPath, { recursive: true });
|
|
65
|
+
// 清理测试遗留(若有)
|
|
66
|
+
if (fs.existsSync(testFile)) fs.unlinkSync(testFile);
|
|
67
|
+
} catch (e) {
|
|
68
|
+
// 迁移失败:清理已复制的内容,回滚,不更新配置
|
|
69
|
+
console.error('[setCachePath] migrate failed:', e.message);
|
|
70
|
+
return res.send({ code: -1, message: '迁移文件失败:' + e.message });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 8. 持久化到 config.json
|
|
75
|
+
try {
|
|
76
|
+
setCachePath(newPath);
|
|
77
|
+
} catch (e) {
|
|
78
|
+
return res.send({ code: -1, message: '配置保存失败:' + e.message });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
res.send({
|
|
82
|
+
code: 0,
|
|
83
|
+
message: '缓存目录设置成功,重启应用后生效',
|
|
84
|
+
data: {
|
|
85
|
+
newPath: newPath,
|
|
86
|
+
needsRestart: true
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
} catch (err) {
|
|
90
|
+
console.log(err);
|
|
91
|
+
res.status(500).send({ code: -1, message: err.message || '服务器内部错误' });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { execFile } = require('child_process');
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
const {
|
|
6
|
+
getCachePath,
|
|
7
|
+
getConfigFile,
|
|
8
|
+
getDefaultCachePath,
|
|
9
|
+
isCustomized,
|
|
10
|
+
setCachePath
|
|
11
|
+
} = require('../config');
|
|
12
|
+
const { getDefaultDataDir } = require('../utils/runtime-paths');
|
|
13
|
+
const { trackEvent } = require('../telemetry/compat');
|
|
14
|
+
|
|
15
|
+
router.get('/getHomeDir', (req, res) => {
|
|
16
|
+
const uploadsDir = getCachePath();
|
|
17
|
+
|
|
18
|
+
res.send({
|
|
19
|
+
code: 0,
|
|
20
|
+
message: 'ok',
|
|
21
|
+
data: {
|
|
22
|
+
uploadsDir,
|
|
23
|
+
defaultDir: getDefaultCachePath(),
|
|
24
|
+
isCustomized: isCustomized(),
|
|
25
|
+
configFile: getConfigFile()
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
router.get('/getVersionInfo', (req, res) => {
|
|
31
|
+
res.send({
|
|
32
|
+
code: 0,
|
|
33
|
+
message: 'ok',
|
|
34
|
+
data: {
|
|
35
|
+
version: require('../../package.json').version,
|
|
36
|
+
deviceId: 'anonymous'
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
router.post('/openCachePath', express.json(), (req, res) => {
|
|
42
|
+
const uploadsDir = getCachePath();
|
|
43
|
+
const respond = (code, message) => res.send({
|
|
44
|
+
code,
|
|
45
|
+
message,
|
|
46
|
+
data: { platform: process.platform, path: uploadsDir }
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
if (process.platform === 'linux' && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY) {
|
|
50
|
+
respond(0, '服务器无桌面环境,缓存目录已返回');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (process.platform === 'darwin') {
|
|
55
|
+
execFile('open', [uploadsDir], (error) => {
|
|
56
|
+
respond(error ? -1 : 0, error ? `打开失败:${error.message}` : '打开成功');
|
|
57
|
+
});
|
|
58
|
+
} else if (process.platform === 'win32') {
|
|
59
|
+
execFile('explorer', [uploadsDir], (error) => {
|
|
60
|
+
respond(error ? -1 : 0, error ? `打开失败:${error.message}` : '打开成功');
|
|
61
|
+
});
|
|
62
|
+
} else {
|
|
63
|
+
execFile('xdg-open', [uploadsDir], (error) => {
|
|
64
|
+
respond(error ? -1 : 0, error ? `打开失败:${error.message}` : '打开成功');
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
router.post('/setCachePath', (req, res) => {
|
|
70
|
+
const inputPath = req.body && req.body.path;
|
|
71
|
+
|
|
72
|
+
if (!inputPath || typeof inputPath !== 'string') {
|
|
73
|
+
return res.send({ code: -1, message: 'invalid path' });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const newPath = path.resolve(inputPath.trim());
|
|
77
|
+
const dataRoot = path.resolve(getDefaultDataDir());
|
|
78
|
+
|
|
79
|
+
if (!path.isAbsolute(newPath) || newPath === path.resolve(getCachePath()) || newPath === dataRoot) {
|
|
80
|
+
return res.send({ code: -1, message: 'invalid cache path' });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
require('fs').mkdirSync(newPath, { recursive: true });
|
|
85
|
+
setCachePath(newPath);
|
|
86
|
+
res.send({
|
|
87
|
+
code: 0,
|
|
88
|
+
message: 'ok',
|
|
89
|
+
data: { newPath, needsRestart: true }
|
|
90
|
+
});
|
|
91
|
+
} catch (error) {
|
|
92
|
+
res.send({ code: -1, message: error.message });
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
router.post('/api/track', (req, res) => {
|
|
97
|
+
const { eventType, eventProperties, userId } = req.body || {};
|
|
98
|
+
|
|
99
|
+
if (!eventType) {
|
|
100
|
+
return res.status(400).send({ code: -1, message: 'eventType is required' });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
trackEvent(eventType, eventProperties || {}, userId || null);
|
|
104
|
+
res.send({ code: 0, message: 'ok' });
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
module.exports = router;
|