env-plugin 0.5.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/LICENSE +21 -0
- package/bin/index.js +23 -0
- package/dist/Container.js +55 -0
- package/dist/Plugin.js +25 -0
- package/dist/PostProxyServer.js +85 -0
- package/dist/client/assets/element-plus-wndYbaZY.js.gz +0 -0
- package/dist/client/assets/index-Bl3B2M1W.js.gz +0 -0
- package/dist/client/assets/index-nrcddKJg.css.gz +0 -0
- package/dist/client/assets/vue-BGFZjnqd.js.gz +0 -0
- package/dist/client/favicon.ico +0 -0
- package/dist/client/index.html +16 -0
- package/dist/constants/responseCode.js +27 -0
- package/dist/controllers/DevServerController.js +102 -0
- package/dist/controllers/EnvController.js +177 -0
- package/dist/controllers/PasswordController.js +106 -0
- package/dist/controllers/RouteRuleController.js +106 -0
- package/dist/dto/BaseRes.js +1 -0
- package/dist/dto/EnvDTO.js +4 -0
- package/dist/index.js +108 -0
- package/dist/middleware/dto.middleware.js +38 -0
- package/dist/middleware/globalErrorHandler.js +42 -0
- package/dist/middleware/responseEnhancer.js +52 -0
- package/dist/models/DevServerModel.js +1 -0
- package/dist/models/EnvModel.js +14 -0
- package/dist/repositories/DevServerRepo.js +101 -0
- package/dist/repositories/EnvRepo.js +121 -0
- package/dist/repositories/PasswordRepo.js +142 -0
- package/dist/repositories/RouteRuleRepo.js +106 -0
- package/dist/repositories/database.js +95 -0
- package/dist/routes/index.js +78 -0
- package/dist/service/DevServerService.js +189 -0
- package/dist/service/EnvService.js +214 -0
- package/dist/service/PasswordService.js +100 -0
- package/dist/service/PreProxyServer.js +344 -0
- package/dist/service/ProxyAutoStarterService.js +62 -0
- package/dist/service/RouteRuleService.js +131 -0
- package/dist/types/index.js +5 -0
- package/dist/types/shared/BaseRes.js +36 -0
- package/dist/types/shared/DevServerItem.js +51 -0
- package/dist/types/shared/EnvItem.js +57 -0
- package/dist/types/shared/EnvmConfig.js +17 -0
- package/dist/types/shared/ListRes.js +1 -0
- package/dist/types/shared/Password.js +48 -0
- package/dist/types/shared/RouteRule.js +49 -0
- package/dist/utils/ResolveConfig.js +79 -0
- package/dist/utils/errors.js +8 -0
- package/dist/utils/logger.js +93 -0
- package/package.json +78 -0
- package/readme.md +214 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { envLogger } from "../utils/logger.js";
|
|
2
|
+
/**
|
|
3
|
+
* 路由规则控制器
|
|
4
|
+
* 负责处理与路由规则相关的HTTP请求,作为请求入口层:
|
|
5
|
+
* - 解析并验证请求参数
|
|
6
|
+
* - 调用对应的服务层方法处理业务逻辑
|
|
7
|
+
* - 格式化并返回响应结果
|
|
8
|
+
* - 统一错误处理
|
|
9
|
+
*/
|
|
10
|
+
class RouteRuleController {
|
|
11
|
+
/**
|
|
12
|
+
* 构造函数 - 注入路由规则服务实例
|
|
13
|
+
* @param private readonly routeRuleService - 路由规则服务实例,处理核心业务逻辑
|
|
14
|
+
*/
|
|
15
|
+
constructor(routeRuleService) {
|
|
16
|
+
this.routeRuleService = routeRuleService;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 获取指定环境的路由规则列表
|
|
20
|
+
* @description 处理查询指定环境所有路由规则的GET请求
|
|
21
|
+
* @param req - Express请求对象,包含环境ID(在params中)
|
|
22
|
+
* @param res - Express响应对象,用于返回路由规则列表
|
|
23
|
+
* @param next - Express下一步中间件函数,用于错误处理
|
|
24
|
+
*/
|
|
25
|
+
handleGetList(req, res, next) {
|
|
26
|
+
try {
|
|
27
|
+
const envId = req.params.envId;
|
|
28
|
+
envLogger.info({ envId }, "接收路由规则列表查询请求");
|
|
29
|
+
// 调用服务层获取数据
|
|
30
|
+
const list = this.routeRuleService.handleGetByEnvId(envId);
|
|
31
|
+
// 返回成功响应(包含列表数据)
|
|
32
|
+
res.success({ list, total: list.length });
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
envLogger.error(error, "路由规则列表查询请求处理失败");
|
|
36
|
+
next(error);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 新增路由规则
|
|
41
|
+
* @description 处理创建新路由规则的POST请求
|
|
42
|
+
* @param req - Express请求对象,包含待创建的路由规则数据(在req.dto中)
|
|
43
|
+
* @param res - Express响应对象,用于返回处理结果
|
|
44
|
+
* @param next - Express下一步中间件函数,用于错误处理
|
|
45
|
+
*/
|
|
46
|
+
handleAdd(req, res, next) {
|
|
47
|
+
try {
|
|
48
|
+
// 验证请求数据
|
|
49
|
+
const routeRuleData = req.dto;
|
|
50
|
+
envLogger.info({ routeRuleData }, "接收新增路由规则请求");
|
|
51
|
+
// 调用服务层处理业务
|
|
52
|
+
const newRule = this.routeRuleService.handleAdd(routeRuleData);
|
|
53
|
+
// 返回成功响应
|
|
54
|
+
res.success({ message: "路由规则添加成功", data: newRule });
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
envLogger.error(error, "新增路由规则请求处理失败");
|
|
58
|
+
next(error);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 更新路由规则
|
|
63
|
+
* @description 处理更新路由规则的POST/PUT请求
|
|
64
|
+
* @param req - Express请求对象,包含待更新的路由规则数据(在req.dto中)
|
|
65
|
+
* @param res - Express响应对象,用于返回处理结果
|
|
66
|
+
* @param next - Express下一步中间件函数,用于错误处理
|
|
67
|
+
*/
|
|
68
|
+
handleUpdate(req, res, next) {
|
|
69
|
+
try {
|
|
70
|
+
// 验证请求数据
|
|
71
|
+
const routeRuleData = req.dto;
|
|
72
|
+
envLogger.info({ routeRuleData }, "接收更新路由规则请求");
|
|
73
|
+
// 调用服务层处理业务
|
|
74
|
+
const updatedRule = this.routeRuleService.handleUpdate(routeRuleData);
|
|
75
|
+
// 返回成功响应
|
|
76
|
+
res.success({ message: "路由规则更新成功", data: updatedRule });
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
envLogger.error(error, "更新路由规则请求处理失败");
|
|
80
|
+
next(error);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 删除路由规则
|
|
85
|
+
* @description 处理删除路由规则的POST/DELETE请求
|
|
86
|
+
* @param req - Express请求对象,包含待删除路由规则的ID(在req.dto中)
|
|
87
|
+
* @param res - Express响应对象,用于返回处理结果
|
|
88
|
+
* @param next - Express下一步中间件函数,用于错误处理
|
|
89
|
+
*/
|
|
90
|
+
handleDelete(req, res, next) {
|
|
91
|
+
try {
|
|
92
|
+
// 验证请求数据
|
|
93
|
+
const routeRuleData = req.dto;
|
|
94
|
+
envLogger.info({ routeRuleData }, "接收删除路由规则请求");
|
|
95
|
+
// 调用服务层处理业务
|
|
96
|
+
this.routeRuleService.handleDelete(routeRuleData);
|
|
97
|
+
// 返回成功响应
|
|
98
|
+
res.success({ message: "路由规则删除成功" });
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
envLogger.error(error, "删除路由规则请求处理失败");
|
|
102
|
+
next(error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export { RouteRuleController };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import portfinder from "portfinder";
|
|
2
|
+
import http from "http";
|
|
3
|
+
import PostProxyServer from "./PostProxyServer.js";
|
|
4
|
+
import { getConfig, loadConfig } from "./utils/ResolveConfig.js";
|
|
5
|
+
import { startDatabase } from "./repositories/database.js";
|
|
6
|
+
import { initLoggers, logger } from "./utils/logger.js";
|
|
7
|
+
class EnvManage {
|
|
8
|
+
get config() {
|
|
9
|
+
return getConfig();
|
|
10
|
+
}
|
|
11
|
+
constructor(options = {}) {
|
|
12
|
+
try {
|
|
13
|
+
loadConfig(options);
|
|
14
|
+
initLoggers(this.config.logLevel);
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (error instanceof Error) {
|
|
18
|
+
console.error("❌ 配置加载失败,服务启动失败,", error.message);
|
|
19
|
+
}
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async startIndependent() {
|
|
24
|
+
logger.info(this.config, "Starting EnvManage...");
|
|
25
|
+
// 检查端口是否被占用
|
|
26
|
+
try {
|
|
27
|
+
await this.checkPortAsync();
|
|
28
|
+
logger.info(`端口 ${this.config.port} 可用,启动服务...`);
|
|
29
|
+
await startDatabase();
|
|
30
|
+
new PostProxyServer();
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (error instanceof Error) {
|
|
34
|
+
logger.error(error, "启动失败");
|
|
35
|
+
}
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 判断端口是否被占用,如果被占用的,查询是否已经启动
|
|
41
|
+
* @returns
|
|
42
|
+
*/
|
|
43
|
+
async checkPortAsync() {
|
|
44
|
+
const result = await this.isPortOccupied(this.config.port);
|
|
45
|
+
if (result) {
|
|
46
|
+
try {
|
|
47
|
+
await this.checkIsRunning();
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
logger.error(error, "端口被占用,且不是 envm 服务");
|
|
51
|
+
}
|
|
52
|
+
throw new Error(`envm 服务已经在端口 ${this.config.port} 启动,请勿重复启动!`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
*
|
|
57
|
+
* @param port 查询端口是否被占用
|
|
58
|
+
* @returns
|
|
59
|
+
*/
|
|
60
|
+
isPortOccupied(port) {
|
|
61
|
+
return portfinder
|
|
62
|
+
.getPortPromise({
|
|
63
|
+
port: port,
|
|
64
|
+
stopPort: port,
|
|
65
|
+
})
|
|
66
|
+
.then(() => {
|
|
67
|
+
return false;
|
|
68
|
+
})
|
|
69
|
+
.catch(() => {
|
|
70
|
+
return true;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 查询端口,中启动的服务是否为 envm
|
|
75
|
+
* @returns
|
|
76
|
+
*/
|
|
77
|
+
checkIsRunning() {
|
|
78
|
+
const options = {
|
|
79
|
+
hostname: "127.0.0.1",
|
|
80
|
+
port: this.config.port,
|
|
81
|
+
path: `${this.config.apiPrefix}/are-you-ok`,
|
|
82
|
+
method: "GET",
|
|
83
|
+
};
|
|
84
|
+
return new Promise((resolve, reject) => {
|
|
85
|
+
const req = http.request(options, (res) => {
|
|
86
|
+
const statusCode = res.statusCode || 0;
|
|
87
|
+
if (statusCode < 200 || statusCode >= 300) {
|
|
88
|
+
reject(new Error(`请求失败,状态码: ${res.statusCode}`));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
let responseData = "";
|
|
92
|
+
res.on("data", (chunk) => {
|
|
93
|
+
responseData += chunk;
|
|
94
|
+
});
|
|
95
|
+
res.on("end", () => {
|
|
96
|
+
const result = JSON.parse(responseData);
|
|
97
|
+
logger.info(result, "收到已启动的代理服务返回的消息");
|
|
98
|
+
resolve(result);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
req.on("error", (error) => {
|
|
102
|
+
reject(error);
|
|
103
|
+
});
|
|
104
|
+
req.end();
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
export { EnvManage };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ZodError } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* 类型安全的DTO转换中间件
|
|
4
|
+
* 将接入参转换为对应的DTO
|
|
5
|
+
*/
|
|
6
|
+
export const toDTO = (schema, source = "body") => {
|
|
7
|
+
return (req, res, next) => {
|
|
8
|
+
try {
|
|
9
|
+
// 从指定来源提取原始数据
|
|
10
|
+
const rawData = req[source];
|
|
11
|
+
// 校验并转换数据(ZodType确保类型安全)
|
|
12
|
+
const validatedData = schema.parse(rawData);
|
|
13
|
+
// 将转换后的DTO挂载到req对象
|
|
14
|
+
req.dto = validatedData;
|
|
15
|
+
next();
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
// 严格判断Zod错误类型(无any)
|
|
19
|
+
if (err instanceof ZodError) {
|
|
20
|
+
// 格式化Zod错误信息
|
|
21
|
+
const errors = err.issues.map((issue) => ({
|
|
22
|
+
field: issue.path.join("."),
|
|
23
|
+
message: issue.message,
|
|
24
|
+
}));
|
|
25
|
+
return res.status(400).json({
|
|
26
|
+
code: 400,
|
|
27
|
+
message: errors[0].message || "参数校验失败",
|
|
28
|
+
errors,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
// 处理其他未知错误
|
|
32
|
+
res.status(500).json({
|
|
33
|
+
code: 500,
|
|
34
|
+
message: "服务器内部错误",
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { AppError } from "../utils/errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* 全局错误处理中间件
|
|
4
|
+
*
|
|
5
|
+
* 统一捕获并处理应用中抛出的所有错误(包括自定义错误和系统错误),
|
|
6
|
+
* 通过响应增强器提供的 res.error() 方法返回标准化错误响应。
|
|
7
|
+
*
|
|
8
|
+
* @param {Error} err - 捕获到的错误对象,可能是自定义错误或系统原生错误
|
|
9
|
+
* @param {Request} req - Express 请求对象
|
|
10
|
+
* @param {Response} res - Express 响应对象(已通过 responseEnhancer 增强,包含 error 方法)
|
|
11
|
+
* @returns {void} 无返回值,直接通过 res.error() 发送响应
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // 在 Express 应用中注册
|
|
15
|
+
* app.use(globalErrorHandler);
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // 抛出错误时会被此中间件捕获
|
|
19
|
+
* throw new AppError('资源未找到', 404, 10001);
|
|
20
|
+
*/
|
|
21
|
+
export const globalErrorHandler = (err, req, res,
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
23
|
+
next) => {
|
|
24
|
+
// 初始化响应信息
|
|
25
|
+
let code;
|
|
26
|
+
let message;
|
|
27
|
+
let status = 0;
|
|
28
|
+
// 处理自定义错误(业务已知错误)
|
|
29
|
+
if (err instanceof AppError) {
|
|
30
|
+
code = err.code;
|
|
31
|
+
message = err.message;
|
|
32
|
+
status = err.status;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
// 处理系统错误(如TypeError、ReferenceError等未知错误)
|
|
36
|
+
console.error("系统错误详情:", err); // 记录详细错误日志用于排查
|
|
37
|
+
code = 500; // 业务状态码:服务器内部错误
|
|
38
|
+
message = "服务器内部错误"; // 对用户展示的友好信息(避免暴露敏感信息)
|
|
39
|
+
}
|
|
40
|
+
// 使用增强的响应方法发送标准化错误响应
|
|
41
|
+
res.error(message, code, { status });
|
|
42
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 响应增强中间件
|
|
3
|
+
*
|
|
4
|
+
* 为 Express 的 Response 对象添加统一格式的 success 和 error 响应方法,
|
|
5
|
+
* 确保 API 返回数据结构一致,包含状态码、消息、数据和时间戳。
|
|
6
|
+
*
|
|
7
|
+
* @param {Request} req - Express 请求对象
|
|
8
|
+
* @param {Response} res - Express 响应对象
|
|
9
|
+
* @param {NextFunction} next - Express 下一步中间件函数
|
|
10
|
+
* @returns {void}
|
|
11
|
+
*/
|
|
12
|
+
export const responseEnhancer = (req, res, next) => {
|
|
13
|
+
/**
|
|
14
|
+
* 发送成功响应
|
|
15
|
+
*
|
|
16
|
+
* @template T - 响应数据的类型
|
|
17
|
+
* @param {T} [data] - 成功响应的数据 payload,可为任意类型
|
|
18
|
+
* @param {string} [message="操作成功"] - 成功提示消息
|
|
19
|
+
* @param {number} [code=200] - HTTP 状态码,默认 200
|
|
20
|
+
* @returns {Response} Express 响应对象,支持链式调用
|
|
21
|
+
* @example
|
|
22
|
+
* res.success({ id: 1, name: '示例' }, '获取成功', 200);
|
|
23
|
+
*/
|
|
24
|
+
res.success = function (data, message = "操作成功", code = 200) {
|
|
25
|
+
return res.status(code).json({
|
|
26
|
+
code,
|
|
27
|
+
message,
|
|
28
|
+
data,
|
|
29
|
+
timestamp: Date.now(),
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* 发送错误响应
|
|
34
|
+
*
|
|
35
|
+
* @template T - 错误附加数据的类型
|
|
36
|
+
* @param {string} [message="操作失败"] - 错误提示消息
|
|
37
|
+
* @param {number} [code=500] - HTTP 状态码,默认 500
|
|
38
|
+
* @param {T} [data] - 错误相关的附加数据,可为任意类型
|
|
39
|
+
* @returns {Response} Express 响应对象,支持链式调用
|
|
40
|
+
* @example
|
|
41
|
+
* res.error('参数错误', 400, { invalidFields: ['name'] });
|
|
42
|
+
*/
|
|
43
|
+
res.error = function (message = "操作失败", code = 500, data) {
|
|
44
|
+
return res.status(code).json({
|
|
45
|
+
code,
|
|
46
|
+
message,
|
|
47
|
+
data,
|
|
48
|
+
timestamp: Date.now(),
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
next();
|
|
52
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from "uuid";
|
|
2
|
+
class EnvItemModel {
|
|
3
|
+
constructor(envItem) {
|
|
4
|
+
this.status = "stopped";
|
|
5
|
+
this.id = uuidv4();
|
|
6
|
+
this.name = envItem.name ?? "";
|
|
7
|
+
this.description = envItem.description ?? "";
|
|
8
|
+
this.port = envItem.port ?? "";
|
|
9
|
+
this.apiBaseUrl = envItem.apiBaseUrl ?? "";
|
|
10
|
+
this.homePage = envItem.homePage ?? "";
|
|
11
|
+
this.devServerId = envItem.devServerId ?? "";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export { EnvItemModel };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { getDatabase } from "./database.js";
|
|
2
|
+
import { DevServerDeleteSchema, DevServerUpdateSchema, DevServerQuerySchema, DevServerModelSchema, } from "../types/index.js";
|
|
3
|
+
import { AppError } from "../utils/errors.js";
|
|
4
|
+
/**
|
|
5
|
+
* 开发服务器仓库类
|
|
6
|
+
* 负责开发服务器相关数据的持久化操作,封装数据库交互逻辑
|
|
7
|
+
*/
|
|
8
|
+
class DevServerRepo {
|
|
9
|
+
/**
|
|
10
|
+
* 获取开发服务器数据集合
|
|
11
|
+
* @returns 开发服务器数据集合对象
|
|
12
|
+
*/
|
|
13
|
+
getCollection() {
|
|
14
|
+
return getDatabase().getCollection("devServer");
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 获取所有开发服务器信息
|
|
18
|
+
* @returns 所有开发服务器信息的数组
|
|
19
|
+
*/
|
|
20
|
+
getAll() {
|
|
21
|
+
return this.getCollection().find();
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 添加新的开发服务器
|
|
25
|
+
* @param devServer - 要添加的开发服务器信息(不含ID)
|
|
26
|
+
* @throws {AppError} 当验证失败时抛出错误
|
|
27
|
+
*/
|
|
28
|
+
addDevServer(devServer) {
|
|
29
|
+
// 验证输入数据
|
|
30
|
+
const validationResult = DevServerModelSchema.safeParse(devServer);
|
|
31
|
+
if (!validationResult.success) {
|
|
32
|
+
throw new AppError(`添加开发服务器失败:参数验证错误 - ${JSON.stringify(validationResult.error.issues)}`);
|
|
33
|
+
}
|
|
34
|
+
this.getCollection().insert(validationResult.data);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 根据ID删除开发服务器
|
|
38
|
+
* @param devServer - 包含要删除的开发服务器ID的对象
|
|
39
|
+
* @throws {AppError} 当验证失败或服务器不存在时抛出错误
|
|
40
|
+
*/
|
|
41
|
+
deleteDevServer(devServer) {
|
|
42
|
+
// 验证输入数据
|
|
43
|
+
const validationResult = DevServerDeleteSchema.safeParse(devServer);
|
|
44
|
+
if (!validationResult.success) {
|
|
45
|
+
throw new AppError(`删除开发服务器失败:参数验证错误 - ${JSON.stringify(validationResult.error.issues)}`);
|
|
46
|
+
}
|
|
47
|
+
// 检查服务器是否存在
|
|
48
|
+
const existing = this.findOneById(validationResult.data);
|
|
49
|
+
if (!existing) {
|
|
50
|
+
throw new AppError(`删除开发服务器失败:服务器【${validationResult.data.id}】不存在`);
|
|
51
|
+
}
|
|
52
|
+
this.getCollection().findAndRemove(validationResult.data);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 根据ID查询开发服务器
|
|
56
|
+
* @param devServer - 包含要查询的开发服务器ID的对象
|
|
57
|
+
* @returns 匹配的开发服务器信息,若未找到则返回null
|
|
58
|
+
* @throws {AppError} 当验证失败时抛出错误
|
|
59
|
+
*/
|
|
60
|
+
findOneById(devServer) {
|
|
61
|
+
// 验证输入数据
|
|
62
|
+
const validationResult = DevServerQuerySchema.safeParse(devServer);
|
|
63
|
+
if (!validationResult.success) {
|
|
64
|
+
throw new AppError(`查询开发服务器失败:参数验证错误 - ${JSON.stringify(validationResult.error.issues)}`);
|
|
65
|
+
}
|
|
66
|
+
return this.getCollection().findOne(validationResult.data);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* 根据URL查询开发服务器
|
|
70
|
+
* @param url - 开发服务器URL
|
|
71
|
+
* @returns 匹配的开发服务器信息,若未找到则返回null
|
|
72
|
+
*/
|
|
73
|
+
findOneByUrl(url) {
|
|
74
|
+
return this.getCollection().findOne({ devServerUrl: url });
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 更新开发服务器信息
|
|
78
|
+
* @param devServer - 包含要更新的开发服务器ID及字段的对象
|
|
79
|
+
* @throws {AppError} 当验证失败或服务器不存在时抛出错误
|
|
80
|
+
*/
|
|
81
|
+
update(devServer) {
|
|
82
|
+
// 验证输入数据
|
|
83
|
+
const validationResult = DevServerUpdateSchema.safeParse(devServer);
|
|
84
|
+
if (!validationResult.success) {
|
|
85
|
+
throw new AppError(`更新开发服务器失败:参数验证错误 - ${JSON.stringify(validationResult.error.issues)}`);
|
|
86
|
+
}
|
|
87
|
+
// 检查服务器是否存在
|
|
88
|
+
const existing = this.findOneById({ id: validationResult.data.id });
|
|
89
|
+
if (!existing) {
|
|
90
|
+
throw new AppError(`更新开发服务器失败:服务器【${validationResult.data.id}】不存在`);
|
|
91
|
+
}
|
|
92
|
+
this.getCollection().findAndUpdate({ id: validationResult.data.id }, (server) => {
|
|
93
|
+
if (!server) {
|
|
94
|
+
throw new AppError(`更新开发服务器失败:服务器【${validationResult.data.id}】不存在`);
|
|
95
|
+
}
|
|
96
|
+
Object.assign(server, validationResult.data);
|
|
97
|
+
return server;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export { DevServerRepo };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { AppError } from "../utils/errors.js";
|
|
2
|
+
import { getDatabase } from "./database.js";
|
|
3
|
+
import { EnvDeleteSchema, } from "../types/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* 环境仓库类
|
|
6
|
+
* 负责环境相关数据的持久化操作,封装了数据库交互逻辑
|
|
7
|
+
*/
|
|
8
|
+
class EnvRepo {
|
|
9
|
+
/**
|
|
10
|
+
* 获取环境数据集合
|
|
11
|
+
* @returns 环境数据集合对象
|
|
12
|
+
*/
|
|
13
|
+
getCollection() {
|
|
14
|
+
return getDatabase().getCollection("envms");
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 构造函数
|
|
18
|
+
*/
|
|
19
|
+
constructor() { }
|
|
20
|
+
/**
|
|
21
|
+
* 获取所有环境信息
|
|
22
|
+
* @returns 所有环境信息的数组
|
|
23
|
+
*/
|
|
24
|
+
getAll() {
|
|
25
|
+
return this.getCollection().find();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 添加新环境
|
|
29
|
+
* @param env - 要添加的环境完整信息对象
|
|
30
|
+
*/
|
|
31
|
+
addEnv(env) {
|
|
32
|
+
this.getCollection().insert(env);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 删除指定环境
|
|
36
|
+
* @param env - 包含要删除环境ID的对象
|
|
37
|
+
* @throws {Error} 当验证失败或删除操作出现问题时抛出错误
|
|
38
|
+
*/
|
|
39
|
+
deleteEnv(env) {
|
|
40
|
+
const target = EnvDeleteSchema.safeParse(env);
|
|
41
|
+
if (!target.success) {
|
|
42
|
+
throw new AppError(`删除环境验证失败: ${JSON.stringify(target.error)}`);
|
|
43
|
+
}
|
|
44
|
+
this.getCollection().findAndRemove(target.data);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 根据ID查询环境信息
|
|
48
|
+
* @param env - 包含要查询环境ID的对象
|
|
49
|
+
* @returns 匹配的环境信息对象,若未找到则返回null
|
|
50
|
+
* @throws {Error} 当验证失败时抛出错误
|
|
51
|
+
*/
|
|
52
|
+
findOne(env) {
|
|
53
|
+
return this.getCollection().findOne(env);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 根据ID查询环境信息
|
|
57
|
+
* @param id - 包含要查询环境ID
|
|
58
|
+
* @returns 匹配的环境信息对象,若未找到则返回null
|
|
59
|
+
* @throws {Error} 当验证失败时抛出错误
|
|
60
|
+
*/
|
|
61
|
+
findOneById(id) {
|
|
62
|
+
return this.findOne({
|
|
63
|
+
id,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 根据devServerID查询数据
|
|
68
|
+
* @param devServerId
|
|
69
|
+
* @returns
|
|
70
|
+
*/
|
|
71
|
+
findEnvsByDevServerId(devServerId) {
|
|
72
|
+
return this.getCollection().find({
|
|
73
|
+
devServerId,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 根据状态查询环境
|
|
78
|
+
* @param status - 环境状态(如'running'、'stopped'等)
|
|
79
|
+
* @returns 符合条件的环境数组
|
|
80
|
+
*/
|
|
81
|
+
findAllByStatus(status) {
|
|
82
|
+
return this.getCollection().find({ status });
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* 根据 apiBaseUrl 环境信息查找单个环境 新增前用于判断是否重复
|
|
86
|
+
* @param env 环境信息
|
|
87
|
+
* @returns 匹配的环境信息或 undefined
|
|
88
|
+
*/
|
|
89
|
+
findOneByApiBaseUrl(env) {
|
|
90
|
+
return this.getCollection().findOne({
|
|
91
|
+
apiBaseUrl: env.apiBaseUrl,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* 根据状态和端口查询
|
|
96
|
+
* @param env
|
|
97
|
+
* @returns
|
|
98
|
+
*/
|
|
99
|
+
findOneByPortAndStatus(env) {
|
|
100
|
+
return this.getCollection().findOne({
|
|
101
|
+
port: env.port,
|
|
102
|
+
status: env.status,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 更新环境信息
|
|
107
|
+
* @param envmItem - 包含要更新的环境ID及字段的对象
|
|
108
|
+
* @throws {AppError} 当未找到对应环境时抛出异常
|
|
109
|
+
* @throws {Error} 当更新操作出现问题时抛出错误
|
|
110
|
+
*/
|
|
111
|
+
update(envmItem) {
|
|
112
|
+
this.getCollection().findAndUpdate({ id: envmItem.id }, (env) => {
|
|
113
|
+
if (!env) {
|
|
114
|
+
throw new AppError("未找到对应的环境");
|
|
115
|
+
}
|
|
116
|
+
Object.assign(env, envmItem);
|
|
117
|
+
return env;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
export { EnvRepo };
|