mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2026-06-11 07:57:28 +00:00
js演练场
This commit is contained in:
@@ -0,0 +1,436 @@
|
||||
package cn.qaiu.lz.web.controller;
|
||||
|
||||
import cn.qaiu.entity.ShareLinkInfo;
|
||||
import cn.qaiu.lz.web.model.PlaygroundTestResp;
|
||||
import cn.qaiu.lz.web.service.DbService;
|
||||
import cn.qaiu.parser.ParserCreate;
|
||||
import cn.qaiu.parser.customjs.JsPlaygroundExecutor;
|
||||
import cn.qaiu.parser.customjs.JsPlaygroundLogger;
|
||||
import cn.qaiu.parser.customjs.JsScriptMetadataParser;
|
||||
import cn.qaiu.vx.core.annotaions.RouteHandler;
|
||||
import cn.qaiu.vx.core.annotaions.RouteMapping;
|
||||
import cn.qaiu.vx.core.enums.RouteMethod;
|
||||
import cn.qaiu.vx.core.model.JsonResult;
|
||||
import cn.qaiu.vx.core.util.AsyncServiceUtil;
|
||||
import cn.qaiu.vx.core.util.ResponseUtil;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.http.HttpServerRequest;
|
||||
import io.vertx.core.http.HttpServerResponse;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 演练场API控制器
|
||||
* 提供JavaScript解析脚本的测试接口
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
@RouteHandler(value = "/v2/playground", order = 10)
|
||||
@Slf4j
|
||||
public class PlaygroundApi {
|
||||
|
||||
private static final int MAX_PARSER_COUNT = 100;
|
||||
private final DbService dbService = AsyncServiceUtil.getAsyncServiceInstance(DbService.class);
|
||||
|
||||
/**
|
||||
* 测试执行JavaScript代码
|
||||
*
|
||||
* @param ctx 路由上下文
|
||||
* @return 测试结果
|
||||
*/
|
||||
@RouteMapping(value = "/test", method = RouteMethod.POST)
|
||||
public Future<JsonObject> test(RoutingContext ctx) {
|
||||
Promise<JsonObject> promise = Promise.promise();
|
||||
|
||||
try {
|
||||
JsonObject body = ctx.body().asJsonObject();
|
||||
String jsCode = body.getString("jsCode");
|
||||
String shareUrl = body.getString("shareUrl");
|
||||
String pwd = body.getString("pwd");
|
||||
String method = body.getString("method", "parse");
|
||||
|
||||
// 参数验证
|
||||
if (StringUtils.isBlank(jsCode)) {
|
||||
promise.complete(JsonObject.mapFrom(PlaygroundTestResp.builder()
|
||||
.success(false)
|
||||
.error("JavaScript代码不能为空")
|
||||
.build()));
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(shareUrl)) {
|
||||
promise.complete(JsonObject.mapFrom(PlaygroundTestResp.builder()
|
||||
.success(false)
|
||||
.error("分享链接不能为空")
|
||||
.build()));
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
// 验证方法类型
|
||||
if (!"parse".equals(method) && !"parseFileList".equals(method) && !"parseById".equals(method)) {
|
||||
promise.complete(JsonObject.mapFrom(PlaygroundTestResp.builder()
|
||||
.success(false)
|
||||
.error("方法类型无效,必须是 parse、parseFileList 或 parseById")
|
||||
.build()));
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
// 创建ShareLinkInfo
|
||||
ParserCreate parserCreate = ParserCreate.fromShareUrl(shareUrl);
|
||||
if (StringUtils.isNotBlank(pwd)) {
|
||||
parserCreate.setShareLinkInfoPwd(pwd);
|
||||
}
|
||||
ShareLinkInfo shareLinkInfo = parserCreate.getShareLinkInfo();
|
||||
|
||||
// 创建演练场执行器
|
||||
JsPlaygroundExecutor executor = new JsPlaygroundExecutor(shareLinkInfo, jsCode);
|
||||
|
||||
// 根据方法类型选择执行,并异步处理结果
|
||||
Future<Object> executionFuture;
|
||||
switch (method) {
|
||||
case "parse":
|
||||
executionFuture = executor.executeParseAsync().map(r -> (Object) r);
|
||||
break;
|
||||
case "parseFileList":
|
||||
executionFuture = executor.executeParseFileListAsync().map(r -> (Object) r);
|
||||
break;
|
||||
case "parseById":
|
||||
executionFuture = executor.executeParseByIdAsync().map(r -> (Object) r);
|
||||
break;
|
||||
default:
|
||||
promise.fail(new IllegalArgumentException("未知的方法类型: " + method));
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
// 异步处理执行结果
|
||||
executionFuture.onSuccess(result -> {
|
||||
log.debug("执行成功,结果类型: {}, 结果值: {}",
|
||||
result != null ? result.getClass().getSimpleName() : "null",
|
||||
result);
|
||||
|
||||
// 获取日志
|
||||
List<JsPlaygroundLogger.LogEntry> logEntries = executor.getLogs();
|
||||
log.debug("获取到 {} 条日志记录", logEntries.size());
|
||||
|
||||
List<PlaygroundTestResp.LogEntry> respLogs = logEntries.stream()
|
||||
.map(entry -> PlaygroundTestResp.LogEntry.builder()
|
||||
.level(entry.getLevel())
|
||||
.message(entry.getMessage())
|
||||
.timestamp(entry.getTimestamp())
|
||||
.source(entry.getSource()) // 使用日志条目的来源标识
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
long executionTime = System.currentTimeMillis() - startTime;
|
||||
|
||||
// 构建响应
|
||||
PlaygroundTestResp response = PlaygroundTestResp.builder()
|
||||
.success(true)
|
||||
.result(result)
|
||||
.logs(respLogs)
|
||||
.executionTime(executionTime)
|
||||
.build();
|
||||
|
||||
JsonObject jsonResponse = JsonObject.mapFrom(response);
|
||||
log.debug("测试成功响应: {}", jsonResponse.encodePrettily());
|
||||
promise.complete(jsonResponse);
|
||||
}).onFailure(e -> {
|
||||
long executionTime = System.currentTimeMillis() - startTime;
|
||||
String errorMessage = e.getMessage();
|
||||
String stackTrace = getStackTrace(e);
|
||||
|
||||
log.error("演练场执行失败", e);
|
||||
|
||||
// 尝试获取已有的日志
|
||||
List<JsPlaygroundLogger.LogEntry> logEntries = executor.getLogs();
|
||||
List<PlaygroundTestResp.LogEntry> respLogs = logEntries.stream()
|
||||
.map(entry -> PlaygroundTestResp.LogEntry.builder()
|
||||
.level(entry.getLevel())
|
||||
.message(entry.getMessage())
|
||||
.timestamp(entry.getTimestamp())
|
||||
.source(entry.getSource()) // 使用日志条目的来源标识
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
PlaygroundTestResp response = PlaygroundTestResp.builder()
|
||||
.success(false)
|
||||
.error(errorMessage)
|
||||
.stackTrace(stackTrace)
|
||||
.executionTime(executionTime)
|
||||
.logs(respLogs)
|
||||
.build();
|
||||
|
||||
promise.complete(JsonObject.mapFrom(response));
|
||||
});
|
||||
|
||||
} catch (Exception e) {
|
||||
long executionTime = System.currentTimeMillis() - startTime;
|
||||
String errorMessage = e.getMessage();
|
||||
String stackTrace = getStackTrace(e);
|
||||
|
||||
log.error("演练场初始化失败", e);
|
||||
|
||||
PlaygroundTestResp response = PlaygroundTestResp.builder()
|
||||
.success(false)
|
||||
.error(errorMessage)
|
||||
.stackTrace(stackTrace)
|
||||
.executionTime(executionTime)
|
||||
.logs(new ArrayList<>())
|
||||
.build();
|
||||
|
||||
promise.complete(JsonObject.mapFrom(response));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析请求参数失败", e);
|
||||
promise.complete(JsonObject.mapFrom(PlaygroundTestResp.builder()
|
||||
.success(false)
|
||||
.error("解析请求参数失败: " + e.getMessage())
|
||||
.stackTrace(getStackTrace(e))
|
||||
.build()));
|
||||
}
|
||||
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取types.js文件内容
|
||||
*
|
||||
* @param response HTTP响应
|
||||
*/
|
||||
@RouteMapping(value = "/types.js", method = RouteMethod.GET)
|
||||
public void getTypesJs(HttpServerResponse response) {
|
||||
try (InputStream inputStream = getClass().getClassLoader()
|
||||
.getResourceAsStream("custom-parsers/types.js")) {
|
||||
|
||||
if (inputStream == null) {
|
||||
ResponseUtil.fireJsonResultResponse(response, JsonResult.error("types.js文件不存在"));
|
||||
return;
|
||||
}
|
||||
|
||||
String content = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))
|
||||
.lines()
|
||||
.collect(Collectors.joining("\n"));
|
||||
|
||||
response.putHeader("Content-Type", "text/javascript; charset=utf-8")
|
||||
.end(content);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("读取types.js失败", e);
|
||||
ResponseUtil.fireJsonResultResponse(response, JsonResult.error("读取types.js失败: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取解析器列表
|
||||
*/
|
||||
@RouteMapping(value = "/parsers", method = RouteMethod.GET)
|
||||
public Future<JsonObject> getParserList() {
|
||||
return dbService.getPlaygroundParserList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存解析器
|
||||
*/
|
||||
@RouteMapping(value = "/parsers", method = RouteMethod.POST)
|
||||
public Future<JsonObject> saveParser(RoutingContext ctx) {
|
||||
Promise<JsonObject> promise = Promise.promise();
|
||||
|
||||
try {
|
||||
JsonObject body = ctx.body().asJsonObject();
|
||||
String jsCode = body.getString("jsCode");
|
||||
|
||||
if (StringUtils.isBlank(jsCode)) {
|
||||
promise.complete(JsonResult.error("JavaScript代码不能为空").toJsonObject());
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
// 解析元数据
|
||||
try {
|
||||
var config = JsScriptMetadataParser.parseScript(jsCode);
|
||||
String type = config.getType();
|
||||
String displayName = config.getDisplayName();
|
||||
String name = config.getMetadata().get("name");
|
||||
String description = config.getMetadata().get("description");
|
||||
String author = config.getMetadata().get("author");
|
||||
String version = config.getMetadata().get("version");
|
||||
String matchPattern = config.getMatchPattern() != null ? config.getMatchPattern().pattern() : null;
|
||||
|
||||
// 检查数量限制
|
||||
dbService.getPlaygroundParserCount().onSuccess(count -> {
|
||||
if (count >= MAX_PARSER_COUNT) {
|
||||
promise.complete(JsonResult.error("解析器数量已达到上限(" + MAX_PARSER_COUNT + "个),请先删除不需要的解析器").toJsonObject());
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查type是否已存在
|
||||
dbService.getPlaygroundParserList().onSuccess(listResult -> {
|
||||
var list = listResult.getJsonArray("data");
|
||||
boolean exists = false;
|
||||
if (list != null) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
var item = list.getJsonObject(i);
|
||||
if (type.equals(item.getString("type"))) {
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
promise.complete(JsonResult.error("解析器类型 " + type + " 已存在,请使用其他类型标识").toJsonObject());
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存到数据库
|
||||
JsonObject parser = new JsonObject();
|
||||
parser.put("name", name);
|
||||
parser.put("type", type);
|
||||
parser.put("displayName", displayName);
|
||||
parser.put("description", description);
|
||||
parser.put("author", author);
|
||||
parser.put("version", version);
|
||||
parser.put("matchPattern", matchPattern);
|
||||
parser.put("jsCode", jsCode);
|
||||
parser.put("ip", getClientIp(ctx.request()));
|
||||
parser.put("enabled", true);
|
||||
|
||||
dbService.savePlaygroundParser(parser).onSuccess(result -> {
|
||||
promise.complete(result);
|
||||
}).onFailure(e -> {
|
||||
log.error("保存解析器失败", e);
|
||||
promise.complete(JsonResult.error("保存失败: " + e.getMessage()).toJsonObject());
|
||||
});
|
||||
}).onFailure(e -> {
|
||||
log.error("获取解析器列表失败", e);
|
||||
promise.complete(JsonResult.error("检查解析器失败: " + e.getMessage()).toJsonObject());
|
||||
});
|
||||
}).onFailure(e -> {
|
||||
log.error("获取解析器数量失败", e);
|
||||
promise.complete(JsonResult.error("检查解析器数量失败: " + e.getMessage()).toJsonObject());
|
||||
});
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("解析脚本元数据失败", e);
|
||||
promise.complete(JsonResult.error("解析脚本元数据失败: " + e.getMessage()).toJsonObject());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析请求参数失败", e);
|
||||
promise.complete(JsonResult.error("解析请求参数失败: " + e.getMessage()).toJsonObject());
|
||||
}
|
||||
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新解析器
|
||||
*/
|
||||
@RouteMapping(value = "/parsers/:id", method = RouteMethod.PUT)
|
||||
public Future<JsonObject> updateParser(RoutingContext ctx, Long id) {
|
||||
Promise<JsonObject> promise = Promise.promise();
|
||||
|
||||
try {
|
||||
JsonObject body = ctx.body().asJsonObject();
|
||||
String jsCode = body.getString("jsCode");
|
||||
|
||||
if (StringUtils.isBlank(jsCode)) {
|
||||
promise.complete(JsonResult.error("JavaScript代码不能为空").toJsonObject());
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
// 解析元数据
|
||||
try {
|
||||
var config = JsScriptMetadataParser.parseScript(jsCode);
|
||||
String displayName = config.getDisplayName();
|
||||
String name = config.getMetadata().get("name");
|
||||
String description = config.getMetadata().get("description");
|
||||
String author = config.getMetadata().get("author");
|
||||
String version = config.getMetadata().get("version");
|
||||
String matchPattern = config.getMatchPattern() != null ? config.getMatchPattern().pattern() : null;
|
||||
|
||||
JsonObject parser = new JsonObject();
|
||||
parser.put("name", name);
|
||||
parser.put("displayName", displayName);
|
||||
parser.put("description", description);
|
||||
parser.put("author", author);
|
||||
parser.put("version", version);
|
||||
parser.put("matchPattern", matchPattern);
|
||||
parser.put("jsCode", jsCode);
|
||||
parser.put("enabled", body.getBoolean("enabled", true));
|
||||
|
||||
dbService.updatePlaygroundParser(id, parser).onSuccess(result -> {
|
||||
promise.complete(result);
|
||||
}).onFailure(e -> {
|
||||
log.error("更新解析器失败", e);
|
||||
promise.complete(JsonResult.error("更新失败: " + e.getMessage()).toJsonObject());
|
||||
});
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("解析脚本元数据失败", e);
|
||||
promise.complete(JsonResult.error("解析脚本元数据失败: " + e.getMessage()).toJsonObject());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析请求参数失败", e);
|
||||
promise.complete(JsonResult.error("解析请求参数失败: " + e.getMessage()).toJsonObject());
|
||||
}
|
||||
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除解析器
|
||||
*/
|
||||
@RouteMapping(value = "/parsers/:id", method = RouteMethod.DELETE)
|
||||
public Future<JsonObject> deleteParser(Long id) {
|
||||
return dbService.deletePlaygroundParser(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取解析器
|
||||
*/
|
||||
@RouteMapping(value = "/parsers/:id", method = RouteMethod.GET)
|
||||
public Future<JsonObject> getParserById(Long id) {
|
||||
return dbService.getPlaygroundParserById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端IP
|
||||
*/
|
||||
private String getClientIp(HttpServerRequest request) {
|
||||
String ip = request.getHeader("X-Forwarded-For");
|
||||
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("X-Real-IP");
|
||||
}
|
||||
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.remoteAddress().host();
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取异常堆栈信息
|
||||
*/
|
||||
private String getStackTrace(Throwable throwable) {
|
||||
if (throwable == null) {
|
||||
return "";
|
||||
}
|
||||
java.io.StringWriter sw = new java.io.StringWriter();
|
||||
java.io.PrintWriter pw = new java.io.PrintWriter(sw);
|
||||
throwable.printStackTrace(pw);
|
||||
return sw.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package cn.qaiu.lz.web.model;
|
||||
|
||||
import cn.qaiu.db.ddl.Constraint;
|
||||
import cn.qaiu.db.ddl.Length;
|
||||
import cn.qaiu.db.ddl.Table;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 演练场解析器实体
|
||||
* 用于保存用户创建的临时JS解析器
|
||||
*/
|
||||
@Data
|
||||
@Table("playground_parser")
|
||||
public class PlaygroundParser {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Constraint(autoIncrement = true, notNull = true)
|
||||
private Long id;
|
||||
|
||||
@Length(varcharSize = 64)
|
||||
@Constraint(notNull = true)
|
||||
private String name; // 解析器名称
|
||||
|
||||
@Length(varcharSize = 64)
|
||||
@Constraint(notNull = true, uniqueKey = "uk_type")
|
||||
private String type; // 解析器类型标识(唯一)
|
||||
|
||||
@Length(varcharSize = 128)
|
||||
private String displayName; // 显示名称
|
||||
|
||||
@Length(varcharSize = 512)
|
||||
private String description; // 描述
|
||||
|
||||
@Length(varcharSize = 64)
|
||||
private String author; // 作者
|
||||
|
||||
@Length(varcharSize = 32)
|
||||
private String version; // 版本号
|
||||
|
||||
@Length(varcharSize = 512)
|
||||
private String matchPattern; // URL匹配正则
|
||||
|
||||
@Length(varcharSize = 65535)
|
||||
@Constraint(notNull = true)
|
||||
private String jsCode; // JavaScript代码
|
||||
|
||||
@Length(varcharSize = 64)
|
||||
private String ip; // 创建者IP
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date createTime = new Date(); // 创建时间
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date updateTime; // 更新时间
|
||||
|
||||
private Boolean enabled = true; // 是否启用
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package cn.qaiu.lz.web.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 演练场测试响应模型
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class PlaygroundTestResp {
|
||||
/**
|
||||
* 是否执行成功
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* 执行结果(根据方法类型返回不同格式)
|
||||
* - parse: String (下载链接)
|
||||
* - parseFileList: List<FileInfo>
|
||||
* - parseById: String (下载链接)
|
||||
*/
|
||||
private Object result;
|
||||
|
||||
/**
|
||||
* 执行日志列表
|
||||
*/
|
||||
private List<LogEntry> logs;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String error;
|
||||
|
||||
/**
|
||||
* 错误堆栈
|
||||
*/
|
||||
private String stackTrace;
|
||||
|
||||
/**
|
||||
* 执行时间(毫秒)
|
||||
*/
|
||||
private long executionTime;
|
||||
|
||||
/**
|
||||
* 日志条目
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public static class LogEntry {
|
||||
/**
|
||||
* 日志级别:DEBUG, INFO, WARN, ERROR
|
||||
*/
|
||||
private String level;
|
||||
|
||||
/**
|
||||
* 日志消息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 日志时间戳
|
||||
*/
|
||||
private long timestamp;
|
||||
|
||||
/**
|
||||
* 日志来源:JS(JavaScript日志)或 JAVA(Java日志)
|
||||
*/
|
||||
private String source;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,4 +20,34 @@ public interface DbService extends BaseAsyncService {
|
||||
|
||||
Future<StatisticsInfo> getStatisticsInfo();
|
||||
|
||||
/**
|
||||
* 获取演练场解析器列表
|
||||
*/
|
||||
Future<JsonObject> getPlaygroundParserList();
|
||||
|
||||
/**
|
||||
* 保存演练场解析器
|
||||
*/
|
||||
Future<JsonObject> savePlaygroundParser(JsonObject parser);
|
||||
|
||||
/**
|
||||
* 更新演练场解析器
|
||||
*/
|
||||
Future<JsonObject> updatePlaygroundParser(Long id, JsonObject parser);
|
||||
|
||||
/**
|
||||
* 删除演练场解析器
|
||||
*/
|
||||
Future<JsonObject> deletePlaygroundParser(Long id);
|
||||
|
||||
/**
|
||||
* 获取演练场解析器数量
|
||||
*/
|
||||
Future<Integer> getPlaygroundParserCount();
|
||||
|
||||
/**
|
||||
* 根据ID获取演练场解析器
|
||||
*/
|
||||
Future<JsonObject> getPlaygroundParserById(Long id);
|
||||
|
||||
}
|
||||
|
||||
@@ -10,10 +10,14 @@ import io.vertx.core.Future;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.jdbcclient.JDBCPool;
|
||||
import io.vertx.sqlclient.Row;
|
||||
import io.vertx.sqlclient.Tuple;
|
||||
import io.vertx.sqlclient.templates.SqlTemplate;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* lz-web
|
||||
@@ -66,4 +70,199 @@ public class DbServiceImpl implements DbService {
|
||||
});
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<JsonObject> getPlaygroundParserList() {
|
||||
JDBCPool client = JDBCPoolInit.instance().getPool();
|
||||
Promise<JsonObject> promise = Promise.promise();
|
||||
String sql = "SELECT * FROM playground_parser ORDER BY create_time DESC";
|
||||
|
||||
client.query(sql).execute().onSuccess(rows -> {
|
||||
List<JsonObject> list = new ArrayList<>();
|
||||
for (Row row : rows) {
|
||||
JsonObject parser = new JsonObject();
|
||||
parser.put("id", row.getLong("id"));
|
||||
parser.put("name", row.getString("name"));
|
||||
parser.put("type", row.getString("type"));
|
||||
parser.put("displayName", row.getString("display_name"));
|
||||
parser.put("description", row.getString("description"));
|
||||
parser.put("author", row.getString("author"));
|
||||
parser.put("version", row.getString("version"));
|
||||
parser.put("matchPattern", row.getString("match_pattern"));
|
||||
parser.put("jsCode", row.getString("js_code"));
|
||||
parser.put("ip", row.getString("ip"));
|
||||
// 将LocalDateTime转换为字符串格式,避免序列化为数组
|
||||
var createTime = row.getLocalDateTime("create_time");
|
||||
if (createTime != null) {
|
||||
parser.put("createTime", createTime.toString().replace("T", " "));
|
||||
}
|
||||
var updateTime = row.getLocalDateTime("update_time");
|
||||
if (updateTime != null) {
|
||||
parser.put("updateTime", updateTime.toString().replace("T", " "));
|
||||
}
|
||||
parser.put("enabled", row.getBoolean("enabled"));
|
||||
list.add(parser);
|
||||
}
|
||||
promise.complete(JsonResult.data(list).toJsonObject());
|
||||
}).onFailure(e -> {
|
||||
log.error("getPlaygroundParserList failed", e);
|
||||
promise.fail(e);
|
||||
});
|
||||
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<JsonObject> savePlaygroundParser(JsonObject parser) {
|
||||
JDBCPool client = JDBCPoolInit.instance().getPool();
|
||||
Promise<JsonObject> promise = Promise.promise();
|
||||
|
||||
String sql = """
|
||||
INSERT INTO playground_parser
|
||||
(name, type, display_name, description, author, version, match_pattern, js_code, ip, create_time, enabled)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), ?)
|
||||
""";
|
||||
|
||||
client.preparedQuery(sql)
|
||||
.execute(Tuple.of(
|
||||
parser.getString("name"),
|
||||
parser.getString("type"),
|
||||
parser.getString("displayName"),
|
||||
parser.getString("description"),
|
||||
parser.getString("author"),
|
||||
parser.getString("version"),
|
||||
parser.getString("matchPattern"),
|
||||
parser.getString("jsCode"),
|
||||
parser.getString("ip"),
|
||||
parser.getBoolean("enabled", true)
|
||||
))
|
||||
.onSuccess(res -> {
|
||||
promise.complete(JsonResult.success("保存成功").toJsonObject());
|
||||
})
|
||||
.onFailure(e -> {
|
||||
log.error("savePlaygroundParser failed", e);
|
||||
promise.fail(e);
|
||||
});
|
||||
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<JsonObject> updatePlaygroundParser(Long id, JsonObject parser) {
|
||||
JDBCPool client = JDBCPoolInit.instance().getPool();
|
||||
Promise<JsonObject> promise = Promise.promise();
|
||||
|
||||
String sql = """
|
||||
UPDATE playground_parser
|
||||
SET name = ?, display_name = ?, description = ?, author = ?,
|
||||
version = ?, match_pattern = ?, js_code = ?, update_time = NOW(), enabled = ?
|
||||
WHERE id = ?
|
||||
""";
|
||||
|
||||
client.preparedQuery(sql)
|
||||
.execute(Tuple.of(
|
||||
parser.getString("name"),
|
||||
parser.getString("displayName"),
|
||||
parser.getString("description"),
|
||||
parser.getString("author"),
|
||||
parser.getString("version"),
|
||||
parser.getString("matchPattern"),
|
||||
parser.getString("jsCode"),
|
||||
parser.getBoolean("enabled", true),
|
||||
id
|
||||
))
|
||||
.onSuccess(res -> {
|
||||
promise.complete(JsonResult.success("更新成功").toJsonObject());
|
||||
})
|
||||
.onFailure(e -> {
|
||||
log.error("updatePlaygroundParser failed", e);
|
||||
promise.fail(e);
|
||||
});
|
||||
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<JsonObject> deletePlaygroundParser(Long id) {
|
||||
JDBCPool client = JDBCPoolInit.instance().getPool();
|
||||
Promise<JsonObject> promise = Promise.promise();
|
||||
|
||||
String sql = "DELETE FROM playground_parser WHERE id = ?";
|
||||
|
||||
client.preparedQuery(sql)
|
||||
.execute(Tuple.of(id))
|
||||
.onSuccess(res -> {
|
||||
promise.complete(JsonResult.success("删除成功").toJsonObject());
|
||||
})
|
||||
.onFailure(e -> {
|
||||
log.error("deletePlaygroundParser failed", e);
|
||||
promise.fail(e);
|
||||
});
|
||||
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Integer> getPlaygroundParserCount() {
|
||||
JDBCPool client = JDBCPoolInit.instance().getPool();
|
||||
Promise<Integer> promise = Promise.promise();
|
||||
|
||||
String sql = "SELECT COUNT(*) as count FROM playground_parser";
|
||||
|
||||
client.query(sql).execute().onSuccess(rows -> {
|
||||
Integer count = rows.iterator().next().getInteger("count");
|
||||
promise.complete(count);
|
||||
}).onFailure(e -> {
|
||||
log.error("getPlaygroundParserCount failed", e);
|
||||
promise.fail(e);
|
||||
});
|
||||
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<JsonObject> getPlaygroundParserById(Long id) {
|
||||
JDBCPool client = JDBCPoolInit.instance().getPool();
|
||||
Promise<JsonObject> promise = Promise.promise();
|
||||
|
||||
String sql = "SELECT * FROM playground_parser WHERE id = ?";
|
||||
|
||||
client.preparedQuery(sql)
|
||||
.execute(Tuple.of(id))
|
||||
.onSuccess(rows -> {
|
||||
if (rows.size() > 0) {
|
||||
Row row = rows.iterator().next();
|
||||
JsonObject parser = new JsonObject();
|
||||
parser.put("id", row.getLong("id"));
|
||||
parser.put("name", row.getString("name"));
|
||||
parser.put("type", row.getString("type"));
|
||||
parser.put("displayName", row.getString("display_name"));
|
||||
parser.put("description", row.getString("description"));
|
||||
parser.put("author", row.getString("author"));
|
||||
parser.put("version", row.getString("version"));
|
||||
parser.put("matchPattern", row.getString("match_pattern"));
|
||||
parser.put("jsCode", row.getString("js_code"));
|
||||
parser.put("ip", row.getString("ip"));
|
||||
// 将LocalDateTime转换为字符串格式,避免序列化为数组
|
||||
var createTime = row.getLocalDateTime("create_time");
|
||||
if (createTime != null) {
|
||||
parser.put("createTime", createTime.toString().replace("T", " "));
|
||||
}
|
||||
var updateTime = row.getLocalDateTime("update_time");
|
||||
if (updateTime != null) {
|
||||
parser.put("updateTime", updateTime.toString().replace("T", " "));
|
||||
}
|
||||
parser.put("enabled", row.getBoolean("enabled"));
|
||||
promise.complete(JsonResult.data(parser).toJsonObject());
|
||||
} else {
|
||||
promise.fail("解析器不存在");
|
||||
}
|
||||
})
|
||||
.onFailure(e -> {
|
||||
log.error("getPlaygroundParserById failed", e);
|
||||
promise.fail(e);
|
||||
});
|
||||
|
||||
return promise.future();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user