@jachy/multiport-proxy 0.0.1
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 +148 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +89 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +88 -0
- package/dist/index.js.map +1 -0
- package/dist/server/config-manager.d.ts +28 -0
- package/dist/server/config-manager.d.ts.map +1 -0
- package/dist/server/config-manager.js +90 -0
- package/dist/server/config-manager.js.map +1 -0
- package/dist/server/logger.d.ts +27 -0
- package/dist/server/logger.d.ts.map +1 -0
- package/dist/server/logger.js +47 -0
- package/dist/server/logger.js.map +1 -0
- package/dist/server/proxy-server.d.ts +15 -0
- package/dist/server/proxy-server.d.ts.map +1 -0
- package/dist/server/proxy-server.js +178 -0
- package/dist/server/proxy-server.js.map +1 -0
- package/dist/web/api-routes.d.ts +6 -0
- package/dist/web/api-routes.d.ts.map +1 -0
- package/dist/web/api-routes.js +112 -0
- package/dist/web/api-routes.js.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Multiport Proxy
|
|
2
|
+
|
|
3
|
+
一个功能强大的多端口代理服务,支持动态配置和实时日志查看。
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🚀 **Web 配置界面** - 启动时自动打开 Web UI,轻松配置代理规则
|
|
8
|
+
- 🔀 **多端口代理** - 支持配置多个本地端口到目标服务的映射
|
|
9
|
+
- ⚙️ **灵活配置** - 支持 CORS、超时、重试等可选配置
|
|
10
|
+
- 📊 **实时日志** - 在 Web 界面查看实时请求/响应日志,无需本地持久化
|
|
11
|
+
- 💾 **配置保存** - 配置自动保存,重启后自动加载
|
|
12
|
+
- 🎯 **零配置启动** - 开箱即用,无需复杂配置
|
|
13
|
+
|
|
14
|
+
## 快速开始
|
|
15
|
+
|
|
16
|
+
### 使用 npx(推荐)
|
|
17
|
+
|
|
18
|
+
无需安装,直接运行:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx @jachy/multiport-proxy
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 全局安装
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install -g @jachy/multiport-proxy
|
|
28
|
+
multiport-proxy
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 本地开发
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# 克隆项目
|
|
35
|
+
git clone <your-repo-url>
|
|
36
|
+
cd multiport-proxy
|
|
37
|
+
|
|
38
|
+
# 安装依赖
|
|
39
|
+
pnpm install
|
|
40
|
+
|
|
41
|
+
# 开发模式
|
|
42
|
+
pnpm run dev
|
|
43
|
+
|
|
44
|
+
# 构建
|
|
45
|
+
pnpm run build
|
|
46
|
+
|
|
47
|
+
# 运行构建后的版本
|
|
48
|
+
pnpm start
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## 项目架构
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
multiport-proxy/
|
|
55
|
+
├── src/
|
|
56
|
+
│ ├── server/
|
|
57
|
+
│ │ ├── proxy-server.ts # 代理服务核心逻辑
|
|
58
|
+
│ │ ├── config-manager.ts # 配置管理模块
|
|
59
|
+
│ │ └── logger.ts # 日志管理模块
|
|
60
|
+
│ ├── web/
|
|
61
|
+
│ │ ├── api-routes.ts # Web API 路由(配置/日志)
|
|
62
|
+
│ │ ├── ui/
|
|
63
|
+
│ │ │ ├── index.html # Web 配置界面
|
|
64
|
+
│ │ │ ├── style.css # 样式表
|
|
65
|
+
│ │ │ └── app.js # 前端逻辑
|
|
66
|
+
│ │ └── middleware.ts # Web 中间件
|
|
67
|
+
│ └── index.ts # 应用入口
|
|
68
|
+
├── data/
|
|
69
|
+
│ └── config.json # 配置持久化文件
|
|
70
|
+
├── package.json
|
|
71
|
+
└── tsconfig.json
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## 核心流程
|
|
75
|
+
|
|
76
|
+
1. **启动**:应用启动时加载配置,初始化代理服务器和 Web 服务器
|
|
77
|
+
2. **Web UI**:自动打开浏览器访问配置页面 (localhost:8888)
|
|
78
|
+
3. **配置**:用户通过 Web UI 添加/编辑/删除代理规则
|
|
79
|
+
4. **代理**:根据配置将请求转发到目标服务
|
|
80
|
+
5. **日志**:实时在 Web UI 显示请求日志,支持滚动查看
|
|
81
|
+
|
|
82
|
+
## 使用流程
|
|
83
|
+
|
|
84
|
+
### 启动项目
|
|
85
|
+
```bash
|
|
86
|
+
pnpm run dev
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 打开配置页面
|
|
90
|
+
自动打开 http://localhost:8888
|
|
91
|
+
|
|
92
|
+
### 配置代理规则
|
|
93
|
+
1. 输入本地监听端口
|
|
94
|
+
2. 输入目标服务地址(如 http://localhost:3000)
|
|
95
|
+
3. 可选配置 CORS、超时等
|
|
96
|
+
4. 点击"保存"
|
|
97
|
+
|
|
98
|
+
### 查看日志
|
|
99
|
+
- 实时显示所有代理请求
|
|
100
|
+
- 支持滚动查看历史日志
|
|
101
|
+
- 按端口/状态码筛选
|
|
102
|
+
|
|
103
|
+
## API 接口
|
|
104
|
+
|
|
105
|
+
### 获取配置
|
|
106
|
+
- `GET /api/config` - 获取所有代理规则
|
|
107
|
+
|
|
108
|
+
### 保存配置
|
|
109
|
+
- `POST /api/config` - 保存代理规则
|
|
110
|
+
|
|
111
|
+
### 获取日志
|
|
112
|
+
- `GET /api/logs` - 获取实时日志(支持分页/筛选)
|
|
113
|
+
|
|
114
|
+
### 清空日志
|
|
115
|
+
- `DELETE /api/logs` - 清空所有日志
|
|
116
|
+
|
|
117
|
+
## 配置文件格式
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"rules": [
|
|
122
|
+
{
|
|
123
|
+
"id": "rule-1",
|
|
124
|
+
"localPort": 3000,
|
|
125
|
+
"targetUrl": "http://api.example.com",
|
|
126
|
+
"cors": {
|
|
127
|
+
"enabled": true,
|
|
128
|
+
"origins": ["*"]
|
|
129
|
+
},
|
|
130
|
+
"timeout": 30000,
|
|
131
|
+
"retries": 0,
|
|
132
|
+
"enabled": true
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## 开发要求
|
|
139
|
+
|
|
140
|
+
- Node.js >= 16
|
|
141
|
+
- TypeScript
|
|
142
|
+
- Express.js (Web 服务器)
|
|
143
|
+
- http-proxy (代理库)
|
|
144
|
+
- React/Vue/Vanilla JS (前端)
|
|
145
|
+
|
|
146
|
+
## 许可证
|
|
147
|
+
|
|
148
|
+
ISC
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
|
+
};
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
const express_1 = __importDefault(require("express"));
|
|
41
|
+
const path_1 = __importDefault(require("path"));
|
|
42
|
+
const config_manager_1 = require("./server/config-manager");
|
|
43
|
+
const logger_1 = require("./server/logger");
|
|
44
|
+
const proxy_server_1 = require("./server/proxy-server");
|
|
45
|
+
const api_routes_1 = require("./web/api-routes");
|
|
46
|
+
const WEB_PORT = 8888;
|
|
47
|
+
async function main() {
|
|
48
|
+
console.log('🚀 Multiport Proxy Starting...\n');
|
|
49
|
+
// 初始化管理模块
|
|
50
|
+
const configManager = new config_manager_1.ConfigManager();
|
|
51
|
+
const logger = new logger_1.Logger();
|
|
52
|
+
const proxyServer = new proxy_server_1.ProxyServer(configManager, logger);
|
|
53
|
+
// 启动代理服务
|
|
54
|
+
proxyServer.startProxies();
|
|
55
|
+
// 创建 Web 服务器
|
|
56
|
+
const app = (0, express_1.default)();
|
|
57
|
+
app.use(express_1.default.json());
|
|
58
|
+
// 静态文件服务
|
|
59
|
+
const uiDir = path_1.default.join(__dirname, 'web', 'ui');
|
|
60
|
+
app.use(express_1.default.static(uiDir));
|
|
61
|
+
// API 路由
|
|
62
|
+
app.use('/api', (0, api_routes_1.createApiRouter)(configManager, logger, proxyServer));
|
|
63
|
+
// 根路径返回 HTML
|
|
64
|
+
app.get('/', (req, res) => {
|
|
65
|
+
res.sendFile(path_1.default.join(uiDir, 'index.html'));
|
|
66
|
+
});
|
|
67
|
+
// 启动 Web 服务器
|
|
68
|
+
app.listen(WEB_PORT, async () => {
|
|
69
|
+
console.log(`✓ Web UI running on http://localhost:${WEB_PORT}`);
|
|
70
|
+
console.log(`✓ Running ports: ${proxyServer.getRunningPorts().join(', ') || 'none'}\n`);
|
|
71
|
+
// 自动打开浏览器
|
|
72
|
+
try {
|
|
73
|
+
const open = (await Promise.resolve().then(() => __importStar(require('open')))).default;
|
|
74
|
+
await open(`http://localhost:${WEB_PORT}`);
|
|
75
|
+
console.log('✓ Browser opened automatically\n');
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
console.log(`Please open http://localhost:${WEB_PORT} in your browser\n`);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
// 优雅关闭
|
|
82
|
+
process.on('SIGINT', () => {
|
|
83
|
+
console.log('\n\n🛑 Shutting down...');
|
|
84
|
+
proxyServer.stopAllProxies();
|
|
85
|
+
process.exit(0);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
main().catch(console.error);
|
|
89
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,sDAA8B;AAC9B,gDAAwB;AACxB,4DAAwD;AACxD,4CAAyC;AACzC,wDAAoD;AACpD,iDAAmD;AAEnD,MAAM,QAAQ,GAAG,IAAI,CAAC;AAEtB,KAAK,UAAU,IAAI;IACjB,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAEhD,UAAU;IACV,MAAM,aAAa,GAAG,IAAI,8BAAa,EAAE,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,eAAM,EAAE,CAAC;IAC5B,MAAM,WAAW,GAAG,IAAI,0BAAW,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAE3D,SAAS;IACT,WAAW,CAAC,YAAY,EAAE,CAAC;IAE3B,aAAa;IACb,MAAM,GAAG,GAAG,IAAA,iBAAO,GAAE,CAAC;IAEtB,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAExB,SAAS;IACT,MAAM,KAAK,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAChD,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAE/B,SAAS;IACT,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,IAAA,4BAAe,EAAC,aAAa,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAErE,aAAa;IACb,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACxB,GAAG,CAAC,QAAQ,CAAC,cAAI,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,aAAa;IACb,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;QAC9B,OAAO,CAAC,GAAG,CAAC,wCAAwC,QAAQ,EAAE,CAAC,CAAC;QAChE,OAAO,CAAC,GAAG,CAAC,oBAAoB,WAAW,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC;QAExF,UAAU;QACV,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,CAAC,wDAAa,MAAM,GAAC,CAAC,CAAC,OAAO,CAAC;YAC5C,MAAM,IAAI,CAAC,oBAAoB,QAAQ,EAAE,CAAC,CAAC;YAC3C,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,gCAAgC,QAAQ,oBAAoB,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO;IACP,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;QACvC,WAAW,CAAC,cAAc,EAAE,CAAC;QAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const express_1 = __importDefault(require("express"));
|
|
40
|
+
const path_1 = __importDefault(require("path"));
|
|
41
|
+
const config_manager_1 = require("./server/config-manager");
|
|
42
|
+
const logger_1 = require("./server/logger");
|
|
43
|
+
const proxy_server_1 = require("./server/proxy-server");
|
|
44
|
+
const api_routes_1 = require("./web/api-routes");
|
|
45
|
+
const WEB_PORT = 8888;
|
|
46
|
+
async function main() {
|
|
47
|
+
console.log('🚀 Multiport Proxy Starting...\n');
|
|
48
|
+
// 初始化管理模块
|
|
49
|
+
const configManager = new config_manager_1.ConfigManager();
|
|
50
|
+
const logger = new logger_1.Logger();
|
|
51
|
+
const proxyServer = new proxy_server_1.ProxyServer(configManager, logger);
|
|
52
|
+
// 启动代理服务
|
|
53
|
+
proxyServer.startProxies();
|
|
54
|
+
// 创建 Web 服务器
|
|
55
|
+
const app = (0, express_1.default)();
|
|
56
|
+
app.use(express_1.default.json());
|
|
57
|
+
// 静态文件服务
|
|
58
|
+
const uiDir = path_1.default.join(__dirname, 'web', 'ui');
|
|
59
|
+
app.use(express_1.default.static(uiDir));
|
|
60
|
+
// API 路由
|
|
61
|
+
app.use('/api', (0, api_routes_1.createApiRouter)(configManager, logger, proxyServer));
|
|
62
|
+
// 根路径返回 HTML
|
|
63
|
+
app.get('/', (req, res) => {
|
|
64
|
+
res.sendFile(path_1.default.join(uiDir, 'index.html'));
|
|
65
|
+
});
|
|
66
|
+
// 启动 Web 服务器
|
|
67
|
+
app.listen(WEB_PORT, async () => {
|
|
68
|
+
console.log(`✓ Web UI running on http://localhost:${WEB_PORT}`);
|
|
69
|
+
console.log(`✓ Running ports: ${proxyServer.getRunningPorts().join(', ') || 'none'}\n`);
|
|
70
|
+
// 自动打开浏览器
|
|
71
|
+
try {
|
|
72
|
+
const open = (await Promise.resolve().then(() => __importStar(require('open')))).default;
|
|
73
|
+
await open(`http://localhost:${WEB_PORT}`);
|
|
74
|
+
console.log('✓ Browser opened automatically\n');
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
console.log(`Please open http://localhost:${WEB_PORT} in your browser\n`);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
// 优雅关闭
|
|
81
|
+
process.on('SIGINT', () => {
|
|
82
|
+
console.log('\n\n🛑 Shutting down...');
|
|
83
|
+
proxyServer.stopAllProxies();
|
|
84
|
+
process.exit(0);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
main().catch(console.error);
|
|
88
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,sDAA8B;AAC9B,gDAAwB;AACxB,4DAAwD;AACxD,4CAAyC;AACzC,wDAAoD;AACpD,iDAAmD;AAEnD,MAAM,QAAQ,GAAG,IAAI,CAAC;AAEtB,KAAK,UAAU,IAAI;IACjB,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAEhD,UAAU;IACV,MAAM,aAAa,GAAG,IAAI,8BAAa,EAAE,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,eAAM,EAAE,CAAC;IAC5B,MAAM,WAAW,GAAG,IAAI,0BAAW,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAE3D,SAAS;IACT,WAAW,CAAC,YAAY,EAAE,CAAC;IAE3B,aAAa;IACb,MAAM,GAAG,GAAG,IAAA,iBAAO,GAAE,CAAC;IAEtB,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAExB,SAAS;IACT,MAAM,KAAK,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAChD,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAE/B,SAAS;IACT,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,IAAA,4BAAe,EAAC,aAAa,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAErE,aAAa;IACb,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACxB,GAAG,CAAC,QAAQ,CAAC,cAAI,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,aAAa;IACb,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;QAC9B,OAAO,CAAC,GAAG,CAAC,wCAAwC,QAAQ,EAAE,CAAC,CAAC;QAChE,OAAO,CAAC,GAAG,CAAC,oBAAoB,WAAW,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC;QAExF,UAAU;QACV,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,CAAC,wDAAa,MAAM,GAAC,CAAC,CAAC,OAAO,CAAC;YAC5C,MAAM,IAAI,CAAC,oBAAoB,QAAQ,EAAE,CAAC,CAAC;YAC3C,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,gCAAgC,QAAQ,oBAAoB,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO;IACP,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;QACvC,WAAW,CAAC,cAAc,EAAE,CAAC;QAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface ProxyRule {
|
|
2
|
+
id: string;
|
|
3
|
+
localPort: number;
|
|
4
|
+
targetUrl: string;
|
|
5
|
+
cors?: {
|
|
6
|
+
enabled: boolean;
|
|
7
|
+
origins?: string[];
|
|
8
|
+
};
|
|
9
|
+
timeout?: number;
|
|
10
|
+
retries?: number;
|
|
11
|
+
enabled: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface Config {
|
|
14
|
+
rules: ProxyRule[];
|
|
15
|
+
}
|
|
16
|
+
export declare class ConfigManager {
|
|
17
|
+
private config;
|
|
18
|
+
constructor();
|
|
19
|
+
private loadConfig;
|
|
20
|
+
saveConfig(): void;
|
|
21
|
+
getConfig(): Config;
|
|
22
|
+
getRules(): ProxyRule[];
|
|
23
|
+
addRule(rule: ProxyRule): void;
|
|
24
|
+
updateRule(id: string, updates: Partial<ProxyRule>): void;
|
|
25
|
+
deleteRule(id: string): void;
|
|
26
|
+
setRules(rules: ProxyRule[]): void;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=config-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-manager.d.ts","sourceRoot":"","sources":["../../src/server/config-manager.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE;QACL,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAID,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAS;;IAMvB,OAAO,CAAC,UAAU;IAalB,UAAU,IAAI,IAAI;IAQlB,SAAS,IAAI,MAAM;IAInB,QAAQ,IAAI,SAAS,EAAE;IAIvB,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IAK9B,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI;IAQzD,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAK5B,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI;CAInC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ConfigManager = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const CONFIG_PATH = path.join(process.cwd(), 'data', 'config.json');
|
|
40
|
+
class ConfigManager {
|
|
41
|
+
constructor() {
|
|
42
|
+
this.config = this.loadConfig();
|
|
43
|
+
}
|
|
44
|
+
loadConfig() {
|
|
45
|
+
try {
|
|
46
|
+
if (fs.existsSync(CONFIG_PATH)) {
|
|
47
|
+
const data = fs.readFileSync(CONFIG_PATH, 'utf-8');
|
|
48
|
+
return JSON.parse(data);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
console.warn('Failed to load config, using defaults:', error);
|
|
53
|
+
}
|
|
54
|
+
return { rules: [] };
|
|
55
|
+
}
|
|
56
|
+
saveConfig() {
|
|
57
|
+
const dataDir = path.dirname(CONFIG_PATH);
|
|
58
|
+
if (!fs.existsSync(dataDir)) {
|
|
59
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
60
|
+
}
|
|
61
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(this.config, null, 2), 'utf-8');
|
|
62
|
+
}
|
|
63
|
+
getConfig() {
|
|
64
|
+
return this.config;
|
|
65
|
+
}
|
|
66
|
+
getRules() {
|
|
67
|
+
return this.config.rules;
|
|
68
|
+
}
|
|
69
|
+
addRule(rule) {
|
|
70
|
+
this.config.rules.push(rule);
|
|
71
|
+
this.saveConfig();
|
|
72
|
+
}
|
|
73
|
+
updateRule(id, updates) {
|
|
74
|
+
const index = this.config.rules.findIndex(r => r.id === id);
|
|
75
|
+
if (index !== -1) {
|
|
76
|
+
this.config.rules[index] = { ...this.config.rules[index], ...updates };
|
|
77
|
+
this.saveConfig();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
deleteRule(id) {
|
|
81
|
+
this.config.rules = this.config.rules.filter(r => r.id !== id);
|
|
82
|
+
this.saveConfig();
|
|
83
|
+
}
|
|
84
|
+
setRules(rules) {
|
|
85
|
+
this.config.rules = rules;
|
|
86
|
+
this.saveConfig();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
exports.ConfigManager = ConfigManager;
|
|
90
|
+
//# sourceMappingURL=config-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../src/server/config-manager.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,2CAA6B;AAmB7B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;AAEpE,MAAa,aAAa;IAGxB;QACE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;IAClC,CAAC;IAEO,UAAU;QAChB,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC/B,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;gBACnD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,wCAAwC,EAAE,KAAK,CAAC,CAAC;QAChE,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACvB,CAAC;IAED,UAAU;QACR,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAC1C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;QACD,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAC/E,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;IAC3B,CAAC;IAED,OAAO,CAAC,IAAe;QACrB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAED,UAAU,CAAC,EAAU,EAAE,OAA2B;QAChD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACjB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC;YACvE,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;IAED,UAAU,CAAC,EAAU;QACnB,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC/D,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAED,QAAQ,CAAC,KAAkB;QACzB,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;CACF;AA1DD,sCA0DC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface LogEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
timestamp: number;
|
|
4
|
+
localPort: number;
|
|
5
|
+
method: string;
|
|
6
|
+
path: string;
|
|
7
|
+
statusCode?: number;
|
|
8
|
+
duration: number;
|
|
9
|
+
targetUrl: string;
|
|
10
|
+
error?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare class Logger {
|
|
13
|
+
private logs;
|
|
14
|
+
private maxLogs;
|
|
15
|
+
addLog(entry: Omit<LogEntry, 'id'>): LogEntry;
|
|
16
|
+
getLogs(limit?: number, offset?: number): LogEntry[];
|
|
17
|
+
getLogsByPort(port: number, limit?: number): LogEntry[];
|
|
18
|
+
getLogsByStatusCode(statusCode: number, limit?: number): LogEntry[];
|
|
19
|
+
clearLogs(): void;
|
|
20
|
+
getAllLogs(): LogEntry[];
|
|
21
|
+
getStats(): {
|
|
22
|
+
totalLogs: number;
|
|
23
|
+
errorCount: number;
|
|
24
|
+
averageDuration: number;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,MAAM;IACjB,OAAO,CAAC,IAAI,CAAkB;IAC9B,OAAO,CAAC,OAAO,CAAO;IAEtB,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,QAAQ;IAgB7C,OAAO,CAAC,KAAK,GAAE,MAAY,EAAE,MAAM,GAAE,MAAU,GAAG,QAAQ,EAAE;IAI5D,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,MAAY,GAAG,QAAQ,EAAE;IAI5D,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,GAAE,MAAY,GAAG,QAAQ,EAAE;IAIxE,SAAS,IAAI,IAAI;IAIjB,UAAU,IAAI,QAAQ,EAAE;IAIxB,QAAQ;;;;;CAST"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Logger = void 0;
|
|
4
|
+
class Logger {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.logs = [];
|
|
7
|
+
this.maxLogs = 500;
|
|
8
|
+
}
|
|
9
|
+
addLog(entry) {
|
|
10
|
+
const logEntry = {
|
|
11
|
+
id: Math.random().toString(36).slice(2),
|
|
12
|
+
...entry,
|
|
13
|
+
};
|
|
14
|
+
this.logs.unshift(logEntry);
|
|
15
|
+
// 保持日志数量在限制内
|
|
16
|
+
if (this.logs.length > this.maxLogs) {
|
|
17
|
+
this.logs = this.logs.slice(0, this.maxLogs);
|
|
18
|
+
}
|
|
19
|
+
return logEntry;
|
|
20
|
+
}
|
|
21
|
+
getLogs(limit = 100, offset = 0) {
|
|
22
|
+
return this.logs.slice(offset, offset + limit);
|
|
23
|
+
}
|
|
24
|
+
getLogsByPort(port, limit = 100) {
|
|
25
|
+
return this.logs.filter(log => log.localPort === port).slice(0, limit);
|
|
26
|
+
}
|
|
27
|
+
getLogsByStatusCode(statusCode, limit = 100) {
|
|
28
|
+
return this.logs.filter(log => log.statusCode === statusCode).slice(0, limit);
|
|
29
|
+
}
|
|
30
|
+
clearLogs() {
|
|
31
|
+
this.logs = [];
|
|
32
|
+
}
|
|
33
|
+
getAllLogs() {
|
|
34
|
+
return this.logs;
|
|
35
|
+
}
|
|
36
|
+
getStats() {
|
|
37
|
+
return {
|
|
38
|
+
totalLogs: this.logs.length,
|
|
39
|
+
errorCount: this.logs.filter(l => l.error).length,
|
|
40
|
+
averageDuration: this.logs.length > 0
|
|
41
|
+
? Math.round(this.logs.reduce((sum, log) => sum + log.duration, 0) / this.logs.length)
|
|
42
|
+
: 0,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.Logger = Logger;
|
|
47
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":";;;AAYA,MAAa,MAAM;IAAnB;QACU,SAAI,GAAe,EAAE,CAAC;QACtB,YAAO,GAAG,GAAG,CAAC;IA+CxB,CAAC;IA7CC,MAAM,CAAC,KAA2B;QAChC,MAAM,QAAQ,GAAa;YACzB,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YACvC,GAAG,KAAK;SACT,CAAC;QAEF,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAE5B,aAAa;QACb,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;YACpC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC/C,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,QAAgB,GAAG,EAAE,SAAiB,CAAC;QAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC;IACjD,CAAC;IAED,aAAa,CAAC,IAAY,EAAE,QAAgB,GAAG;QAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACzE,CAAC;IAED,mBAAmB,CAAC,UAAkB,EAAE,QAAgB,GAAG;QACzD,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAChF,CAAC;IAED,SAAS;QACP,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;IACjB,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,QAAQ;QACN,OAAO;YACL,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;YAC3B,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM;YACjD,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;gBACnC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;gBACtF,CAAC,CAAC,CAAC;SACN,CAAC;IACJ,CAAC;CACF;AAjDD,wBAiDC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ConfigManager } from './config-manager';
|
|
2
|
+
import { Logger } from './logger';
|
|
3
|
+
export declare class ProxyServer {
|
|
4
|
+
private servers;
|
|
5
|
+
private configManager;
|
|
6
|
+
private logger;
|
|
7
|
+
constructor(configManager: ConfigManager, logger: Logger);
|
|
8
|
+
startProxies(): void;
|
|
9
|
+
private startProxy;
|
|
10
|
+
stopProxy(port: number): void;
|
|
11
|
+
stopAllProxies(): void;
|
|
12
|
+
updateProxies(): void;
|
|
13
|
+
getRunningPorts(): number[];
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=proxy-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-server.d.ts","sourceRoot":"","sources":["../../src/server/proxy-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAa,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,MAAM,CAAS;gBAEX,aAAa,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM;IAKxD,YAAY,IAAI,IAAI;IAQpB,OAAO,CAAC,UAAU;IAuHlB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAS7B,cAAc,IAAI,IAAI;IAMtB,aAAa,IAAI,IAAI;IAKrB,eAAe,IAAI,MAAM,EAAE;CAG5B"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.ProxyServer = void 0;
|
|
40
|
+
const http = __importStar(require("http"));
|
|
41
|
+
const http_proxy_1 = __importDefault(require("http-proxy"));
|
|
42
|
+
class ProxyServer {
|
|
43
|
+
constructor(configManager, logger) {
|
|
44
|
+
this.servers = new Map();
|
|
45
|
+
this.configManager = configManager;
|
|
46
|
+
this.logger = logger;
|
|
47
|
+
}
|
|
48
|
+
startProxies() {
|
|
49
|
+
const rules = this.configManager.getRules().filter(r => r.enabled);
|
|
50
|
+
for (const rule of rules) {
|
|
51
|
+
this.startProxy(rule);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
startProxy(rule) {
|
|
55
|
+
if (this.servers.has(rule.localPort)) {
|
|
56
|
+
this.stopProxy(rule.localPort);
|
|
57
|
+
}
|
|
58
|
+
const proxy = http_proxy_1.default.createProxyServer({
|
|
59
|
+
target: rule.targetUrl,
|
|
60
|
+
timeout: rule.timeout || 30000,
|
|
61
|
+
changeOrigin: true,
|
|
62
|
+
secure: false, // 允许自签名证书
|
|
63
|
+
followRedirects: true,
|
|
64
|
+
autoRewrite: true,
|
|
65
|
+
});
|
|
66
|
+
const server = http.createServer((req, res) => {
|
|
67
|
+
const startTime = Date.now();
|
|
68
|
+
// 处理 CORS
|
|
69
|
+
if (rule.cors?.enabled) {
|
|
70
|
+
const origins = rule.cors.origins || ['*'];
|
|
71
|
+
const origin = req.headers.origin || '*';
|
|
72
|
+
if (origins.includes('*') || origins.includes(origin)) {
|
|
73
|
+
res.setHeader('Access-Control-Allow-Origin', origin);
|
|
74
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
|
|
75
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, *');
|
|
76
|
+
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// 处理 OPTIONS 请求
|
|
80
|
+
if (req.method === 'OPTIONS') {
|
|
81
|
+
res.writeHead(200);
|
|
82
|
+
res.end();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// 代理请求
|
|
86
|
+
let retryCount = 0;
|
|
87
|
+
const maxRetries = rule.retries || 0;
|
|
88
|
+
const handleRequest = () => {
|
|
89
|
+
proxy.web(req, res);
|
|
90
|
+
};
|
|
91
|
+
// 错误处理
|
|
92
|
+
proxy.on('error', (error) => {
|
|
93
|
+
const duration = Date.now() - startTime;
|
|
94
|
+
if (retryCount < maxRetries) {
|
|
95
|
+
retryCount++;
|
|
96
|
+
console.log(`Retry ${retryCount}/${maxRetries} for ${rule.localPort}`);
|
|
97
|
+
handleRequest();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
// 详细的错误日志
|
|
101
|
+
console.error(`[${rule.localPort}] Proxy error:`, error.message);
|
|
102
|
+
console.error(`[${rule.localPort}] Request: ${req.method} ${req.url}`);
|
|
103
|
+
console.error(`[${rule.localPort}] Target: ${rule.targetUrl}`);
|
|
104
|
+
this.logger.addLog({
|
|
105
|
+
timestamp: Date.now(),
|
|
106
|
+
localPort: rule.localPort,
|
|
107
|
+
method: req.method || 'GET',
|
|
108
|
+
path: req.url || '/',
|
|
109
|
+
duration,
|
|
110
|
+
targetUrl: rule.targetUrl,
|
|
111
|
+
error: error.message,
|
|
112
|
+
});
|
|
113
|
+
if (!res.headersSent) {
|
|
114
|
+
res.writeHead(502, { 'Content-Type': 'application/json' });
|
|
115
|
+
res.end(JSON.stringify({
|
|
116
|
+
error: 'Bad Gateway',
|
|
117
|
+
message: error.message,
|
|
118
|
+
target: rule.targetUrl,
|
|
119
|
+
path: req.url,
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
// 监听代理响应
|
|
124
|
+
proxy.once('proxyRes', (proxyRes) => {
|
|
125
|
+
const duration = Date.now() - startTime;
|
|
126
|
+
this.logger.addLog({
|
|
127
|
+
timestamp: Date.now(),
|
|
128
|
+
localPort: rule.localPort,
|
|
129
|
+
method: req.method || 'GET',
|
|
130
|
+
path: req.url || '/',
|
|
131
|
+
statusCode: proxyRes.statusCode,
|
|
132
|
+
duration,
|
|
133
|
+
targetUrl: rule.targetUrl,
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
handleRequest();
|
|
137
|
+
});
|
|
138
|
+
try {
|
|
139
|
+
server.listen(rule.localPort, () => {
|
|
140
|
+
console.log(`✓ Proxy running: localhost:${rule.localPort} -> ${rule.targetUrl}`);
|
|
141
|
+
});
|
|
142
|
+
server.on('error', (error) => {
|
|
143
|
+
if (error.code === 'EADDRINUSE') {
|
|
144
|
+
console.error(`✗ Port ${rule.localPort} is already in use`);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
console.error(`✗ Error on port ${rule.localPort}:`, error.message);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
this.servers.set(rule.localPort, server);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
console.error(`Failed to start proxy on port ${rule.localPort}:`, error);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
stopProxy(port) {
|
|
157
|
+
const server = this.servers.get(port);
|
|
158
|
+
if (server) {
|
|
159
|
+
server.close();
|
|
160
|
+
this.servers.delete(port);
|
|
161
|
+
console.log(`✓ Proxy stopped on port ${port}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
stopAllProxies() {
|
|
165
|
+
for (const port of this.servers.keys()) {
|
|
166
|
+
this.stopProxy(port);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
updateProxies() {
|
|
170
|
+
this.stopAllProxies();
|
|
171
|
+
this.startProxies();
|
|
172
|
+
}
|
|
173
|
+
getRunningPorts() {
|
|
174
|
+
return Array.from(this.servers.keys());
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
exports.ProxyServer = ProxyServer;
|
|
178
|
+
//# sourceMappingURL=proxy-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-server.js","sourceRoot":"","sources":["../../src/server/proxy-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { ConfigManager } from '../server/config-manager';
|
|
3
|
+
import { Logger } from '../server/logger';
|
|
4
|
+
import { ProxyServer } from '../server/proxy-server';
|
|
5
|
+
export declare function createApiRouter(configManager: ConfigManager, logger: Logger, proxyServer: ProxyServer): Router;
|
|
6
|
+
//# sourceMappingURL=api-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-routes.d.ts","sourceRoot":"","sources":["../../src/web/api-routes.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,wBAAgB,eAAe,CAC7B,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,WAAW,GACvB,MAAM,CAkHR"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createApiRouter = createApiRouter;
|
|
7
|
+
const express_1 = __importDefault(require("express"));
|
|
8
|
+
function createApiRouter(configManager, logger, proxyServer) {
|
|
9
|
+
const router = express_1.default.Router();
|
|
10
|
+
// 获取所有配置
|
|
11
|
+
router.get('/config', (req, res) => {
|
|
12
|
+
res.json(configManager.getConfig());
|
|
13
|
+
});
|
|
14
|
+
// 保存配置
|
|
15
|
+
router.post('/config', (req, res) => {
|
|
16
|
+
try {
|
|
17
|
+
const { rules } = req.body;
|
|
18
|
+
if (!Array.isArray(rules)) {
|
|
19
|
+
return res.status(400).json({ error: 'Invalid rules format' });
|
|
20
|
+
}
|
|
21
|
+
configManager.setRules(rules);
|
|
22
|
+
proxyServer.updateProxies();
|
|
23
|
+
res.json({ success: true, message: 'Config saved' });
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
res.status(500).json({ error: error.message });
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
// 添加规则
|
|
30
|
+
router.post('/config/rules', (req, res) => {
|
|
31
|
+
try {
|
|
32
|
+
const rule = req.body;
|
|
33
|
+
if (!rule.id) {
|
|
34
|
+
rule.id = Math.random().toString(36).slice(2);
|
|
35
|
+
}
|
|
36
|
+
rule.enabled = rule.enabled !== false;
|
|
37
|
+
configManager.addRule(rule);
|
|
38
|
+
proxyServer.updateProxies();
|
|
39
|
+
res.json({ success: true, rule });
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
res.status(500).json({ error: error.message });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
// 更新规则
|
|
46
|
+
router.put('/config/rules/:id', (req, res) => {
|
|
47
|
+
try {
|
|
48
|
+
const { id } = req.params;
|
|
49
|
+
const updates = req.body;
|
|
50
|
+
configManager.updateRule(id, updates);
|
|
51
|
+
proxyServer.updateProxies();
|
|
52
|
+
res.json({ success: true, message: 'Rule updated' });
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
res.status(500).json({ error: error.message });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
// 删除规则
|
|
59
|
+
router.delete('/config/rules/:id', (req, res) => {
|
|
60
|
+
try {
|
|
61
|
+
const { id } = req.params;
|
|
62
|
+
configManager.deleteRule(id);
|
|
63
|
+
proxyServer.updateProxies();
|
|
64
|
+
res.json({ success: true, message: 'Rule deleted' });
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
res.status(500).json({ error: error.message });
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
// 获取日志
|
|
71
|
+
router.get('/logs', (req, res) => {
|
|
72
|
+
try {
|
|
73
|
+
const { limit = '100', offset = '0', port, statusCode } = req.query;
|
|
74
|
+
let logs;
|
|
75
|
+
if (port) {
|
|
76
|
+
logs = logger.getLogsByPort(parseInt(port), parseInt(limit));
|
|
77
|
+
}
|
|
78
|
+
else if (statusCode) {
|
|
79
|
+
logs = logger.getLogsByStatusCode(parseInt(statusCode), parseInt(limit));
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
logs = logger.getLogs(parseInt(limit), parseInt(offset));
|
|
83
|
+
}
|
|
84
|
+
res.json({
|
|
85
|
+
logs,
|
|
86
|
+
stats: logger.getStats(),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
res.status(500).json({ error: error.message });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
// 清空日志
|
|
94
|
+
router.delete('/logs', (req, res) => {
|
|
95
|
+
try {
|
|
96
|
+
logger.clearLogs();
|
|
97
|
+
res.json({ success: true, message: 'Logs cleared' });
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
res.status(500).json({ error: error.message });
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
// 获取运行状态
|
|
104
|
+
router.get('/status', (req, res) => {
|
|
105
|
+
res.json({
|
|
106
|
+
runningPorts: proxyServer.getRunningPorts(),
|
|
107
|
+
stats: logger.getStats(),
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
return router;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=api-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-routes.js","sourceRoot":"","sources":["../../src/web/api-routes.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jachy/multiport-proxy",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A multi-port proxy server with web UI configuration",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"multiport-proxy": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"private": false,
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"dev": "ts-node src/cli.ts",
|
|
16
|
+
"build": "tsc && chmod +x dist/cli.js",
|
|
17
|
+
"start": "node dist/cli.js",
|
|
18
|
+
"prepublishOnly": "pnpm run build",
|
|
19
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
20
|
+
},
|
|
21
|
+
"keywords": ["proxy", "multiport", "http", "cli", "reverse-proxy", "port-forwarding", "web-ui"],
|
|
22
|
+
"author": "Jachy",
|
|
23
|
+
"license": "ISC",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/Mammoth777/multiport-proxy.git"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/Mammoth777/multiport-proxy/issues"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/Mammoth777/multiport-proxy#readme",
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=16.0.0"
|
|
34
|
+
},
|
|
35
|
+
"packageManager": "pnpm@10.17.0",
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"express": "^4.18.2",
|
|
38
|
+
"http-proxy": "^1.18.1",
|
|
39
|
+
"open": "^10.0.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/express": "^4.17.21",
|
|
43
|
+
"@types/http-proxy": "^1.17.14",
|
|
44
|
+
"@types/node": "^20.10.0",
|
|
45
|
+
"typescript": "^5.3.3",
|
|
46
|
+
"ts-node": "^10.9.2"
|
|
47
|
+
}
|
|
48
|
+
}
|