Files
netdisk-fast-download/web-service/src/main/java/cn/qaiu/lz/AppMain.java

195 lines
8.8 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package cn.qaiu.lz;
import cn.qaiu.WebClientVertxInit;
import cn.qaiu.db.pool.JDBCPoolInit;
import cn.qaiu.lz.common.cache.CacheConfigLoader;
import cn.qaiu.lz.common.interceptorImpl.RateLimiter;
import cn.qaiu.lz.web.config.PlaygroundConfig;
import cn.qaiu.lz.web.service.DbService;
import cn.qaiu.parser.custom.CustomParserConfig;
import cn.qaiu.parser.custom.CustomParserRegistry;
import cn.qaiu.parser.customjs.JsScriptMetadataParser;
import cn.qaiu.vx.core.Deploy;
import cn.qaiu.vx.core.util.AsyncServiceUtil;
import cn.qaiu.vx.core.util.ConfigConstant;
import cn.qaiu.vx.core.util.VertxHolder;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.core.json.jackson.DatabindCodec;
import io.vertx.core.shareddata.LocalMap;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Date;
import static cn.qaiu.vx.core.util.ConfigConstant.LOCAL;
/**
* vertx程序入口
*
* <br>Create date 2021-05-08 13:00:01
* @author qaiu yyzy
*/
@Slf4j
public class AppMain {
public static void main(String[] args) {
// 先注册 ShutdownHookJVM 逆序执行,先注册的后执行)
// 确保关闭顺序Vert.x -> JDBCPoolInit -> JsParserExecutor
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
JDBCPoolInit.instance().close();
} catch (Exception e) {
// ignore
}
try {
cn.qaiu.parser.customjs.JsParserExecutor.shutdownExecutor();
} catch (Exception e) {
// ignore
}
}));
// start
Deploy.instance().start(args, AppMain::exec);
}
/**
* 框架回调方法
* 初始化数据库/缓存等
*
* @param jsonObject 配置
*/
private static void exec(JsonObject jsonObject) {
WebClientVertxInit.init(VertxHolder.getVertxInstance());
DatabindCodec.mapper().registerModule(new JavaTimeModule());
// 限流
if (jsonObject.containsKey("rateLimit")) {
JsonObject rateLimit = jsonObject.getJsonObject("rateLimit");
RateLimiter.init(rateLimit);
}
// 数据库
if (jsonObject.getJsonObject(ConfigConstant.SERVER).getBoolean("enableDatabase")) {
JDBCPoolInit.builder().config(jsonObject.getJsonObject("dataSource"))
.build()
.initPool().onSuccess(PreparedStatement -> {
VertxHolder.getVertxInstance().setTimer(1000, id -> {
System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS"));
System.out.println("数据库连接成功");
// 加载演练场解析器
String addr = jsonObject.getJsonObject(ConfigConstant.SERVER).getString("domainName");
if (addr == null || addr.isBlank()) {
addr = "http://127.0.0.1:" + jsonObject.getJsonObject(ConfigConstant.SERVER).getInteger("port", 6400);
}
// 读取代理配置获取前端页面端口(同步读文件,避免阻塞 event loop
String proxyConfName = jsonObject.getString("proxyConf", "server-proxy");
String pageAddr = addr;
try {
String configFile = proxyConfName + ".yml";
Path configPath = Path.of("resources", configFile);
if (!Files.exists(configPath)) {
configPath = Path.of(configFile);
}
if (Files.exists(configPath)) {
String yamlContent = Files.readString(configPath);
java.util.regex.Matcher m = java.util.regex.Pattern
.compile("^\\s*-\\s+listen:\\s*(\\d+)", java.util.regex.Pattern.MULTILINE)
.matcher(yamlContent);
if (m.find()) {
int pagePort = Integer.parseInt(m.group(1));
pageAddr = "http://127.0.0.1:" + pagePort;
}
}
} catch (Exception e) {
log.warn("读取代理配置失败,使用默认页面地址: {}", e.getMessage());
}
loadPlaygroundParsers(pageAddr);
System.out.println("启动成功: \n本地服务地址: " + addr);
});
});
}
// 缓存
if (jsonObject.containsKey(ConfigConstant.CACHE)) {
CacheConfigLoader.init(jsonObject.getJsonObject(ConfigConstant.CACHE));
}
LocalMap<Object, Object> localMap = VertxHolder.getVertxInstance().sharedData().getLocalMap(LOCAL);
// 代理
if (jsonObject.containsKey(ConfigConstant.PROXY)) {
JsonArray proxyJsonArray = jsonObject.getJsonArray(ConfigConstant.PROXY);
if (proxyJsonArray != null) {
JsonObject jsonObject1 = new JsonObject();
proxyJsonArray.forEach(proxyJson -> {
String panTypes = ((JsonObject)proxyJson).getString("panTypes");
if (!panTypes.isEmpty()) {
for (String s : panTypes.split(",")) {
jsonObject1.put(s, proxyJson);
}
}
});
localMap.put("proxy", jsonObject1);
}
}
// 认证
if (jsonObject.containsKey(ConfigConstant.AUTHS)) {
JsonObject auths = jsonObject.getJsonObject(ConfigConstant.AUTHS);
localMap.put(ConfigConstant.AUTHS, auths);
}
// 演练场配置
PlaygroundConfig.loadFromJson(jsonObject);
}
/**
* 在启动时加载所有已发布的演练场解析器
*/
private static void loadPlaygroundParsers(String accessAddr) {
DbService dbService = AsyncServiceUtil.getAsyncServiceInstance(DbService.class);
dbService.getPlaygroundParserList().onSuccess(result -> {
JsonArray parsers = result.getJsonArray("data");
if (parsers != null) {
int loadedCount = 0;
for (int i = 0; i < parsers.size(); i++) {
JsonObject parser = parsers.getJsonObject(i);
// 只注册已启用的解析器
if (parser.getBoolean("enabled", false)) {
try {
String jsCode = parser.getString("jsCode");
if (jsCode == null || jsCode.trim().isEmpty()) {
log.error("加载演练场解析器失败: {} - JavaScript代码为空", parser.getString("name"));
continue;
}
CustomParserConfig config = JsScriptMetadataParser.parseScript(jsCode);
CustomParserRegistry.register(config);
loadedCount++;
log.info("已加载演练场解析器: {} ({})",
config.getDisplayName(), config.getType());
} catch (Exception e) {
String parserName = parser.getString("name");
String errorMsg = e.getMessage();
log.error("加载演练场解析器失败: {} - {}", parserName, errorMsg, e);
// 如果是require相关错误提供更详细的提示
if (errorMsg != null && errorMsg.contains("require")) {
log.error("提示演练场解析器不支持CommonJS模块系统require请确保代码使用ES5.1语法");
}
}
}
}
log.info("演练场解析器加载完成,共加载 {} 个解析器", loadedCount);
} else {
log.info("未找到已发布的演练场解析器");
}
log.info("服务已启动,可通过 {} 访问页面", accessAddr);
}).onFailure(e -> {
log.error("加载演练场解析器列表失败", e);
});
}
}