@oxiaom/adoremix 1.0.37 → 1.0.39
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-manager/app.py +589 -0
- package/config-manager/templates/index.html +1396 -0
- package/package.json +3 -2
- package/src/cli.js +40 -0
- package/src/config-manager.js +139 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxiaom/adoremix",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.39",
|
|
4
4
|
"description": "AdoreMix broadcast server - cross-platform installer, runner and service manager",
|
|
5
5
|
"bin": {
|
|
6
6
|
"adoremix": "./bin/adoremix.js"
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
"src",
|
|
41
41
|
"templates",
|
|
42
42
|
"tts",
|
|
43
|
-
"webui"
|
|
43
|
+
"webui",
|
|
44
|
+
"config-manager"
|
|
44
45
|
],
|
|
45
46
|
"keywords": [
|
|
46
47
|
"adoremix",
|
package/src/cli.js
CHANGED
|
@@ -465,6 +465,46 @@ function buildProgram() {
|
|
|
465
465
|
try { process.exitCode = mod.status(); } catch (e) { logger.error(e.message); process.exitCode = 1; }
|
|
466
466
|
});
|
|
467
467
|
|
|
468
|
+
const cfgmgr = program
|
|
469
|
+
.command('config-manager')
|
|
470
|
+
.description('设备配置管理 UI(配置 IP / 修改 config.ini / 查看日志),端口 9877,开机自启');
|
|
471
|
+
|
|
472
|
+
cfgmgr
|
|
473
|
+
.command('install')
|
|
474
|
+
.description('安装设备配置管理 UI(端口 9877,开机自启)')
|
|
475
|
+
.option('--workdir <path>')
|
|
476
|
+
.action((opts) => {
|
|
477
|
+
const mod = require('./config-manager');
|
|
478
|
+
try {
|
|
479
|
+
process.exitCode = mod.install(resolveWorkdir(opts.workdir));
|
|
480
|
+
} catch (e) {
|
|
481
|
+
logger.error(e.message);
|
|
482
|
+
process.exitCode = 1;
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
cfgmgr
|
|
487
|
+
.command('uninstall')
|
|
488
|
+
.description('卸载设备配置管理 UI')
|
|
489
|
+
.option('--workdir <path>')
|
|
490
|
+
.action((opts) => {
|
|
491
|
+
const mod = require('./config-manager');
|
|
492
|
+
try {
|
|
493
|
+
process.exitCode = mod.uninstall(resolveWorkdir(opts.workdir));
|
|
494
|
+
} catch (e) {
|
|
495
|
+
logger.error(e.message);
|
|
496
|
+
process.exitCode = 1;
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
cfgmgr
|
|
501
|
+
.command('status')
|
|
502
|
+
.description('查看设备配置管理 UI 运行状态')
|
|
503
|
+
.action(() => {
|
|
504
|
+
const mod = require('./config-manager');
|
|
505
|
+
try { process.exitCode = mod.status(); } catch (e) { logger.error(e.message); process.exitCode = 1; }
|
|
506
|
+
});
|
|
507
|
+
|
|
468
508
|
program
|
|
469
509
|
.command('uninstall')
|
|
470
510
|
.description('完全卸载:停服务 + 卸载 systemd 服务;加 --purge 删除工作目录(含配置/数据库,不可恢复)')
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
const logger = require('./logger');
|
|
7
|
+
|
|
8
|
+
const SERVICE_NAME = 'config-manager';
|
|
9
|
+
const SYSTEM_UNIT_PATH = `/etc/systemd/system/${SERVICE_NAME}.service`;
|
|
10
|
+
const PORT = 9877;
|
|
11
|
+
|
|
12
|
+
function which(cmd) {
|
|
13
|
+
try { return execSync(`command -v ${cmd}`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim(); }
|
|
14
|
+
catch (e) { return null; }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function run(cmd) {
|
|
18
|
+
try { return execSync(cmd, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim(); }
|
|
19
|
+
catch (e) { return null; }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// 复制主包内置的 config-manager 代码(app.py + templates)到工作目录
|
|
23
|
+
function copyCode(workdir) {
|
|
24
|
+
const srcDir = path.join(__dirname, '..', 'config-manager');
|
|
25
|
+
const dstDir = path.join(workdir, 'config-manager');
|
|
26
|
+
fs.mkdirSync(dstDir, { recursive: true });
|
|
27
|
+
fs.copyFileSync(path.join(srcDir, 'app.py'), path.join(dstDir, 'app.py'));
|
|
28
|
+
fs.mkdirSync(path.join(dstDir, 'templates'), { recursive: true });
|
|
29
|
+
fs.copyFileSync(path.join(srcDir, 'templates', 'index.html'), path.join(dstDir, 'templates', 'index.html'));
|
|
30
|
+
return dstDir;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function buildUnit(workdir, pythonBin) {
|
|
34
|
+
const codeDir = path.join(workdir, 'config-manager');
|
|
35
|
+
return `# AdoreMix 设备配置管理 UI(由 adoremix config-manager install 生成)
|
|
36
|
+
[Unit]
|
|
37
|
+
Description=AdoreMix Config Manager (设备配置管理 UI)
|
|
38
|
+
After=network.target
|
|
39
|
+
|
|
40
|
+
[Service]
|
|
41
|
+
Type=simple
|
|
42
|
+
WorkingDirectory=${codeDir}
|
|
43
|
+
Environment=ADOREMIX_WORKDIR=${workdir}
|
|
44
|
+
ExecStart=${pythonBin} app.py
|
|
45
|
+
Restart=on-failure
|
|
46
|
+
RestartSec=5
|
|
47
|
+
|
|
48
|
+
[Install]
|
|
49
|
+
WantedBy=multi-user.target
|
|
50
|
+
`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function install(workdir) {
|
|
54
|
+
if (process.platform !== 'linux') {
|
|
55
|
+
logger.error('config-manager 仅支持 Linux(依赖 systemd)');
|
|
56
|
+
return 1;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 1. 检测 Python3
|
|
60
|
+
const pythonBin = which('python3');
|
|
61
|
+
if (!pythonBin) {
|
|
62
|
+
logger.error('未检测到 python3,请先安装:sudo dnf/apt install python3');
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
logger.ok(`python3: ${pythonBin}`);
|
|
66
|
+
|
|
67
|
+
// 2. 检测/安装 Flask
|
|
68
|
+
if (!run(`${pythonBin} -c "import flask"`)) {
|
|
69
|
+
logger.info('未检测到 Flask,尝试安装...');
|
|
70
|
+
try {
|
|
71
|
+
execSync(`${pythonBin} -m pip install flask`, { stdio: 'inherit' });
|
|
72
|
+
logger.ok('Flask 已安装');
|
|
73
|
+
} catch (e) {
|
|
74
|
+
logger.error(`Flask 安装失败:${(e.message || '').split('\n')[0]}`);
|
|
75
|
+
logger.warn(` 请手动安装:${pythonBin} -m pip install flask`);
|
|
76
|
+
return 1;
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
logger.ok('Flask 已就绪');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 3. 复制代码
|
|
83
|
+
try {
|
|
84
|
+
copyCode(workdir);
|
|
85
|
+
logger.ok(`复制 config-manager 代码到 ${path.join(workdir, 'config-manager')}`);
|
|
86
|
+
} catch (e) {
|
|
87
|
+
logger.error(`复制代码失败:${(e.message || '').split('\n')[0]}`);
|
|
88
|
+
return 1;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 4. 写 systemd 服务(开机自启)
|
|
92
|
+
try {
|
|
93
|
+
fs.writeFileSync(SYSTEM_UNIT_PATH, buildUnit(workdir, pythonBin), 'utf8');
|
|
94
|
+
logger.ok(`写入 ${SYSTEM_UNIT_PATH}`);
|
|
95
|
+
} catch (e) {
|
|
96
|
+
logger.error(`写服务失败:${(e.message || '').split('\n')[0]}(可能需要 root)`);
|
|
97
|
+
return 1;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 5. 启动 + 开机自启
|
|
101
|
+
try {
|
|
102
|
+
execSync('systemctl daemon-reload', { stdio: 'inherit' });
|
|
103
|
+
execSync(`systemctl enable ${SERVICE_NAME}`, { stdio: 'inherit' });
|
|
104
|
+
execSync(`systemctl restart ${SERVICE_NAME}`, { stdio: 'inherit' });
|
|
105
|
+
logger.ok('config-manager 已启动并设为开机自启');
|
|
106
|
+
} catch (e) {
|
|
107
|
+
logger.warn(`systemctl 操作失败:${(e.message || '').split('\n')[0]}(可能非 systemd,请手动启动)`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
logger.log('');
|
|
111
|
+
logger.log(`访问 UI:http://<本机IP>:${PORT}/`);
|
|
112
|
+
logger.log(`功能:配置 IP 地址 / 修改 config.ini / 查看运行日志`);
|
|
113
|
+
return 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function uninstall(workdir) {
|
|
117
|
+
if (process.platform !== 'linux') return 0;
|
|
118
|
+
try { execSync(`systemctl disable ${SERVICE_NAME}`, { stdio: 'ignore' }); } catch (e) {}
|
|
119
|
+
try { execSync(`systemctl stop ${SERVICE_NAME}`, { stdio: 'ignore' }); } catch (e) {}
|
|
120
|
+
try { fs.unlinkSync(SYSTEM_UNIT_PATH); logger.ok('已删除 systemd 服务'); } catch (e) {}
|
|
121
|
+
try { execSync('systemctl daemon-reload', { stdio: 'ignore' }); } catch (e) {}
|
|
122
|
+
const codeDir = path.join(workdir, 'config-manager');
|
|
123
|
+
if (fs.existsSync(codeDir)) {
|
|
124
|
+
fs.rmSync(codeDir, { recursive: true, force: true });
|
|
125
|
+
logger.ok(`已删除 ${codeDir}`);
|
|
126
|
+
}
|
|
127
|
+
logger.ok('config-manager 已卸载');
|
|
128
|
+
return 0;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function status() {
|
|
132
|
+
if (process.platform !== 'linux') { logger.warn('仅 Linux 支持'); return 1; }
|
|
133
|
+
const out = run(`systemctl is-active ${SERVICE_NAME}`);
|
|
134
|
+
if (out === 'active') { logger.ok('config-manager 运行中'); return 0; }
|
|
135
|
+
logger.warn(`config-manager 状态:${out || '未运行'}`);
|
|
136
|
+
return 1;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
module.exports = { install, uninstall, status, PORT };
|