@lzm04521/ssh-mcp-server 1.1.5
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 +15 -0
- package/README.md +157 -0
- package/admin-web/dist/assets/index-DXbr5DVR.js +494 -0
- package/admin-web/dist/index.html +6 -0
- package/admin-web/dist/logo.png +0 -0
- package/build/cli/command-line-parser.js +715 -0
- package/build/cli/command-line-parser.js.map +1 -0
- package/build/cli/run-mode.js +44 -0
- package/build/cli/run-mode.js.map +1 -0
- package/build/cli/stdio-proxy.js +304 -0
- package/build/cli/stdio-proxy.js.map +1 -0
- package/build/config/index.js +5 -0
- package/build/config/index.js.map +1 -0
- package/build/config/server.js +16 -0
- package/build/config/server.js.map +1 -0
- package/build/core/mcp-http-server.js +14 -0
- package/build/core/mcp-http-server.js.map +1 -0
- package/build/core/mcp-server.js +95 -0
- package/build/core/mcp-server.js.map +1 -0
- package/build/index.js +98 -0
- package/build/index.js.map +1 -0
- package/build/models/admin-types.js +135 -0
- package/build/models/admin-types.js.map +1 -0
- package/build/models/types.js +2 -0
- package/build/models/types.js.map +1 -0
- package/build/server/index.js +128 -0
- package/build/server/index.js.map +1 -0
- package/build/server/routes/admin.js +929 -0
- package/build/server/routes/admin.js.map +1 -0
- package/build/server/routes/audit.js +9 -0
- package/build/server/routes/audit.js.map +1 -0
- package/build/server/routes/backups.js +11 -0
- package/build/server/routes/backups.js.map +1 -0
- package/build/server/routes/mcp.js +52 -0
- package/build/server/routes/mcp.js.map +1 -0
- package/build/server/routes/settings.js +49 -0
- package/build/server/routes/settings.js.map +1 -0
- package/build/server/routes/system.js +147 -0
- package/build/server/routes/system.js.map +1 -0
- package/build/services/audit-store.js +123 -0
- package/build/services/audit-store.js.map +1 -0
- package/build/services/autostart-service.js +55 -0
- package/build/services/autostart-service.js.map +1 -0
- package/build/services/backup-scheduler.js +90 -0
- package/build/services/backup-scheduler.js.map +1 -0
- package/build/services/backup-service.js +113 -0
- package/build/services/backup-service.js.map +1 -0
- package/build/services/config-store.js +163 -0
- package/build/services/config-store.js.map +1 -0
- package/build/services/defaults.js +35 -0
- package/build/services/defaults.js.map +1 -0
- package/build/services/restart-helper.js +43 -0
- package/build/services/restart-helper.js.map +1 -0
- package/build/services/ssh-connection-manager.js +1775 -0
- package/build/services/ssh-connection-manager.js.map +1 -0
- package/build/services/update-service.js +93 -0
- package/build/services/update-service.js.map +1 -0
- package/build/tools/download.js +41 -0
- package/build/tools/download.js.map +1 -0
- package/build/tools/execute-command.js +53 -0
- package/build/tools/execute-command.js.map +1 -0
- package/build/tools/index.js +17 -0
- package/build/tools/index.js.map +1 -0
- package/build/tools/list-directory.js +57 -0
- package/build/tools/list-directory.js.map +1 -0
- package/build/tools/list-servers.js +51 -0
- package/build/tools/list-servers.js.map +1 -0
- package/build/tools/upload.js +41 -0
- package/build/tools/upload.js.map +1 -0
- package/build/utils/logger.js +28 -0
- package/build/utils/logger.js.map +1 -0
- package/build/utils/ssh-config-parser.js +195 -0
- package/build/utils/ssh-config-parser.js.map +1 -0
- package/build/utils/status-collector.js +226 -0
- package/build/utils/status-collector.js.map +1 -0
- package/build/utils/tool-error.js +20 -0
- package/build/utils/tool-error.js.map +1 -0
- package/package.json +69 -0
package/build/index.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { SshMcpServer } from "./core/mcp-server.js";
|
|
3
|
+
import { SERVER_CONFIG } from "./config/server.js";
|
|
4
|
+
import { Logger } from "./utils/logger.js";
|
|
5
|
+
import { CommandLineParser } from "./cli/command-line-parser.js";
|
|
6
|
+
import { resolveRunMode } from "./cli/run-mode.js";
|
|
7
|
+
import { runProxyMode } from "./cli/stdio-proxy.js";
|
|
8
|
+
import { ConfigStore, getGlobalConfigPath } from "./services/config-store.js";
|
|
9
|
+
import { DEFAULT_ADMIN_PORT } from "./models/admin-types.js";
|
|
10
|
+
import { startAdminServer } from "./server/index.js";
|
|
11
|
+
const HELP_TEXT = `Usage: ssh-mcp-server [options] [host port username password]
|
|
12
|
+
|
|
13
|
+
Options:
|
|
14
|
+
--config-file <path> Load SSH server configs from a JSON file
|
|
15
|
+
--ssh-config-file <path> Read host aliases from SSH config (default: ~/.ssh/config)
|
|
16
|
+
--ssh <config> Add an SSH config as JSON or legacy key=value pairs (repeatable)
|
|
17
|
+
-h, --host <host> SSH host or SSH config alias for single-host mode
|
|
18
|
+
-p, --port <port> SSH port for single-host mode
|
|
19
|
+
-u, --username <name> SSH username for single-host mode
|
|
20
|
+
-w, --password <password> SSH password for single-host mode
|
|
21
|
+
-k, --privateKey <path> SSH private key path for single-host mode
|
|
22
|
+
-P, --passphrase <passphrase> SSH private key passphrase
|
|
23
|
+
-a, --agent <path> SSH agent socket path or pageant on Windows
|
|
24
|
+
-W, --whitelist <patterns> Command whitelist regexes, comma-separated
|
|
25
|
+
-B, --blacklist <patterns> Command blacklist regexes, comma-separated
|
|
26
|
+
--proxy <url> Proxy URL (SOCKS5, HTTP, or HTTPS)
|
|
27
|
+
-s, --socksProxy <url> Legacy SOCKS5 proxy URL
|
|
28
|
+
--allowed-local-paths <paths> Extra allowed local paths, comma-separated
|
|
29
|
+
--allowed-remote-paths <paths> Allowed remote POSIX absolute paths, comma-separated
|
|
30
|
+
--transport-mode <mode> SSH transport mode: exec or shell (default: exec)
|
|
31
|
+
--shell-ready-timeout <ms> Shell readiness probe timeout (default: 10000)
|
|
32
|
+
--command-template <template> Wrap commands with <command> or <quotedCommand>
|
|
33
|
+
--pty Allocate pseudo-tty for exec mode commands (default: true)
|
|
34
|
+
--try-keyboard Enable keyboard-interactive authentication
|
|
35
|
+
--pre-connect Pre-connect to all SSH servers on startup
|
|
36
|
+
--stdio Force legacy stdio MCP mode (no auto-started admin daemon)
|
|
37
|
+
--admin Start admin HTTP server (127.0.0.1:${DEFAULT_ADMIN_PORT})
|
|
38
|
+
--admin-port <port> Admin HTTP port (default ${DEFAULT_ADMIN_PORT}, overrides config file)
|
|
39
|
+
--version, -v Print package version
|
|
40
|
+
--help Print this help message`;
|
|
41
|
+
function hasArg(...names) {
|
|
42
|
+
return process.argv.slice(2).some((arg) => names.includes(arg));
|
|
43
|
+
}
|
|
44
|
+
function getArgValue(name) {
|
|
45
|
+
const idx = process.argv.indexOf(name);
|
|
46
|
+
if (idx !== -1 && idx + 1 < process.argv.length)
|
|
47
|
+
return process.argv[idx + 1];
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Main program entry
|
|
52
|
+
*/
|
|
53
|
+
async function main() {
|
|
54
|
+
if (hasArg("--help")) {
|
|
55
|
+
console.log(HELP_TEXT);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (hasArg("--version", "-v")) {
|
|
59
|
+
console.log(SERVER_CONFIG.version);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const runMode = resolveRunMode(process.argv.slice(2));
|
|
63
|
+
// Admin mode: single Fastify host 127.0.0.1, priority CLI > file > default
|
|
64
|
+
if (runMode.mode === "admin") {
|
|
65
|
+
const parsed = CommandLineParser.parseArgs();
|
|
66
|
+
// --admin-port is the authoritative admin port (distinct from --port SSH port)
|
|
67
|
+
const cliPort = runMode.adminPort;
|
|
68
|
+
// Config file override chain: --config-file > SSH_MCP_CONFIG env > global path
|
|
69
|
+
const configPath = parsed.configFile ?? process.env.SSH_MCP_CONFIG ?? getGlobalConfigPath();
|
|
70
|
+
// For admin mode, we still need to respect stored port if no CLI override
|
|
71
|
+
let filePort;
|
|
72
|
+
try {
|
|
73
|
+
const store = new ConfigStore({ configPath });
|
|
74
|
+
const cfg = await store.load();
|
|
75
|
+
filePort = cfg.port;
|
|
76
|
+
}
|
|
77
|
+
catch { }
|
|
78
|
+
const port = cliPort ?? filePort ?? DEFAULT_ADMIN_PORT;
|
|
79
|
+
const srv = await startAdminServer({ port, configPath });
|
|
80
|
+
Logger.log(`Admin server listening on 127.0.0.1:${srv.port}`, "info");
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
// Proxy mode(npx 默认): 确保 admin 常驻服务运行后做 stdio→HTTP 转发
|
|
84
|
+
if (runMode.mode === "proxy") {
|
|
85
|
+
try {
|
|
86
|
+
await runProxyMode({ adminPort: runMode.adminPort });
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
Logger.log(error instanceof Error ? error.message : String(error), "error");
|
|
90
|
+
process.exitCode = 1;
|
|
91
|
+
}
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const sshMcpServer = new SshMcpServer();
|
|
95
|
+
await sshMcpServer.run();
|
|
96
|
+
}
|
|
97
|
+
main().catch((error) => Logger.handleError(error, "【SSH MCP Server Error】", true));
|
|
98
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// 管理端口默认值的唯一来源:models 层定义,services/server/cli 各处引用,避免多处写死漂移
|
|
3
|
+
export const DEFAULT_ADMIN_PORT = 61823;
|
|
4
|
+
const MAX_TIMEOUT_MS = 2_147_483_647; // setTimeout/setInterval 32-bit signed int 上限
|
|
5
|
+
const timeout = z.number().int().positive().max(MAX_TIMEOUT_MS).optional();
|
|
6
|
+
export const ConnectionSchema = z
|
|
7
|
+
.object({
|
|
8
|
+
name: z.string().min(1),
|
|
9
|
+
host: z.string().min(1),
|
|
10
|
+
port: z.number().int().min(1).max(65535),
|
|
11
|
+
username: z.string().min(1),
|
|
12
|
+
password: z.string().optional(),
|
|
13
|
+
privateKey: z.string().optional(),
|
|
14
|
+
passphrase: z.string().optional(),
|
|
15
|
+
agent: z.string().optional(),
|
|
16
|
+
tryKeyboard: z.boolean().optional(),
|
|
17
|
+
proxy: z.string().optional(),
|
|
18
|
+
socksProxy: z.string().optional(),
|
|
19
|
+
pty: z.boolean().optional(),
|
|
20
|
+
transportMode: z.enum(["exec", "shell"]).optional(),
|
|
21
|
+
shellReadyTimeoutMs: timeout,
|
|
22
|
+
shellCommandTimeoutMs: timeout,
|
|
23
|
+
commandTimeoutMs: timeout,
|
|
24
|
+
connectionTimeoutMs: timeout,
|
|
25
|
+
sftpTimeoutMs: timeout,
|
|
26
|
+
maxOutputBytes: z.number().int().min(0).optional(),
|
|
27
|
+
keepaliveIntervalMs: timeout,
|
|
28
|
+
keepaliveCountMax: timeout,
|
|
29
|
+
commandTemplate: z
|
|
30
|
+
.string()
|
|
31
|
+
.optional()
|
|
32
|
+
.refine((v) => !v || v.includes("<command>") || v.includes("<quotedCommand>"), "commandTemplate 必须包含 <command> 或 <quotedCommand>"),
|
|
33
|
+
allowedLocalPaths: z.array(z.string()).optional(),
|
|
34
|
+
allowedRemotePaths: z
|
|
35
|
+
.array(z.string())
|
|
36
|
+
.optional()
|
|
37
|
+
.refine((v) => !v || v.every((p) => p.startsWith("/")), "远端路径必须为绝对 POSIX 路径"),
|
|
38
|
+
commandWhitelist: z
|
|
39
|
+
.array(z.string())
|
|
40
|
+
.optional()
|
|
41
|
+
.refine((v) => !v ||
|
|
42
|
+
v.every((s) => {
|
|
43
|
+
try {
|
|
44
|
+
new RegExp(s);
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}), "正则格式不正确"),
|
|
51
|
+
commandBlacklist: z
|
|
52
|
+
.array(z.string())
|
|
53
|
+
.optional()
|
|
54
|
+
.refine((v) => !v ||
|
|
55
|
+
v.every((s) => {
|
|
56
|
+
try {
|
|
57
|
+
new RegExp(s);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}), "正则格式不正确"),
|
|
64
|
+
algorithms: z.record(z.string(), z.any()).optional(),
|
|
65
|
+
})
|
|
66
|
+
.passthrough();
|
|
67
|
+
export const HostSchema = ConnectionSchema;
|
|
68
|
+
export const EnvironmentSchema = z
|
|
69
|
+
.object({
|
|
70
|
+
displayName: z.string().max(100).optional(),
|
|
71
|
+
hostOrder: z.array(z.string()).optional(),
|
|
72
|
+
hosts: z.record(z.string().min(1), HostSchema),
|
|
73
|
+
})
|
|
74
|
+
.passthrough();
|
|
75
|
+
export const ProjectSchema = z
|
|
76
|
+
.object({
|
|
77
|
+
displayName: z.string().max(100).optional(),
|
|
78
|
+
defaultEnvironment: z.string().min(1).optional(),
|
|
79
|
+
environments: z.record(z.string().min(1), EnvironmentSchema).default({}),
|
|
80
|
+
})
|
|
81
|
+
.passthrough()
|
|
82
|
+
.superRefine((p, ctx) => {
|
|
83
|
+
if (p.defaultEnvironment && !p.environments[p.defaultEnvironment]) {
|
|
84
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["defaultEnvironment"], message: "默认环境不存在" });
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
export const SettingsSchema = z.object({
|
|
88
|
+
port: z.coerce.number().int().min(1).max(65535).optional(),
|
|
89
|
+
preConnect: z.boolean().optional(),
|
|
90
|
+
audit: z
|
|
91
|
+
.object({
|
|
92
|
+
enabled: z.boolean().optional(),
|
|
93
|
+
retentionDays: z.number().int().min(1).max(365).optional(),
|
|
94
|
+
logResults: z.boolean().optional(),
|
|
95
|
+
})
|
|
96
|
+
.optional(),
|
|
97
|
+
backups: z
|
|
98
|
+
.object({
|
|
99
|
+
retentionDays: z.number().int().min(1).max(365).optional(),
|
|
100
|
+
maxCount: z.number().int().min(1).optional(),
|
|
101
|
+
autoEnabled: z.boolean().optional(),
|
|
102
|
+
intervalHours: z.number().int().min(1).max(720).optional(),
|
|
103
|
+
})
|
|
104
|
+
.optional(),
|
|
105
|
+
});
|
|
106
|
+
export const GlobalConfigSchema = z.object({
|
|
107
|
+
port: z.number().int().min(0).max(65535).default(DEFAULT_ADMIN_PORT),
|
|
108
|
+
projects: z.record(z.string().min(1), ProjectSchema).default({}),
|
|
109
|
+
projectOrder: z.array(z.string()).optional(),
|
|
110
|
+
audit: z
|
|
111
|
+
.object({
|
|
112
|
+
enabled: z.boolean().optional(),
|
|
113
|
+
retentionDays: z.number().int().min(1).max(365).optional(),
|
|
114
|
+
logResults: z.boolean().optional(),
|
|
115
|
+
})
|
|
116
|
+
.optional(),
|
|
117
|
+
backups: z
|
|
118
|
+
.object({
|
|
119
|
+
retentionDays: z.number().int().min(1).max(365).optional(),
|
|
120
|
+
maxCount: z.number().int().min(1).optional(),
|
|
121
|
+
autoEnabled: z.boolean().optional(),
|
|
122
|
+
intervalHours: z.number().int().min(1).max(720).optional(),
|
|
123
|
+
})
|
|
124
|
+
.optional(),
|
|
125
|
+
security: z
|
|
126
|
+
.object({
|
|
127
|
+
commandWhitelist: z.array(z.string()).optional(),
|
|
128
|
+
commandBlacklist: z.array(z.string()).optional(),
|
|
129
|
+
allowedLocalPaths: z.array(z.string()).optional(),
|
|
130
|
+
allowedRemotePaths: z.array(z.string()).optional(),
|
|
131
|
+
})
|
|
132
|
+
.optional(),
|
|
133
|
+
preConnect: z.boolean().optional(),
|
|
134
|
+
});
|
|
135
|
+
//# sourceMappingURL=admin-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-types.js","sourceRoot":"","sources":["../../src/models/admin-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/models/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import Fastify from "fastify";
|
|
2
|
+
import fastifyStatic from "@fastify/static";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { DEFAULT_ADMIN_PORT } from "../models/admin-types.js";
|
|
7
|
+
import { ConfigStore } from "../services/config-store.js";
|
|
8
|
+
import { registerAdminRoutes } from "./routes/admin.js";
|
|
9
|
+
import { registerMcpRoutes } from "./routes/mcp.js";
|
|
10
|
+
import { registerAuditRoutes } from "./routes/audit.js";
|
|
11
|
+
import { registerBackupRoutes } from "./routes/backups.js";
|
|
12
|
+
import { registerSystemRoutes } from "./routes/system.js";
|
|
13
|
+
import { registerSettingsRoutes } from "./routes/settings.js";
|
|
14
|
+
import { BackupService } from "../services/backup-service.js";
|
|
15
|
+
import { startBackupScheduler, stopBackupScheduler } from "../services/backup-scheduler.js";
|
|
16
|
+
import { SSHConnectionManager } from "../services/ssh-connection-manager.js";
|
|
17
|
+
async function createServerInstance(opts = {}, onRestart) {
|
|
18
|
+
const store = new ConfigStore({ configPath: opts.configPath });
|
|
19
|
+
const cfg = await store.load();
|
|
20
|
+
const port = opts.port ?? cfg.port ?? DEFAULT_ADMIN_PORT;
|
|
21
|
+
const app = Fastify({ logger: false });
|
|
22
|
+
// 仅信任本地回环 Host 头:接口无鉴权,靠该校验阻断网页经 DNS rebinding 读配置/调 /mcp
|
|
23
|
+
const trustedHosts = new Set(["127.0.0.1", "localhost", "[::1]", "::1"]);
|
|
24
|
+
app.addHook("onRequest", async (req, reply) => {
|
|
25
|
+
const raw = String(req.headers.host || "").toLowerCase();
|
|
26
|
+
let hostname = raw;
|
|
27
|
+
if (hostname.startsWith("[")) {
|
|
28
|
+
const end = hostname.indexOf("]");
|
|
29
|
+
hostname = end > 0 ? hostname.slice(0, end + 1) : hostname;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const idx = hostname.lastIndexOf(":");
|
|
33
|
+
if (idx > 0)
|
|
34
|
+
hostname = hostname.slice(0, idx);
|
|
35
|
+
}
|
|
36
|
+
if (!trustedHosts.has(hostname)) {
|
|
37
|
+
return reply.code(403).send({ ok: false, code: "HOST_FORBIDDEN", message: "不允许的 Host 头" });
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
registerAdminRoutes(app, store);
|
|
41
|
+
registerSettingsRoutes(app, store);
|
|
42
|
+
registerAuditRoutes(app);
|
|
43
|
+
registerBackupRoutes(app, store);
|
|
44
|
+
// 同进程软重启:不依赖外部拉起进程(沙箱/服务/终端环境均可靠),由外层 holder 负责先关旧实例
|
|
45
|
+
registerSystemRoutes(app, store, { onRestart });
|
|
46
|
+
// HTTP /mcp 与 stdio 共用 SSHConnectionManager 单例:启动即加载 UI 配置,
|
|
47
|
+
// 配置文件变更时热同步(仅 projects/security 变化才重置,避免改端口等误断开所有连接)
|
|
48
|
+
const sshManager = SSHConnectionManager.getInstance();
|
|
49
|
+
let mcpConfigSig = null;
|
|
50
|
+
const applyMcpConfig = (c) => {
|
|
51
|
+
const sig = JSON.stringify({ projects: c.projects, security: c.security });
|
|
52
|
+
if (sig === mcpConfigSig)
|
|
53
|
+
return;
|
|
54
|
+
mcpConfigSig = sig;
|
|
55
|
+
sshManager.setConfig(c);
|
|
56
|
+
if (c?.preConnect) {
|
|
57
|
+
void sshManager.connectAll().catch(() => { });
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
applyMcpConfig(cfg);
|
|
61
|
+
// 独立于备份调度器的配置 watcher:UI 保存配置后 HTTP /mcp 即时生效
|
|
62
|
+
const stopMcpWatch = store.onChange((nextCfg) => {
|
|
63
|
+
try {
|
|
64
|
+
applyMcpConfig(nextCfg);
|
|
65
|
+
}
|
|
66
|
+
catch { }
|
|
67
|
+
});
|
|
68
|
+
await registerMcpRoutes(app);
|
|
69
|
+
// R6/R7: 静态托管 admin-web/dist 于 /admin/ (同端口)
|
|
70
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
71
|
+
const dist = path.join(__dirname, "../../admin-web/dist");
|
|
72
|
+
if (fs.existsSync(dist)) {
|
|
73
|
+
await app.register(fastifyStatic, { root: dist, prefix: "/admin/" });
|
|
74
|
+
// SPA fallback: /admin -> index.html (fastifyStatic 已处理 /admin/,此处补 /admin 无斜杠)
|
|
75
|
+
app.get("/admin", async (_req, reply) => reply.sendFile("index.html"));
|
|
76
|
+
// 根路径直接跳转管理界面,避免裸 / 404
|
|
77
|
+
app.get("/", async (_req, reply) => reply.redirect("/admin/"));
|
|
78
|
+
}
|
|
79
|
+
await app.listen({ host: "127.0.0.1", port });
|
|
80
|
+
const addr = app.server.address();
|
|
81
|
+
const actualPort = addr.port;
|
|
82
|
+
// 定时备份调度
|
|
83
|
+
let stopWatch = null;
|
|
84
|
+
try {
|
|
85
|
+
const svc = new BackupService(store);
|
|
86
|
+
startBackupScheduler(store, svc, cfg);
|
|
87
|
+
// 配置变更时重调度(热重载)
|
|
88
|
+
stopWatch = store.onChange((nextCfg) => {
|
|
89
|
+
try {
|
|
90
|
+
startBackupScheduler(store, svc, nextCfg);
|
|
91
|
+
}
|
|
92
|
+
catch { }
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
catch { }
|
|
96
|
+
return {
|
|
97
|
+
port: actualPort,
|
|
98
|
+
close: async () => { try {
|
|
99
|
+
stopBackupScheduler();
|
|
100
|
+
}
|
|
101
|
+
catch { } try {
|
|
102
|
+
stopWatch?.();
|
|
103
|
+
}
|
|
104
|
+
catch { } try {
|
|
105
|
+
stopMcpWatch();
|
|
106
|
+
}
|
|
107
|
+
catch { } return app.close(); },
|
|
108
|
+
app,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
export async function startAdminServer(opts = {}) {
|
|
112
|
+
// 重启 = 关闭当前实例(释放端口、停调度器/watcher)→ 以最新配置重建并监听
|
|
113
|
+
const holder = {};
|
|
114
|
+
const onRestart = async () => {
|
|
115
|
+
if (holder.current)
|
|
116
|
+
await holder.current.close();
|
|
117
|
+
const next = await createServerInstance(opts, onRestart);
|
|
118
|
+
holder.current = next;
|
|
119
|
+
return next.port;
|
|
120
|
+
};
|
|
121
|
+
holder.current = await createServerInstance(opts, onRestart);
|
|
122
|
+
return {
|
|
123
|
+
get port() { return holder.current.port; },
|
|
124
|
+
get app() { return holder.current.app; },
|
|
125
|
+
close: async () => holder.current.close(),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
|