@hangox/mg-cli 1.0.0 → 1.0.2
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/dist/cli.js +1580 -0
- package/dist/cli.js.map +1 -0
- package/dist/daemon-runner.js +794 -0
- package/dist/daemon-runner.js.map +1 -0
- package/dist/index-DNrszrq9.d.ts +568 -0
- package/dist/index.d.ts +129 -0
- package/dist/index.js +950 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +689 -0
- package/dist/server.js.map +1 -0
- package/package.json +5 -1
- package/.eslintrc.cjs +0 -26
- package/CLAUDE.md +0 -43
- package/src/cli/client.ts +0 -266
- package/src/cli/commands/execute-code.ts +0 -59
- package/src/cli/commands/export-image.ts +0 -193
- package/src/cli/commands/get-all-nodes.ts +0 -81
- package/src/cli/commands/get-all-pages.ts +0 -118
- package/src/cli/commands/get-node-by-id.ts +0 -83
- package/src/cli/commands/get-node-by-link.ts +0 -105
- package/src/cli/commands/server.ts +0 -130
- package/src/cli/index.ts +0 -33
- package/src/index.ts +0 -9
- package/src/server/connection-manager.ts +0 -211
- package/src/server/daemon-runner.ts +0 -22
- package/src/server/daemon.ts +0 -211
- package/src/server/index.ts +0 -8
- package/src/server/logger.ts +0 -117
- package/src/server/request-handler.ts +0 -192
- package/src/server/websocket-server.ts +0 -297
- package/src/shared/constants.ts +0 -90
- package/src/shared/errors.ts +0 -131
- package/src/shared/index.ts +0 -8
- package/src/shared/types.ts +0 -227
- package/src/shared/utils.ts +0 -352
- package/tests/unit/shared/constants.test.ts +0 -66
- package/tests/unit/shared/errors.test.ts +0 -82
- package/tests/unit/shared/utils.test.ts +0 -208
- package/tsconfig.json +0 -22
- package/tsup.config.ts +0 -33
- package/vitest.config.ts +0 -22
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Server 管理命令
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { Command } from 'commander'
|
|
6
|
-
import {
|
|
7
|
-
startServerForeground,
|
|
8
|
-
startServerDaemon,
|
|
9
|
-
stopServer,
|
|
10
|
-
restartServer,
|
|
11
|
-
getServerStatus,
|
|
12
|
-
} from '../../server/daemon.js'
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* 创建 server 命令组
|
|
16
|
-
*/
|
|
17
|
-
export function createServerCommand(): Command {
|
|
18
|
-
const serverCmd = new Command('server')
|
|
19
|
-
.description('Server 管理命令')
|
|
20
|
-
|
|
21
|
-
// server start
|
|
22
|
-
serverCmd
|
|
23
|
-
.command('start')
|
|
24
|
-
.description('启动 MG Server')
|
|
25
|
-
.option('--port <number>', '指定启动端口', (value) => parseInt(value, 10))
|
|
26
|
-
.option('--foreground', '前台模式运行(不作为守护进程)', false)
|
|
27
|
-
.action(async (options) => {
|
|
28
|
-
try {
|
|
29
|
-
if (options.foreground) {
|
|
30
|
-
await startServerForeground(options.port)
|
|
31
|
-
} else {
|
|
32
|
-
const info = await startServerDaemon(options.port)
|
|
33
|
-
console.log('MG Server 启动成功')
|
|
34
|
-
console.log(`监听端口: ${info.port}`)
|
|
35
|
-
console.log(`进程 PID: ${info.pid}`)
|
|
36
|
-
console.log(`运行模式: 守护进程`)
|
|
37
|
-
}
|
|
38
|
-
} catch (error: any) {
|
|
39
|
-
console.error(`错误: ${error.message}`)
|
|
40
|
-
process.exit(1)
|
|
41
|
-
}
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
// server stop
|
|
45
|
-
serverCmd
|
|
46
|
-
.command('stop')
|
|
47
|
-
.description('停止 MG Server')
|
|
48
|
-
.action(() => {
|
|
49
|
-
try {
|
|
50
|
-
const { stopped, info } = stopServer()
|
|
51
|
-
|
|
52
|
-
if (stopped && info) {
|
|
53
|
-
console.log('MG Server 已停止')
|
|
54
|
-
console.log(`PID: ${info.pid}`)
|
|
55
|
-
|
|
56
|
-
// 计算运行时长
|
|
57
|
-
const uptimeMs = Date.now() - new Date(info.startedAt).getTime()
|
|
58
|
-
const seconds = Math.floor(uptimeMs / 1000)
|
|
59
|
-
const minutes = Math.floor(seconds / 60)
|
|
60
|
-
const hours = Math.floor(minutes / 60)
|
|
61
|
-
|
|
62
|
-
let uptime = ''
|
|
63
|
-
if (hours > 0) {
|
|
64
|
-
uptime = `${hours} 小时 ${minutes % 60} 分钟`
|
|
65
|
-
} else if (minutes > 0) {
|
|
66
|
-
uptime = `${minutes} 分钟 ${seconds % 60} 秒`
|
|
67
|
-
} else {
|
|
68
|
-
uptime = `${seconds} 秒`
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
console.log(`运行时长: ${uptime}`)
|
|
72
|
-
} else {
|
|
73
|
-
console.log('MG Server 未运行')
|
|
74
|
-
}
|
|
75
|
-
} catch (error: any) {
|
|
76
|
-
console.error(`错误: ${error.message}`)
|
|
77
|
-
process.exit(1)
|
|
78
|
-
}
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
// server restart
|
|
82
|
-
serverCmd
|
|
83
|
-
.command('restart')
|
|
84
|
-
.description('重启 MG Server')
|
|
85
|
-
.option('--port <number>', '重启后使用的端口', (value) => parseInt(value, 10))
|
|
86
|
-
.action(async (options) => {
|
|
87
|
-
try {
|
|
88
|
-
const status = getServerStatus()
|
|
89
|
-
|
|
90
|
-
if (status.running) {
|
|
91
|
-
console.log(`正在停止 MG Server (PID: ${status.pid})...`)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const info = await restartServer(options.port)
|
|
95
|
-
|
|
96
|
-
console.log('MG Server 已重启')
|
|
97
|
-
console.log(`监听端口: ${info.port}`)
|
|
98
|
-
console.log(`新进程 PID: ${info.pid}`)
|
|
99
|
-
} catch (error: any) {
|
|
100
|
-
console.error(`错误: ${error.message}`)
|
|
101
|
-
process.exit(1)
|
|
102
|
-
}
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
// server status
|
|
106
|
-
serverCmd
|
|
107
|
-
.command('status')
|
|
108
|
-
.description('查看 Server 运行状态')
|
|
109
|
-
.action(() => {
|
|
110
|
-
try {
|
|
111
|
-
const status = getServerStatus()
|
|
112
|
-
|
|
113
|
-
if (status.running) {
|
|
114
|
-
console.log('MG Server 状态: 运行中 ✓')
|
|
115
|
-
console.log(`监听端口: ${status.port}`)
|
|
116
|
-
console.log(`进程 PID: ${status.pid}`)
|
|
117
|
-
console.log(`启动时间: ${status.startedAt}`)
|
|
118
|
-
console.log(`运行时长: ${status.uptime}`)
|
|
119
|
-
} else {
|
|
120
|
-
console.log('MG Server 状态: 未运行 ✗')
|
|
121
|
-
console.log("提示: 使用 'mg-cli server start' 启动 Server")
|
|
122
|
-
}
|
|
123
|
-
} catch (error: any) {
|
|
124
|
-
console.error(`错误: ${error.message}`)
|
|
125
|
-
process.exit(1)
|
|
126
|
-
}
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
return serverCmd
|
|
130
|
-
}
|
package/src/cli/index.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MG CLI 入口
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { Command } from 'commander'
|
|
6
|
-
import { createServerCommand } from './commands/server.js'
|
|
7
|
-
import { createGetNodeByIdCommand } from './commands/get-node-by-id.js'
|
|
8
|
-
import { createGetNodeByLinkCommand } from './commands/get-node-by-link.js'
|
|
9
|
-
import { createGetAllNodesCommand } from './commands/get-all-nodes.js'
|
|
10
|
-
import { createExportImageCommand } from './commands/export-image.js'
|
|
11
|
-
import { createExecuteCodeCommand } from './commands/execute-code.js'
|
|
12
|
-
import { createGetAllPagesCommand } from './commands/get-all-pages.js'
|
|
13
|
-
|
|
14
|
-
const program = new Command()
|
|
15
|
-
|
|
16
|
-
program
|
|
17
|
-
.name('mg-cli')
|
|
18
|
-
.description('MasterGo CLI 工具 - 用于 Claude Code 与 MasterGo 通信')
|
|
19
|
-
.version('1.0.0')
|
|
20
|
-
|
|
21
|
-
// 添加 server 命令组
|
|
22
|
-
program.addCommand(createServerCommand())
|
|
23
|
-
|
|
24
|
-
// 添加业务命令
|
|
25
|
-
program.addCommand(createGetNodeByIdCommand())
|
|
26
|
-
program.addCommand(createGetNodeByLinkCommand())
|
|
27
|
-
program.addCommand(createGetAllNodesCommand())
|
|
28
|
-
program.addCommand(createExportImageCommand())
|
|
29
|
-
program.addCommand(createExecuteCodeCommand())
|
|
30
|
-
program.addCommand(createGetAllPagesCommand())
|
|
31
|
-
|
|
32
|
-
// 解析命令行参数
|
|
33
|
-
program.parse()
|
package/src/index.ts
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 连接管理器
|
|
3
|
-
* 管理 Provider 和 Consumer 的 WebSocket 连接
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { WebSocket } from 'ws'
|
|
7
|
-
import { ConnectionType, HEARTBEAT_TIMEOUT } from '../shared/constants.js'
|
|
8
|
-
import type { ConnectionInfo } from '../shared/types.js'
|
|
9
|
-
import { generateId } from '../shared/utils.js'
|
|
10
|
-
import { Logger } from './logger.js'
|
|
11
|
-
|
|
12
|
-
/** 带连接信息的 WebSocket */
|
|
13
|
-
export interface ManagedWebSocket extends WebSocket {
|
|
14
|
-
/** 连接 ID */
|
|
15
|
-
connectionId: string
|
|
16
|
-
/** 连接信息 */
|
|
17
|
-
connectionInfo: ConnectionInfo
|
|
18
|
-
/** 是否存活 */
|
|
19
|
-
isAlive: boolean
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* 连接管理器
|
|
24
|
-
*/
|
|
25
|
-
export class ConnectionManager {
|
|
26
|
-
private logger: Logger
|
|
27
|
-
|
|
28
|
-
/** Provider 连接(按页面 URL 索引) */
|
|
29
|
-
private providers = new Map<string, ManagedWebSocket>()
|
|
30
|
-
|
|
31
|
-
/** Consumer 连接 */
|
|
32
|
-
private consumers = new Map<string, ManagedWebSocket>()
|
|
33
|
-
|
|
34
|
-
/** 所有连接(按 ID 索引) */
|
|
35
|
-
private allConnections = new Map<string, ManagedWebSocket>()
|
|
36
|
-
|
|
37
|
-
/** 心跳检查定时器 */
|
|
38
|
-
private heartbeatTimer: NodeJS.Timeout | null = null
|
|
39
|
-
|
|
40
|
-
constructor(logger: Logger) {
|
|
41
|
-
this.logger = logger
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* 启动心跳检查
|
|
46
|
-
*/
|
|
47
|
-
startHeartbeatCheck(interval: number = 30000): void {
|
|
48
|
-
if (this.heartbeatTimer) {
|
|
49
|
-
clearInterval(this.heartbeatTimer)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
this.heartbeatTimer = setInterval(() => {
|
|
53
|
-
this.checkHeartbeats()
|
|
54
|
-
}, interval)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* 停止心跳检查
|
|
59
|
-
*/
|
|
60
|
-
stopHeartbeatCheck(): void {
|
|
61
|
-
if (this.heartbeatTimer) {
|
|
62
|
-
clearInterval(this.heartbeatTimer)
|
|
63
|
-
this.heartbeatTimer = null
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* 检查所有连接的心跳
|
|
69
|
-
*/
|
|
70
|
-
private checkHeartbeats(): void {
|
|
71
|
-
const now = Date.now()
|
|
72
|
-
|
|
73
|
-
for (const [id, ws] of this.allConnections) {
|
|
74
|
-
const lastActive = ws.connectionInfo.lastActiveAt.getTime()
|
|
75
|
-
const elapsed = now - lastActive
|
|
76
|
-
|
|
77
|
-
if (elapsed > HEARTBEAT_TIMEOUT) {
|
|
78
|
-
this.logger.warn(`连接 ${id} 心跳超时,关闭连接`)
|
|
79
|
-
this.removeConnection(ws)
|
|
80
|
-
ws.terminate()
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* 添加连接
|
|
87
|
-
*/
|
|
88
|
-
addConnection(
|
|
89
|
-
ws: WebSocket,
|
|
90
|
-
type: ConnectionType,
|
|
91
|
-
pageUrl?: string,
|
|
92
|
-
pageId?: string
|
|
93
|
-
): ManagedWebSocket {
|
|
94
|
-
const connectionId = generateId()
|
|
95
|
-
const now = new Date()
|
|
96
|
-
|
|
97
|
-
const connectionInfo: ConnectionInfo = {
|
|
98
|
-
id: connectionId,
|
|
99
|
-
type,
|
|
100
|
-
pageUrl,
|
|
101
|
-
pageId,
|
|
102
|
-
connectedAt: now,
|
|
103
|
-
lastActiveAt: now,
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const managedWs = ws as ManagedWebSocket
|
|
107
|
-
managedWs.connectionId = connectionId
|
|
108
|
-
managedWs.connectionInfo = connectionInfo
|
|
109
|
-
managedWs.isAlive = true
|
|
110
|
-
|
|
111
|
-
this.allConnections.set(connectionId, managedWs)
|
|
112
|
-
|
|
113
|
-
if (type === ConnectionType.PROVIDER && pageUrl) {
|
|
114
|
-
// 如果已有同页面的连接,先移除旧的
|
|
115
|
-
const existing = this.providers.get(pageUrl)
|
|
116
|
-
if (existing) {
|
|
117
|
-
this.logger.info(`页面 ${pageUrl} 已有连接,替换为新连接`)
|
|
118
|
-
this.removeConnection(existing)
|
|
119
|
-
existing.close()
|
|
120
|
-
}
|
|
121
|
-
this.providers.set(pageUrl, managedWs)
|
|
122
|
-
this.logger.info(`Provider 连接: ${pageUrl}`)
|
|
123
|
-
} else if (type === ConnectionType.CONSUMER) {
|
|
124
|
-
this.consumers.set(connectionId, managedWs)
|
|
125
|
-
this.logger.info(`Consumer 连接: ${connectionId}`)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return managedWs
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* 移除连接
|
|
133
|
-
*/
|
|
134
|
-
removeConnection(ws: ManagedWebSocket): void {
|
|
135
|
-
const { connectionId, connectionInfo } = ws
|
|
136
|
-
|
|
137
|
-
this.allConnections.delete(connectionId)
|
|
138
|
-
|
|
139
|
-
if (connectionInfo.type === ConnectionType.PROVIDER && connectionInfo.pageUrl) {
|
|
140
|
-
this.providers.delete(connectionInfo.pageUrl)
|
|
141
|
-
this.logger.info(`Provider 断开: ${connectionInfo.pageUrl}`)
|
|
142
|
-
} else if (connectionInfo.type === ConnectionType.CONSUMER) {
|
|
143
|
-
this.consumers.delete(connectionId)
|
|
144
|
-
this.logger.info(`Consumer 断开: ${connectionId}`)
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* 更新连接活跃时间
|
|
150
|
-
*/
|
|
151
|
-
updateLastActive(ws: ManagedWebSocket): void {
|
|
152
|
-
ws.connectionInfo.lastActiveAt = new Date()
|
|
153
|
-
ws.isAlive = true
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* 根据页面 URL 查找 Provider
|
|
158
|
-
*/
|
|
159
|
-
findProviderByPageUrl(pageUrl: string): ManagedWebSocket | undefined {
|
|
160
|
-
return this.providers.get(pageUrl)
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* 获取第一个可用的 Provider
|
|
165
|
-
*/
|
|
166
|
-
getFirstProvider(): ManagedWebSocket | undefined {
|
|
167
|
-
const iterator = this.providers.values()
|
|
168
|
-
const first = iterator.next()
|
|
169
|
-
return first.value
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* 获取所有 Provider 信息
|
|
174
|
-
*/
|
|
175
|
-
getAllProviders(): ConnectionInfo[] {
|
|
176
|
-
return Array.from(this.providers.values()).map((ws) => ws.connectionInfo)
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* 获取连接统计
|
|
181
|
-
*/
|
|
182
|
-
getStats(): { providers: number; consumers: number; total: number } {
|
|
183
|
-
return {
|
|
184
|
-
providers: this.providers.size,
|
|
185
|
-
consumers: this.consumers.size,
|
|
186
|
-
total: this.allConnections.size,
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* 获取所有已连接的页面 URL
|
|
192
|
-
*/
|
|
193
|
-
getConnectedPageUrls(): string[] {
|
|
194
|
-
return Array.from(this.providers.keys())
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* 关闭所有连接
|
|
199
|
-
*/
|
|
200
|
-
closeAll(): void {
|
|
201
|
-
this.stopHeartbeatCheck()
|
|
202
|
-
|
|
203
|
-
for (const ws of this.allConnections.values()) {
|
|
204
|
-
ws.close()
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
this.providers.clear()
|
|
208
|
-
this.consumers.clear()
|
|
209
|
-
this.allConnections.clear()
|
|
210
|
-
}
|
|
211
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 守护进程启动脚本
|
|
3
|
-
* 这个脚本被 daemon.ts 作为子进程启动
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { startServerForeground } from './daemon.js'
|
|
7
|
-
|
|
8
|
-
// 解析命令行参数
|
|
9
|
-
const args = process.argv.slice(2)
|
|
10
|
-
let port: number | undefined
|
|
11
|
-
|
|
12
|
-
for (let i = 0; i < args.length; i++) {
|
|
13
|
-
if (args[i] === '--port' && args[i + 1]) {
|
|
14
|
-
port = parseInt(args[i + 1], 10)
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// 启动 Server
|
|
19
|
-
startServerForeground(port).catch((error) => {
|
|
20
|
-
console.error('守护进程启动失败:', error)
|
|
21
|
-
process.exit(1)
|
|
22
|
-
})
|
package/src/server/daemon.ts
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 守护进程管理
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { spawn, ChildProcess } from 'node:child_process'
|
|
6
|
-
import { fileURLToPath } from 'node:url'
|
|
7
|
-
import { dirname, join } from 'node:path'
|
|
8
|
-
import {
|
|
9
|
-
readServerInfo,
|
|
10
|
-
writeServerInfo,
|
|
11
|
-
deleteServerInfo,
|
|
12
|
-
isProcessRunning,
|
|
13
|
-
killProcess,
|
|
14
|
-
ensureConfigDir,
|
|
15
|
-
getCurrentISOTime,
|
|
16
|
-
formatDuration,
|
|
17
|
-
} from '../shared/utils.js'
|
|
18
|
-
import { SERVER_START_TIMEOUT, DEFAULT_PORT } from '../shared/constants.js'
|
|
19
|
-
import { ErrorCode, MGError } from '../shared/errors.js'
|
|
20
|
-
import type { ServerInfo } from '../shared/types.js'
|
|
21
|
-
import { createServer } from './websocket-server.js'
|
|
22
|
-
import { createLogger, LogLevel } from './logger.js'
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* 检查 Server 是否在运行
|
|
26
|
-
*/
|
|
27
|
-
export function isServerRunning(): { running: boolean; info: ServerInfo | null } {
|
|
28
|
-
const info = readServerInfo()
|
|
29
|
-
|
|
30
|
-
if (!info) {
|
|
31
|
-
return { running: false, info: null }
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// 检查进程是否存在
|
|
35
|
-
if (!isProcessRunning(info.pid)) {
|
|
36
|
-
// 进程不存在,清理旧文件
|
|
37
|
-
deleteServerInfo()
|
|
38
|
-
return { running: false, info: null }
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return { running: true, info }
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* 启动 Server(前台模式)
|
|
46
|
-
*/
|
|
47
|
-
export async function startServerForeground(port?: number): Promise<void> {
|
|
48
|
-
const { running, info } = isServerRunning()
|
|
49
|
-
|
|
50
|
-
if (running && info) {
|
|
51
|
-
throw new MGError(
|
|
52
|
-
ErrorCode.SERVER_ALREADY_RUNNING,
|
|
53
|
-
`Server 已在运行中 (PID: ${info.pid}, 端口: ${info.port})`
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
ensureConfigDir()
|
|
58
|
-
|
|
59
|
-
const logger = createLogger({
|
|
60
|
-
console: true,
|
|
61
|
-
file: true,
|
|
62
|
-
minLevel: LogLevel.INFO,
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
const server = createServer({
|
|
66
|
-
port: port || DEFAULT_PORT,
|
|
67
|
-
logger,
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
// 注册信号处理
|
|
71
|
-
const cleanup = async () => {
|
|
72
|
-
console.log('\n正在停止 Server...')
|
|
73
|
-
await server.stop()
|
|
74
|
-
deleteServerInfo()
|
|
75
|
-
process.exit(0)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
process.on('SIGINT', cleanup)
|
|
79
|
-
process.on('SIGTERM', cleanup)
|
|
80
|
-
|
|
81
|
-
try {
|
|
82
|
-
const actualPort = await server.start()
|
|
83
|
-
|
|
84
|
-
// 写入 Server 信息
|
|
85
|
-
writeServerInfo({
|
|
86
|
-
port: actualPort,
|
|
87
|
-
pid: process.pid,
|
|
88
|
-
startedAt: getCurrentISOTime(),
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
console.log(`\nMG Server 启动成功`)
|
|
92
|
-
console.log(`监听端口: ${actualPort}`)
|
|
93
|
-
console.log(`进程 PID: ${process.pid}`)
|
|
94
|
-
console.log(`运行模式: 前台`)
|
|
95
|
-
console.log(`\n按 Ctrl+C 停止...`)
|
|
96
|
-
} catch (error) {
|
|
97
|
-
logger.error('Server 启动失败:', error)
|
|
98
|
-
throw error
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* 启动 Server(守护进程模式)
|
|
104
|
-
*/
|
|
105
|
-
export async function startServerDaemon(port?: number): Promise<ServerInfo> {
|
|
106
|
-
const { running, info } = isServerRunning()
|
|
107
|
-
|
|
108
|
-
if (running && info) {
|
|
109
|
-
throw new MGError(
|
|
110
|
-
ErrorCode.SERVER_ALREADY_RUNNING,
|
|
111
|
-
`Server 已在运行中 (PID: ${info.pid}, 端口: ${info.port})`
|
|
112
|
-
)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
ensureConfigDir()
|
|
116
|
-
|
|
117
|
-
// 获取当前模块的路径
|
|
118
|
-
const currentFile = fileURLToPath(import.meta.url)
|
|
119
|
-
const currentDir = dirname(currentFile)
|
|
120
|
-
const serverScript = join(currentDir, 'daemon-runner.js')
|
|
121
|
-
|
|
122
|
-
// 启动子进程
|
|
123
|
-
const args = ['--foreground']
|
|
124
|
-
if (port) {
|
|
125
|
-
args.push('--port', String(port))
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const child: ChildProcess = spawn(process.execPath, [serverScript, ...args], {
|
|
129
|
-
detached: true,
|
|
130
|
-
stdio: 'ignore',
|
|
131
|
-
env: {
|
|
132
|
-
...process.env,
|
|
133
|
-
MG_DAEMON: '1',
|
|
134
|
-
},
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
child.unref()
|
|
138
|
-
|
|
139
|
-
// 等待 Server 启动
|
|
140
|
-
const startTime = Date.now()
|
|
141
|
-
while (Date.now() - startTime < SERVER_START_TIMEOUT) {
|
|
142
|
-
await new Promise((resolve) => setTimeout(resolve, 200))
|
|
143
|
-
|
|
144
|
-
const { running, info } = isServerRunning()
|
|
145
|
-
if (running && info) {
|
|
146
|
-
return info
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
throw new MGError(ErrorCode.SERVER_START_FAILED, 'Server 启动超时')
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* 停止 Server
|
|
155
|
-
*/
|
|
156
|
-
export function stopServer(): { stopped: boolean; info: ServerInfo | null } {
|
|
157
|
-
const { running, info } = isServerRunning()
|
|
158
|
-
|
|
159
|
-
if (!running || !info) {
|
|
160
|
-
return { stopped: false, info: null }
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// 终止进程
|
|
164
|
-
const killed = killProcess(info.pid)
|
|
165
|
-
|
|
166
|
-
if (killed) {
|
|
167
|
-
deleteServerInfo()
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return { stopped: killed, info }
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* 重启 Server
|
|
175
|
-
*/
|
|
176
|
-
export async function restartServer(port?: number): Promise<ServerInfo> {
|
|
177
|
-
const { info: oldInfo } = stopServer()
|
|
178
|
-
|
|
179
|
-
// 等待旧进程完全停止
|
|
180
|
-
await new Promise((resolve) => setTimeout(resolve, 500))
|
|
181
|
-
|
|
182
|
-
// 启动新 Server
|
|
183
|
-
return startServerDaemon(port || oldInfo?.port)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* 获取 Server 状态
|
|
188
|
-
*/
|
|
189
|
-
export function getServerStatus(): {
|
|
190
|
-
running: boolean
|
|
191
|
-
port?: number
|
|
192
|
-
pid?: number
|
|
193
|
-
startedAt?: string
|
|
194
|
-
uptime?: string
|
|
195
|
-
} {
|
|
196
|
-
const { running, info } = isServerRunning()
|
|
197
|
-
|
|
198
|
-
if (!running || !info) {
|
|
199
|
-
return { running: false }
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const uptimeMs = Date.now() - new Date(info.startedAt).getTime()
|
|
203
|
-
|
|
204
|
-
return {
|
|
205
|
-
running: true,
|
|
206
|
-
port: info.port,
|
|
207
|
-
pid: info.pid,
|
|
208
|
-
startedAt: info.startedAt,
|
|
209
|
-
uptime: formatDuration(uptimeMs),
|
|
210
|
-
}
|
|
211
|
-
}
|
package/src/server/index.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Server 模块导出
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export { MGServer, createServer, type ServerOptions } from './websocket-server.js'
|
|
6
|
-
export { ConnectionManager, type ManagedWebSocket } from './connection-manager.js'
|
|
7
|
-
export { RequestHandler } from './request-handler.js'
|
|
8
|
-
export { Logger, createLogger, LogLevel, type LoggerOptions } from './logger.js'
|