protocol-proxy 1.0.0

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/server.js ADDED
@@ -0,0 +1,202 @@
1
+ const express = require('express');
2
+ const path = require('path');
3
+ const cors = require('cors');
4
+ const { exec } = require('child_process');
5
+ const os = require('os');
6
+ const configStore = require('./lib/config-store');
7
+ const proxyManager = require('./lib/proxy-manager');
8
+
9
+ const app = express();
10
+ const PORT = process.env.ADMIN_PORT || 3000;
11
+
12
+ function openBrowser(url) {
13
+ const platform = os.platform();
14
+ let command;
15
+ if (platform === 'win32') {
16
+ command = `start "" "${url}"`;
17
+ } else if (platform === 'darwin') {
18
+ command = `open "${url}"`;
19
+ } else {
20
+ command = `xdg-open "${url}"`;
21
+ }
22
+ exec(command, (err) => {
23
+ if (err) console.error('[Browser] 打开浏览器失败:', err.message);
24
+ });
25
+ }
26
+
27
+ app.use(cors());
28
+ app.use(express.json());
29
+ app.use(express.static(path.join(__dirname, 'public')));
30
+
31
+ // ==================== 管理 API ====================
32
+
33
+ // 获取所有代理配置
34
+ app.get('/api/proxies', (req, res) => {
35
+ const proxies = configStore.getProxies().map(p => ({
36
+ ...p,
37
+ target: p.target ? {
38
+ ...p.target,
39
+ apiKey: p.target.apiKey ? '***' : '',
40
+ } : null,
41
+ running: proxyManager.isRunning(p.id),
42
+ }));
43
+ res.json(proxies);
44
+ });
45
+
46
+ // 获取单个代理配置(含敏感信息)
47
+ app.get('/api/proxies/:id', (req, res) => {
48
+ const proxy = configStore.getProxyById(req.params.id);
49
+ if (!proxy) return res.status(404).json({ error: 'Proxy not found' });
50
+ res.json(proxy);
51
+ });
52
+
53
+ // 创建代理
54
+ app.post('/api/proxies', async (req, res) => {
55
+ const { name, port, requireAuth, authToken, target } = req.body;
56
+
57
+ if (!name || !port || !target) {
58
+ return res.status(400).json({ error: 'name, port and target are required' });
59
+ }
60
+
61
+ const parsedPort = parseInt(port);
62
+
63
+ // 端口冲突校验
64
+ const existing = configStore.getProxies().find(p => p.port === parsedPort);
65
+ if (existing) {
66
+ return res.status(409).json({
67
+ error: `端口 ${parsedPort} 已被代理「${existing.name}」占用,请更换端口`,
68
+ });
69
+ }
70
+
71
+ const proxy = configStore.addProxy({
72
+ name,
73
+ port: parsedPort,
74
+ requireAuth: !!requireAuth,
75
+ authToken: authToken || null,
76
+ target,
77
+ });
78
+
79
+ try {
80
+ await proxyManager.startProxy(proxy);
81
+ res.status(201).json({ ...proxy, running: true });
82
+ } catch (err) {
83
+ // 启动失败,回滚已保存的配置
84
+ configStore.removeProxy(proxy.id);
85
+ res.status(500).json({ error: `代理启动失败: ${err.message}` });
86
+ }
87
+ });
88
+
89
+ // 更新代理
90
+ app.put('/api/proxies/:id', async (req, res) => {
91
+ const { name, port, requireAuth, authToken, target } = req.body;
92
+ const existing = configStore.getProxyById(req.params.id);
93
+ if (!existing) return res.status(404).json({ error: 'Proxy not found' });
94
+
95
+ const updates = {};
96
+ if (name !== undefined) updates.name = name;
97
+ if (port !== undefined) updates.port = parseInt(port);
98
+ if (requireAuth !== undefined) updates.requireAuth = !!requireAuth;
99
+ if (authToken !== undefined) updates.authToken = authToken || null;
100
+ if (target !== undefined) updates.target = target;
101
+
102
+ // 端口变更时校验冲突
103
+ const needRestart = updates.port !== undefined && updates.port !== existing.port;
104
+ if (needRestart) {
105
+ const conflict = configStore.getProxies().find(p => p.id !== req.params.id && p.port === updates.port);
106
+ if (conflict) {
107
+ return res.status(409).json({
108
+ error: `端口 ${updates.port} 已被代理「${conflict.name}」占用,请更换端口`,
109
+ });
110
+ }
111
+ }
112
+
113
+ const updated = configStore.updateProxy(req.params.id, updates);
114
+
115
+ if (needRestart) {
116
+ try {
117
+ await proxyManager.restartProxy(updated);
118
+ } catch (err) {
119
+ return res.status(500).json({ error: `代理重启失败: ${err.message}` });
120
+ }
121
+ } else {
122
+ proxyManager.updateProxyConfig(updated);
123
+ }
124
+
125
+ res.json({ ...updated, running: proxyManager.isRunning(updated.id) });
126
+ });
127
+
128
+ // 删除代理
129
+ app.delete('/api/proxies/:id', async (req, res) => {
130
+ const existing = configStore.getProxyById(req.params.id);
131
+ if (!existing) return res.status(404).json({ error: 'Proxy not found' });
132
+
133
+ await proxyManager.stopProxy(req.params.id);
134
+ configStore.removeProxy(req.params.id);
135
+ res.json({ success: true });
136
+ });
137
+
138
+ // 启动/停止代理
139
+ app.post('/api/proxies/:id/start', async (req, res) => {
140
+ const proxy = configStore.getProxyById(req.params.id);
141
+ if (!proxy) return res.status(404).json({ error: 'Proxy not found' });
142
+
143
+ try {
144
+ await proxyManager.startProxy(proxy);
145
+ res.json({ success: true, running: true });
146
+ } catch (err) {
147
+ res.status(500).json({ error: 'Failed to start proxy', message: err.message });
148
+ }
149
+ });
150
+
151
+ app.post('/api/proxies/:id/stop', async (req, res) => {
152
+ await proxyManager.stopProxy(req.params.id);
153
+ res.json({ success: true, running: false });
154
+ });
155
+
156
+ // 获取运行状态
157
+ app.get('/api/status', (req, res) => {
158
+ res.json({
159
+ running: proxyManager.getRunningPorts(),
160
+ total: configStore.getProxies().length,
161
+ });
162
+ });
163
+
164
+ // 前端首页
165
+ app.get('/', (req, res) => {
166
+ res.sendFile(path.join(__dirname, 'public', 'index.html'));
167
+ });
168
+
169
+ // ==================== 启动 ====================
170
+
171
+ async function init() {
172
+ // 启动所有已配置的代理
173
+ const proxies = configStore.getProxies();
174
+ for (const proxy of proxies) {
175
+ try {
176
+ await proxyManager.startProxy(proxy);
177
+ } catch (err) {
178
+ console.error(`[Init] Failed to start proxy ${proxy.name}:`, err.message);
179
+ }
180
+ }
181
+
182
+ app.listen(PORT, () => {
183
+ const adminUrl = `http://localhost:${PORT}`;
184
+ console.log(`[Admin] Management server running on ${adminUrl}`);
185
+ console.log(`[Admin] ${proxies.length} proxy config(s) loaded`);
186
+ openBrowser(adminUrl);
187
+ });
188
+ }
189
+
190
+ // 优雅关闭
191
+ process.on('SIGINT', async () => {
192
+ console.log('\nShutting down...');
193
+ await proxyManager.stopAll();
194
+ process.exit(0);
195
+ });
196
+
197
+ process.on('SIGTERM', async () => {
198
+ await proxyManager.stopAll();
199
+ process.exit(0);
200
+ });
201
+
202
+ init();