@feng3d/cts 0.0.6
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/README.md +150 -0
- package/dist/boot.d.ts +41 -0
- package/dist/boot.d.ts.map +1 -0
- package/dist/boot.js +204 -0
- package/dist/boot.js.map +1 -0
- package/dist/cli.d.ts +10 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +377 -0
- package/dist/cli.js.map +1 -0
- package/dist/handlers/control-handler.d.ts +158 -0
- package/dist/handlers/control-handler.d.ts.map +1 -0
- package/dist/handlers/control-handler.js +378 -0
- package/dist/handlers/control-handler.js.map +1 -0
- package/dist/handlers/unified-proxy.d.ts +207 -0
- package/dist/handlers/unified-proxy.d.ts.map +1 -0
- package/dist/handlers/unified-proxy.js +475 -0
- package/dist/handlers/unified-proxy.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +115 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +433 -0
- package/dist/server.js.map +1 -0
- package/dist/session-manager.d.ts +218 -0
- package/dist/session-manager.d.ts.map +1 -0
- package/dist/session-manager.js +372 -0
- package/dist/session-manager.js.map +1 -0
- package/package.json +41 -0
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module server
|
|
3
|
+
* @description 穿透服务端核心模块,提供内网穿透转发服务器的主体实现。
|
|
4
|
+
* 负责创建 HTTP/HTTPS 服务器、WebSocket 控制通道,并协调会话管理、HTTP 代理和 WebSocket 代理等子模块。
|
|
5
|
+
*/
|
|
6
|
+
import { ServerConfig } from '@feng3d/chuantou-shared';
|
|
7
|
+
import { SessionManager } from './session-manager.js';
|
|
8
|
+
/**
|
|
9
|
+
* 服务器状态信息接口
|
|
10
|
+
*
|
|
11
|
+
* 描述当前转发服务器的运行状态,包括运行情况、网络配置、连接统计等信息。
|
|
12
|
+
*/
|
|
13
|
+
export interface ServerStatus {
|
|
14
|
+
/** 服务器是否正在运行 */
|
|
15
|
+
running: boolean;
|
|
16
|
+
/** 服务器监听的主机地址 */
|
|
17
|
+
host: string;
|
|
18
|
+
/** 控制通道端口号 */
|
|
19
|
+
controlPort: number;
|
|
20
|
+
/** 是否启用了 TLS 加密 */
|
|
21
|
+
tls: boolean;
|
|
22
|
+
/** 服务器运行时长(毫秒) */
|
|
23
|
+
uptime: number;
|
|
24
|
+
/** 已认证的客户端数量 */
|
|
25
|
+
authenticatedClients: number;
|
|
26
|
+
/** 已注册的端口总数 */
|
|
27
|
+
totalPorts: number;
|
|
28
|
+
/** 当前活跃连接数 */
|
|
29
|
+
activeConnections: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 转发服务器
|
|
33
|
+
*
|
|
34
|
+
* 穿透系统的服务端核心类,负责:
|
|
35
|
+
* - 创建并管理 HTTP/HTTPS 服务器
|
|
36
|
+
* - 处理 WebSocket 控制通道连接
|
|
37
|
+
* - 协调会话管理、HTTP 代理和 WebSocket 代理
|
|
38
|
+
* - 提供服务器状态查询和管理端点
|
|
39
|
+
*/
|
|
40
|
+
export declare class ForwardServer {
|
|
41
|
+
/** 服务器配置 */
|
|
42
|
+
private config;
|
|
43
|
+
/** 会话管理器实例 */
|
|
44
|
+
private sessionManager;
|
|
45
|
+
/** 统一代理处理器(同时支持 HTTP 和 WebSocket) */
|
|
46
|
+
private proxyHandler;
|
|
47
|
+
/** 控制通道处理器 */
|
|
48
|
+
private controlHandler;
|
|
49
|
+
/** WebSocket 控制服务器 */
|
|
50
|
+
private controlServer;
|
|
51
|
+
/** HTTP/HTTPS 服务器实例 */
|
|
52
|
+
private httpServer?;
|
|
53
|
+
/** 统计信息定时器 */
|
|
54
|
+
private statsInterval?;
|
|
55
|
+
/** 服务器启动时间戳 */
|
|
56
|
+
private startedAt?;
|
|
57
|
+
/**
|
|
58
|
+
* 创建转发服务器实例
|
|
59
|
+
*
|
|
60
|
+
* @param options - 服务器配置选项,未提供的字段将使用默认值
|
|
61
|
+
*/
|
|
62
|
+
constructor(options?: Partial<ServerConfig>);
|
|
63
|
+
/**
|
|
64
|
+
* 启动服务器
|
|
65
|
+
*
|
|
66
|
+
* 创建 HTTP 或 HTTPS 服务器,绑定请求处理和 WebSocket 升级事件,
|
|
67
|
+
* 开始监听控制端口,并启动定时统计输出。
|
|
68
|
+
*
|
|
69
|
+
* @returns 服务器启动完成的 Promise
|
|
70
|
+
*/
|
|
71
|
+
start(): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* 处理 HTTP 请求(包含管理端点)
|
|
74
|
+
*
|
|
75
|
+
* 提供以下管理端点:
|
|
76
|
+
* - `GET /` — 返回状态监控页面(HTML)
|
|
77
|
+
* - `GET /_chuantou/status` — 返回服务器状态信息(JSON)
|
|
78
|
+
* - `GET /_chuantou/sessions` — 返回会话列表(JSON)
|
|
79
|
+
* - `POST /_chuantou/stop` — 停止服务器(JSON)
|
|
80
|
+
*
|
|
81
|
+
* @param req - HTTP 请求对象
|
|
82
|
+
* @param res - HTTP 响应对象
|
|
83
|
+
*/
|
|
84
|
+
private handleHttpRequest;
|
|
85
|
+
/**
|
|
86
|
+
* 停止服务器
|
|
87
|
+
*
|
|
88
|
+
* 依次停止统计定时器、WebSocket 控制服务器、HTTP 服务器,
|
|
89
|
+
* 以及所有 HTTP 和 WebSocket 代理,最后清理所有会话。
|
|
90
|
+
*
|
|
91
|
+
* @returns 服务器完全停止后的 Promise
|
|
92
|
+
*/
|
|
93
|
+
stop(): Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* 获取服务器状态
|
|
96
|
+
*
|
|
97
|
+
* 汇总当前服务器的运行状态、网络配置和连接统计等信息。
|
|
98
|
+
*
|
|
99
|
+
* @returns 包含服务器运行状态的 {@link ServerStatus} 对象
|
|
100
|
+
*/
|
|
101
|
+
getStatus(): ServerStatus;
|
|
102
|
+
/**
|
|
103
|
+
* 获取服务器配置
|
|
104
|
+
*
|
|
105
|
+
* @returns 当前服务器使用的 {@link ServerConfig} 配置对象
|
|
106
|
+
*/
|
|
107
|
+
getConfig(): ServerConfig;
|
|
108
|
+
/**
|
|
109
|
+
* 获取会话管理器
|
|
110
|
+
*
|
|
111
|
+
* @returns 当前服务器使用的 {@link SessionManager} 会话管理器实例
|
|
112
|
+
*/
|
|
113
|
+
getSessionManager(): SessionManager;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,YAAY,EAA0B,MAAM,yBAAyB,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAgQtD;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,gBAAgB;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB;IACnB,GAAG,EAAE,OAAO,CAAC;IACb,kBAAkB;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB;IAChB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,eAAe;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc;IACd,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,qBAAa,aAAa;IACxB,YAAY;IACZ,OAAO,CAAC,MAAM,CAAe;IAC7B,cAAc;IACd,OAAO,CAAC,cAAc,CAAiB;IACvC,qCAAqC;IACrC,OAAO,CAAC,YAAY,CAAsB;IAC1C,cAAc;IACd,OAAO,CAAC,cAAc,CAAiB;IACvC,sBAAsB;IACtB,OAAO,CAAC,aAAa,CAAkB;IACvC,uBAAuB;IACvB,OAAO,CAAC,UAAU,CAAC,CAA6E;IAChG,cAAc;IACd,OAAO,CAAC,aAAa,CAAC,CAAiC;IACvD,eAAe;IACf,OAAO,CAAC,SAAS,CAAC,CAAS;IAE3B;;;;OAIG;gBACS,OAAO,GAAE,OAAO,CAAC,YAAY,CAAM;IAsB/C;;;;;;;OAOG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqC5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,iBAAiB;IAsCzB;;;;;;;OAOG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB3B;;;;;;OAMG;IACH,SAAS,IAAI,YAAY;IAczB;;;;OAIG;IACH,SAAS,IAAI,YAAY;IAIzB;;;;OAIG;IACH,iBAAiB,IAAI,cAAc;CAGpC"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module server
|
|
3
|
+
* @description 穿透服务端核心模块,提供内网穿透转发服务器的主体实现。
|
|
4
|
+
* 负责创建 HTTP/HTTPS 服务器、WebSocket 控制通道,并协调会话管理、HTTP 代理和 WebSocket 代理等子模块。
|
|
5
|
+
*/
|
|
6
|
+
import { WebSocketServer } from 'ws';
|
|
7
|
+
import { createServer as createHttpServer } from 'http';
|
|
8
|
+
import { createServer as createHttpsServer } from 'https';
|
|
9
|
+
import { DEFAULT_CONFIG, logger } from '@feng3d/chuantou-shared';
|
|
10
|
+
import { SessionManager } from './session-manager.js';
|
|
11
|
+
import { ControlHandler } from './handlers/control-handler.js';
|
|
12
|
+
import { UnifiedProxyHandler } from './handlers/unified-proxy.js';
|
|
13
|
+
/** 状态页面 HTML 模板 */
|
|
14
|
+
const STATUS_HTML = `<!DOCTYPE html>
|
|
15
|
+
<html lang="zh-CN">
|
|
16
|
+
<head>
|
|
17
|
+
<meta charset="UTF-8">
|
|
18
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
19
|
+
<title>穿透服务器状态</title>
|
|
20
|
+
<style>
|
|
21
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
22
|
+
body {
|
|
23
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
24
|
+
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
|
|
25
|
+
min-height: 100vh;
|
|
26
|
+
color: #e0e0e0;
|
|
27
|
+
padding: 20px;
|
|
28
|
+
}
|
|
29
|
+
.container {
|
|
30
|
+
max-width: 800px;
|
|
31
|
+
margin: 0 auto;
|
|
32
|
+
}
|
|
33
|
+
.header {
|
|
34
|
+
text-align: center;
|
|
35
|
+
margin-bottom: 30px;
|
|
36
|
+
padding: 30px 20px;
|
|
37
|
+
background: rgba(255,255,255,0.05);
|
|
38
|
+
border-radius: 16px;
|
|
39
|
+
backdrop-filter: blur(10px);
|
|
40
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
41
|
+
}
|
|
42
|
+
.header h1 {
|
|
43
|
+
font-size: 28px;
|
|
44
|
+
margin-bottom: 8px;
|
|
45
|
+
background: linear-gradient(90deg, #00d9ff, #00ff88);
|
|
46
|
+
-webkit-background-clip: text;
|
|
47
|
+
-webkit-text-fill-color: transparent;
|
|
48
|
+
}
|
|
49
|
+
.header .status {
|
|
50
|
+
display: inline-flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
gap: 8px;
|
|
53
|
+
padding: 6px 16px;
|
|
54
|
+
border-radius: 20px;
|
|
55
|
+
font-size: 14px;
|
|
56
|
+
font-weight: 500;
|
|
57
|
+
}
|
|
58
|
+
.status.running {
|
|
59
|
+
background: rgba(0, 255, 136, 0.15);
|
|
60
|
+
color: #00ff88;
|
|
61
|
+
}
|
|
62
|
+
.status.running::before {
|
|
63
|
+
content: "";
|
|
64
|
+
width: 8px;
|
|
65
|
+
height: 8px;
|
|
66
|
+
border-radius: 50%;
|
|
67
|
+
background: #00ff88;
|
|
68
|
+
animation: pulse 1.5s infinite;
|
|
69
|
+
}
|
|
70
|
+
.status.stopped {
|
|
71
|
+
background: rgba(255, 77, 77, 0.15);
|
|
72
|
+
color: #ff4d4d;
|
|
73
|
+
}
|
|
74
|
+
@keyframes pulse {
|
|
75
|
+
0%, 100% { opacity: 1; }
|
|
76
|
+
50% { opacity: 0.4; }
|
|
77
|
+
}
|
|
78
|
+
.grid {
|
|
79
|
+
display: grid;
|
|
80
|
+
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
|
81
|
+
gap: 16px;
|
|
82
|
+
margin-bottom: 20px;
|
|
83
|
+
}
|
|
84
|
+
.card {
|
|
85
|
+
background: rgba(255,255,255,0.05);
|
|
86
|
+
border-radius: 12px;
|
|
87
|
+
padding: 20px;
|
|
88
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
89
|
+
backdrop-filter: blur(10px);
|
|
90
|
+
}
|
|
91
|
+
.card-label {
|
|
92
|
+
font-size: 12px;
|
|
93
|
+
color: #888;
|
|
94
|
+
margin-bottom: 6px;
|
|
95
|
+
text-transform: uppercase;
|
|
96
|
+
letter-spacing: 0.5px;
|
|
97
|
+
}
|
|
98
|
+
.card-value {
|
|
99
|
+
font-size: 24px;
|
|
100
|
+
font-weight: 600;
|
|
101
|
+
color: #fff;
|
|
102
|
+
}
|
|
103
|
+
.card-value .unit {
|
|
104
|
+
font-size: 14px;
|
|
105
|
+
color: #888;
|
|
106
|
+
font-weight: 400;
|
|
107
|
+
}
|
|
108
|
+
.sessions {
|
|
109
|
+
background: rgba(255,255,255,0.05);
|
|
110
|
+
border-radius: 12px;
|
|
111
|
+
padding: 20px;
|
|
112
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
113
|
+
margin-top: 20px;
|
|
114
|
+
}
|
|
115
|
+
.sessions-title {
|
|
116
|
+
font-size: 14px;
|
|
117
|
+
color: #888;
|
|
118
|
+
margin-bottom: 16px;
|
|
119
|
+
text-transform: uppercase;
|
|
120
|
+
letter-spacing: 0.5px;
|
|
121
|
+
}
|
|
122
|
+
.session-item {
|
|
123
|
+
display: flex;
|
|
124
|
+
justify-content: space-between;
|
|
125
|
+
align-items: center;
|
|
126
|
+
padding: 12px 16px;
|
|
127
|
+
background: rgba(0,0,0,0.2);
|
|
128
|
+
border-radius: 8px;
|
|
129
|
+
margin-bottom: 8px;
|
|
130
|
+
font-size: 14px;
|
|
131
|
+
}
|
|
132
|
+
.session-item:last-child {
|
|
133
|
+
margin-bottom: 0;
|
|
134
|
+
}
|
|
135
|
+
.session-id {
|
|
136
|
+
font-family: monospace;
|
|
137
|
+
color: #00d9ff;
|
|
138
|
+
}
|
|
139
|
+
.session-time {
|
|
140
|
+
color: #888;
|
|
141
|
+
}
|
|
142
|
+
.empty-state {
|
|
143
|
+
text-align: center;
|
|
144
|
+
padding: 30px;
|
|
145
|
+
color: #666;
|
|
146
|
+
font-size: 14px;
|
|
147
|
+
}
|
|
148
|
+
.footer {
|
|
149
|
+
text-align: center;
|
|
150
|
+
margin-top: 30px;
|
|
151
|
+
padding: 20px;
|
|
152
|
+
color: #666;
|
|
153
|
+
font-size: 12px;
|
|
154
|
+
}
|
|
155
|
+
.last-update {
|
|
156
|
+
text-align: center;
|
|
157
|
+
color: #666;
|
|
158
|
+
font-size: 12px;
|
|
159
|
+
margin-top: 10px;
|
|
160
|
+
}
|
|
161
|
+
</style>
|
|
162
|
+
</head>
|
|
163
|
+
<body>
|
|
164
|
+
<div class="container">
|
|
165
|
+
<div class="header">
|
|
166
|
+
<h1>🚀 feng3d-cts 穿透服务器</h1>
|
|
167
|
+
<div class="status running" id="status">运行中</div>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
<div class="grid">
|
|
171
|
+
<div class="card">
|
|
172
|
+
<div class="card-label">监听地址</div>
|
|
173
|
+
<div class="card-value" id="host">-</div>
|
|
174
|
+
</div>
|
|
175
|
+
<div class="card">
|
|
176
|
+
<div class="card-label">运行时长</div>
|
|
177
|
+
<div class="card-value"><span id="uptime">-</span><span class="unit"> 秒</span></div>
|
|
178
|
+
</div>
|
|
179
|
+
<div class="card">
|
|
180
|
+
<div class="card-label">客户端</div>
|
|
181
|
+
<div class="card-value"><span id="clients">0</span><span class="unit"> 个</span></div>
|
|
182
|
+
</div>
|
|
183
|
+
<div class="card">
|
|
184
|
+
<div class="card-label">端口</div>
|
|
185
|
+
<div class="card-value"><span id="ports">0</span><span class="unit"> 个</span></div>
|
|
186
|
+
</div>
|
|
187
|
+
<div class="card">
|
|
188
|
+
<div class="card-label">连接数</div>
|
|
189
|
+
<div class="card-value"><span id="connections">0</span><span class="unit"> 个</span></div>
|
|
190
|
+
</div>
|
|
191
|
+
<div class="card">
|
|
192
|
+
<div class="card-label">TLS</div>
|
|
193
|
+
<div class="card-value" id="tls">-</div>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
<div class="sessions">
|
|
198
|
+
<div class="sessions-title">客户端会话</div>
|
|
199
|
+
<div id="sessions-list"></div>
|
|
200
|
+
</div>
|
|
201
|
+
|
|
202
|
+
<div class="last-update">最后更新: <span id="lastUpdate">-</span></div>
|
|
203
|
+
|
|
204
|
+
<div class="footer">
|
|
205
|
+
<a href="https://github.com/feng3d/chuantou" target="_blank" style="color: #00d9ff; text-decoration: none;">feng3d-cts</a>
|
|
206
|
+
— 内网穿透服务端
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
|
|
210
|
+
<script>
|
|
211
|
+
function formatUptime(ms) {
|
|
212
|
+
const seconds = Math.floor(ms / 1000);
|
|
213
|
+
const minutes = Math.floor(seconds / 60);
|
|
214
|
+
const hours = Math.floor(minutes / 60);
|
|
215
|
+
const days = Math.floor(hours / 24);
|
|
216
|
+
if (days > 0) return \`\${days}天 \${hours % 24}小时\`;
|
|
217
|
+
if (hours > 0) return \`\${hours}小时 \${minutes % 60}分钟\`;
|
|
218
|
+
if (minutes > 0) return \`\${minutes}分钟 \${seconds % 60}秒\`;
|
|
219
|
+
return \`\${seconds}秒\`;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function formatTime(timestamp) {
|
|
223
|
+
return new Date(timestamp).toLocaleTimeString('zh-CN');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async function updateStatus() {
|
|
227
|
+
try {
|
|
228
|
+
const res = await fetch('/_chuantou/status');
|
|
229
|
+
const data = await res.json();
|
|
230
|
+
|
|
231
|
+
document.getElementById('host').textContent = data.host + ':' + data.controlPort;
|
|
232
|
+
document.getElementById('uptime').textContent = formatUptime(data.uptime);
|
|
233
|
+
document.getElementById('clients').textContent = data.authenticatedClients;
|
|
234
|
+
document.getElementById('ports').textContent = data.totalPorts;
|
|
235
|
+
document.getElementById('connections').textContent = data.activeConnections;
|
|
236
|
+
document.getElementById('tls').textContent = data.tls ? '已启用' : '已禁用';
|
|
237
|
+
document.getElementById('lastUpdate').textContent = new Date().toLocaleTimeString('zh-CN');
|
|
238
|
+
|
|
239
|
+
// 获取会话列表
|
|
240
|
+
const sessionsRes = await fetch('/_chuantou/sessions');
|
|
241
|
+
const sessions = await sessionsRes.json();
|
|
242
|
+
const listEl = document.getElementById('sessions-list');
|
|
243
|
+
if (sessions.length === 0) {
|
|
244
|
+
listEl.innerHTML = '<div class="empty-state">暂无客户端连接</div>';
|
|
245
|
+
} else {
|
|
246
|
+
listEl.innerHTML = sessions.map(s => \`
|
|
247
|
+
<div class="session-item">
|
|
248
|
+
<span class="session-id">\${s.clientId.slice(0, 8)}...</span>
|
|
249
|
+
<span class="session-time">连接于 \${formatTime(s.connectedAt)}</span>
|
|
250
|
+
</div>
|
|
251
|
+
\`).join('');
|
|
252
|
+
}
|
|
253
|
+
} catch (e) {
|
|
254
|
+
logger.error('获取状态失败:', e);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
updateStatus();
|
|
259
|
+
setInterval(updateStatus, 3000);
|
|
260
|
+
</script>
|
|
261
|
+
</body>
|
|
262
|
+
</html>
|
|
263
|
+
`;
|
|
264
|
+
/**
|
|
265
|
+
* 转发服务器
|
|
266
|
+
*
|
|
267
|
+
* 穿透系统的服务端核心类,负责:
|
|
268
|
+
* - 创建并管理 HTTP/HTTPS 服务器
|
|
269
|
+
* - 处理 WebSocket 控制通道连接
|
|
270
|
+
* - 协调会话管理、HTTP 代理和 WebSocket 代理
|
|
271
|
+
* - 提供服务器状态查询和管理端点
|
|
272
|
+
*/
|
|
273
|
+
export class ForwardServer {
|
|
274
|
+
/**
|
|
275
|
+
* 创建转发服务器实例
|
|
276
|
+
*
|
|
277
|
+
* @param options - 服务器配置选项,未提供的字段将使用默认值
|
|
278
|
+
*/
|
|
279
|
+
constructor(options = {}) {
|
|
280
|
+
this.config = {
|
|
281
|
+
host: options.host ?? '0.0.0.0',
|
|
282
|
+
controlPort: options.controlPort ?? DEFAULT_CONFIG.CONTROL_PORT,
|
|
283
|
+
authTokens: options.authTokens ?? [],
|
|
284
|
+
heartbeatInterval: options.heartbeatInterval ?? DEFAULT_CONFIG.HEARTBEAT_INTERVAL,
|
|
285
|
+
sessionTimeout: options.sessionTimeout ?? DEFAULT_CONFIG.SESSION_TIMEOUT,
|
|
286
|
+
tls: options.tls,
|
|
287
|
+
};
|
|
288
|
+
this.sessionManager = new SessionManager(this.config.heartbeatInterval, this.config.sessionTimeout);
|
|
289
|
+
this.proxyHandler = new UnifiedProxyHandler(this.sessionManager);
|
|
290
|
+
this.controlHandler = new ControlHandler(this.sessionManager, this.config, this.proxyHandler);
|
|
291
|
+
this.controlServer = new WebSocketServer({ noServer: true });
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* 启动服务器
|
|
295
|
+
*
|
|
296
|
+
* 创建 HTTP 或 HTTPS 服务器,绑定请求处理和 WebSocket 升级事件,
|
|
297
|
+
* 开始监听控制端口,并启动定时统计输出。
|
|
298
|
+
*
|
|
299
|
+
* @returns 服务器启动完成的 Promise
|
|
300
|
+
*/
|
|
301
|
+
async start() {
|
|
302
|
+
const serverOptions = this.config.tls ? {
|
|
303
|
+
key: this.config.tls.key,
|
|
304
|
+
cert: this.config.tls.cert,
|
|
305
|
+
} : undefined;
|
|
306
|
+
this.httpServer = serverOptions
|
|
307
|
+
? createHttpsServer(serverOptions)
|
|
308
|
+
: createHttpServer();
|
|
309
|
+
this.httpServer.on('request', (req, res) => {
|
|
310
|
+
this.handleHttpRequest(req, res);
|
|
311
|
+
});
|
|
312
|
+
this.httpServer.on('upgrade', (req, socket, head) => {
|
|
313
|
+
this.controlServer.handleUpgrade(req, socket, head, (ws) => {
|
|
314
|
+
this.controlHandler.handleConnection(ws);
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
this.httpServer.on('error', (error) => {
|
|
318
|
+
logger.error('服务器错误:', error);
|
|
319
|
+
});
|
|
320
|
+
this.httpServer.listen(this.config.controlPort, this.config.host, () => {
|
|
321
|
+
const protocol = this.config.tls ? 'https/wss' : 'http/ws';
|
|
322
|
+
logger.log(`控制服务器正在监听 ${protocol}://${this.config.host}:${this.config.controlPort}`);
|
|
323
|
+
});
|
|
324
|
+
this.startedAt = Date.now();
|
|
325
|
+
this.statsInterval = setInterval(() => {
|
|
326
|
+
const stats = this.sessionManager.getStats();
|
|
327
|
+
logger.log(`统计: ${stats.authenticatedClients} 个已认证客户端, ${stats.totalPorts} 个端口, ${stats.totalConnections} 个连接`);
|
|
328
|
+
}, 60000);
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* 处理 HTTP 请求(包含管理端点)
|
|
332
|
+
*
|
|
333
|
+
* 提供以下管理端点:
|
|
334
|
+
* - `GET /` — 返回状态监控页面(HTML)
|
|
335
|
+
* - `GET /_chuantou/status` — 返回服务器状态信息(JSON)
|
|
336
|
+
* - `GET /_chuantou/sessions` — 返回会话列表(JSON)
|
|
337
|
+
* - `POST /_chuantou/stop` — 停止服务器(JSON)
|
|
338
|
+
*
|
|
339
|
+
* @param req - HTTP 请求对象
|
|
340
|
+
* @param res - HTTP 响应对象
|
|
341
|
+
*/
|
|
342
|
+
handleHttpRequest(req, res) {
|
|
343
|
+
const url = req.url ?? '/';
|
|
344
|
+
// 状态监控页面
|
|
345
|
+
if (url === '/' && req.method === 'GET') {
|
|
346
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
347
|
+
res.end(STATUS_HTML);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
// 状态 API
|
|
351
|
+
if (url === '/_chuantou/status' && req.method === 'GET') {
|
|
352
|
+
const status = this.getStatus();
|
|
353
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
354
|
+
res.end(JSON.stringify(status));
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
// 会话列表 API
|
|
358
|
+
if (url === '/_chuantou/sessions' && req.method === 'GET') {
|
|
359
|
+
const sessions = this.sessionManager.getSessions();
|
|
360
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
361
|
+
res.end(JSON.stringify(sessions));
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
// 停止服务器 API
|
|
365
|
+
if (url === '/_chuantou/stop' && req.method === 'POST') {
|
|
366
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
367
|
+
res.end(JSON.stringify({ message: '服务器正在停止' }));
|
|
368
|
+
this.stop();
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
res.writeHead(200);
|
|
372
|
+
res.end('穿透服务器正在运行');
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* 停止服务器
|
|
376
|
+
*
|
|
377
|
+
* 依次停止统计定时器、WebSocket 控制服务器、HTTP 服务器,
|
|
378
|
+
* 以及所有 HTTP 和 WebSocket 代理,最后清理所有会话。
|
|
379
|
+
*
|
|
380
|
+
* @returns 服务器完全停止后的 Promise
|
|
381
|
+
*/
|
|
382
|
+
async stop() {
|
|
383
|
+
logger.log('正在停止服务器...');
|
|
384
|
+
if (this.statsInterval) {
|
|
385
|
+
clearInterval(this.statsInterval);
|
|
386
|
+
this.statsInterval = undefined;
|
|
387
|
+
}
|
|
388
|
+
this.controlServer.close();
|
|
389
|
+
if (this.httpServer) {
|
|
390
|
+
this.httpServer.close();
|
|
391
|
+
}
|
|
392
|
+
await this.proxyHandler.stopAll();
|
|
393
|
+
this.sessionManager.clear();
|
|
394
|
+
logger.log('服务器已停止');
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* 获取服务器状态
|
|
398
|
+
*
|
|
399
|
+
* 汇总当前服务器的运行状态、网络配置和连接统计等信息。
|
|
400
|
+
*
|
|
401
|
+
* @returns 包含服务器运行状态的 {@link ServerStatus} 对象
|
|
402
|
+
*/
|
|
403
|
+
getStatus() {
|
|
404
|
+
const stats = this.sessionManager.getStats();
|
|
405
|
+
return {
|
|
406
|
+
running: this.httpServer?.listening ?? false,
|
|
407
|
+
host: this.config.host,
|
|
408
|
+
controlPort: this.config.controlPort,
|
|
409
|
+
tls: this.config.tls !== undefined,
|
|
410
|
+
uptime: this.startedAt ? Date.now() - this.startedAt : 0,
|
|
411
|
+
authenticatedClients: stats.authenticatedClients,
|
|
412
|
+
totalPorts: stats.totalPorts,
|
|
413
|
+
activeConnections: stats.totalConnections,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* 获取服务器配置
|
|
418
|
+
*
|
|
419
|
+
* @returns 当前服务器使用的 {@link ServerConfig} 配置对象
|
|
420
|
+
*/
|
|
421
|
+
getConfig() {
|
|
422
|
+
return this.config;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* 获取会话管理器
|
|
426
|
+
*
|
|
427
|
+
* @returns 当前服务器使用的 {@link SessionManager} 会话管理器实例
|
|
428
|
+
*/
|
|
429
|
+
getSessionManager() {
|
|
430
|
+
return this.sessionManager;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|