修改XNEngine支持数据库读取,还未完成
This commit is contained in:
parent
88d2ffb032
commit
7da7a8a5ee
Binary file not shown.
@ -15,6 +15,7 @@ endif()
|
|||||||
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
find_package(OpenSSL REQUIRED)
|
find_package(OpenSSL REQUIRED)
|
||||||
|
find_package(SQLite3 REQUIRED)
|
||||||
|
|
||||||
add_executable(XNEngine
|
add_executable(XNEngine
|
||||||
main.cpp
|
main.cpp
|
||||||
@ -30,6 +31,7 @@ target_link_libraries(XNEngine PRIVATE
|
|||||||
pthread
|
pthread
|
||||||
OpenSSL::SSL
|
OpenSSL::SSL
|
||||||
OpenSSL::Crypto
|
OpenSSL::Crypto
|
||||||
|
sqlite3
|
||||||
dl
|
dl
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "../XNCore/XNServiceManager.h"
|
#include "../XNCore/XNServiceManager.h"
|
||||||
#include "../XNCore/XNModelManager.h"
|
#include "../XNCore/XNModelManager.h"
|
||||||
#include "../XNCore/XNScenarioManager.h"
|
#include "../XNCore/XNScenarioManager.h"
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
// 引擎类构造函数
|
// 引擎类构造函数
|
||||||
XNEngine::XNEngine()
|
XNEngine::XNEngine()
|
||||||
@ -55,35 +56,42 @@ void XNEngine::SimControlListener(const XNSim::XNSimControl::XNRuntimeControl &c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置日志级别
|
// 解析配置文件
|
||||||
bool XNEngine::SetLogLevel(const std::string &XmlPath)
|
bool XNEngine::ParseConfig(const std::string &XmlPath)
|
||||||
{
|
{
|
||||||
|
size_t index = XmlPath.find_last_of('.');
|
||||||
|
if (index != std::string::npos) {
|
||||||
|
std::string suffix = XmlPath.substr(index);
|
||||||
|
if (suffix != ".xml" && suffix != ".sce") {
|
||||||
|
std::cerr << "0x1005 配置文件不是 .xml 或 .sce 文件, 引擎将退出!" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cerr << "0x1006 配置文件没有 .xml 或 .sce 的后缀名, 引擎将退出!" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// 打开配置文件
|
// 打开配置文件
|
||||||
std::ifstream file(XmlPath);
|
std::ifstream file(XmlPath);
|
||||||
if (!file.is_open()) {
|
if (!file.is_open()) {
|
||||||
std::cerr << "0x1003 Failed to open the runtime environment configuration file, "
|
std::cerr << "0x1007 打开配置文件失败, 引擎将退出!" << std::endl;
|
||||||
"the engine will exit!"
|
|
||||||
<< std::endl;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 解析配置文件
|
// 解析配置文件
|
||||||
tinyxml2::XMLDocument doc;
|
tinyxml2::XMLDocument doc;
|
||||||
if (doc.LoadFile(XmlPath.c_str()) != tinyxml2::XML_SUCCESS) {
|
if (doc.LoadFile(XmlPath.c_str()) != tinyxml2::XML_SUCCESS) {
|
||||||
std::cerr << "0x1004 Failed to parse the runtime environment configuration file, "
|
std::cerr << "0x1008 解析配置文件失败, 引擎将退出!" << std::endl;
|
||||||
"the engine will exit!"
|
|
||||||
<< std::endl;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 获取根元素
|
// 获取根元素
|
||||||
tinyxml2::XMLElement *root = doc.FirstChildElement("Scenario");
|
tinyxml2::XMLElement *root = doc.FirstChildElement("Scenario");
|
||||||
if (!root) {
|
if (!root) {
|
||||||
std::cerr << "0x1005 Failed to find Scenario element in configuration file!" << std::endl;
|
std::cerr << "0x1009 配置文件中未找到 Scenario 根元素, 引擎将退出!" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 顺便读取一下CPU亲和性
|
// 顺便读取一下CPU亲和性
|
||||||
int cpus = sysconf(_SC_NPROCESSORS_ONLN);
|
int cpus = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
std::cout << "Current number of CPU cores-> " << cpus << std::endl;
|
std::cout << "当前CPU核心数-> " << cpus << std::endl;
|
||||||
|
|
||||||
// 设置CPU亲和性
|
// 设置CPU亲和性
|
||||||
cpu_set_t mask;
|
cpu_set_t mask;
|
||||||
@ -106,30 +114,34 @@ bool XNEngine::SetLogLevel(const std::string &XmlPath)
|
|||||||
CPU_SET(index, &mask);
|
CPU_SET(index, &mask);
|
||||||
}
|
}
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
std::cerr << "Invalid CPU affinity value: " << cpuIndex << std::endl;
|
std::cerr << "0x1010 无效的CPU亲和性值: " << cpuIndex << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
|
if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
|
||||||
std::cerr << "0x1020 Failed to set engine CPU affinity-> " << strerror(errno) << std::endl;
|
std::cerr << "0x1011 设置引擎CPU亲和性失败-> " << strerror(errno) << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
std::cout << "Successfully set engine CPU affinity-> " << CPUAffinity << std::endl;
|
std::cout << "成功设置引擎CPU亲和性-> " << CPUAffinity << std::endl;
|
||||||
|
|
||||||
// 锁定内存
|
// 锁定内存
|
||||||
if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
|
if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
|
||||||
std::cerr << "0x1021 Failed to lock engine memory-> " << strerror(errno) << std::endl;
|
std::cerr << "0x1012 锁定引擎内存失败-> " << strerror(errno) << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
std::cout << "Successfully locked engine memory!" << std::endl;
|
std::cout << "成功锁定引擎内存!" << std::endl;
|
||||||
|
|
||||||
|
// 获取配置文件中的日志元素
|
||||||
|
bool isDebug = false;
|
||||||
|
bool isInfo = false;
|
||||||
|
bool isWarn = false;
|
||||||
|
bool isError = false;
|
||||||
// 获取配置文件中的控制台输出元素
|
// 获取配置文件中的控制台输出元素
|
||||||
tinyxml2::XMLElement *consoleOutputNode = root->FirstChildElement("ConsoleOutput");
|
tinyxml2::XMLElement *consoleOutputNode = root->FirstChildElement("ConsoleOutput");
|
||||||
if (!consoleOutputNode) {
|
if (!consoleOutputNode) {
|
||||||
std::cout << "The runtime environment configuration file does not contain "
|
std::cout << "0x1013 配置文件中未找到 ConsoleOutput 元素, 控制台将输出所有日志!"
|
||||||
"the ConsoleOutput element, the Console will Output all Log!"
|
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
} else {
|
} else {
|
||||||
// 获取配置文件中的调试日志输出元素
|
// 获取配置文件中的调试日志输出元素
|
||||||
@ -138,9 +150,9 @@ bool XNEngine::SetLogLevel(const std::string &XmlPath)
|
|||||||
&& (strcmp(debugConsoleOutput, "true") == 0 || strcmp(debugConsoleOutput, "1") == 0
|
&& (strcmp(debugConsoleOutput, "true") == 0 || strcmp(debugConsoleOutput, "1") == 0
|
||||||
|| strcmp(debugConsoleOutput, "True") == 0
|
|| strcmp(debugConsoleOutput, "True") == 0
|
||||||
|| strcmp(debugConsoleOutput, "TRUE") == 0)) {
|
|| strcmp(debugConsoleOutput, "TRUE") == 0)) {
|
||||||
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Debug, true);
|
isDebug = true;
|
||||||
} else {
|
} else {
|
||||||
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Debug, false);
|
isDebug = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取配置文件中的信息日志输出元素
|
// 获取配置文件中的信息日志输出元素
|
||||||
@ -149,9 +161,9 @@ bool XNEngine::SetLogLevel(const std::string &XmlPath)
|
|||||||
&& (strcmp(infoConsoleOutput, "true") == 0 || strcmp(infoConsoleOutput, "1") == 0
|
&& (strcmp(infoConsoleOutput, "true") == 0 || strcmp(infoConsoleOutput, "1") == 0
|
||||||
|| strcmp(infoConsoleOutput, "True") == 0
|
|| strcmp(infoConsoleOutput, "True") == 0
|
||||||
|| strcmp(infoConsoleOutput, "TRUE") == 0)) {
|
|| strcmp(infoConsoleOutput, "TRUE") == 0)) {
|
||||||
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Info, true);
|
isInfo = true;
|
||||||
} else {
|
} else {
|
||||||
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Info, false);
|
isInfo = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取配置文件中的警告日志输出元素
|
// 获取配置文件中的警告日志输出元素
|
||||||
@ -160,9 +172,9 @@ bool XNEngine::SetLogLevel(const std::string &XmlPath)
|
|||||||
&& (strcmp(warningConsoleOutput, "true") == 0 || strcmp(warningConsoleOutput, "1") == 0
|
&& (strcmp(warningConsoleOutput, "true") == 0 || strcmp(warningConsoleOutput, "1") == 0
|
||||||
|| strcmp(warningConsoleOutput, "True") == 0
|
|| strcmp(warningConsoleOutput, "True") == 0
|
||||||
|| strcmp(warningConsoleOutput, "TRUE") == 0)) {
|
|| strcmp(warningConsoleOutput, "TRUE") == 0)) {
|
||||||
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Warning, true);
|
isWarn = true;
|
||||||
} else {
|
} else {
|
||||||
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Warning, false);
|
isWarn = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取配置文件中的错误日志输出元素
|
// 获取配置文件中的错误日志输出元素
|
||||||
@ -171,27 +183,26 @@ bool XNEngine::SetLogLevel(const std::string &XmlPath)
|
|||||||
&& (strcmp(errorConsoleOutput, "true") == 0 || strcmp(errorConsoleOutput, "1") == 0
|
&& (strcmp(errorConsoleOutput, "true") == 0 || strcmp(errorConsoleOutput, "1") == 0
|
||||||
|| strcmp(errorConsoleOutput, "True") == 0
|
|| strcmp(errorConsoleOutput, "True") == 0
|
||||||
|| strcmp(errorConsoleOutput, "TRUE") == 0)) {
|
|| strcmp(errorConsoleOutput, "TRUE") == 0)) {
|
||||||
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Error, true);
|
isError = true;
|
||||||
} else {
|
} else {
|
||||||
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Error, false);
|
isError = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 设置控制台输出
|
||||||
|
SetConsoleOutput(isDebug, isInfo, isWarn, isError);
|
||||||
|
|
||||||
// 获取配置文件中的日志元素
|
|
||||||
tinyxml2::XMLElement *logNode = root->FirstChildElement("Log");
|
tinyxml2::XMLElement *logNode = root->FirstChildElement("Log");
|
||||||
if (!logNode) {
|
if (!logNode) {
|
||||||
std::cout << "The runtime environment configuration file does not contain "
|
std::cout << "0x1014 配置文件中未找到 Log 元素, 日志文件将记录所有日志!" << std::endl;
|
||||||
"the Log element, the Log File will record all Log!"
|
|
||||||
<< std::endl;
|
|
||||||
} else {
|
} else {
|
||||||
// 获取配置文件中的调试日志输出元素
|
// 获取配置文件中的调试日志输出元素
|
||||||
const char *debugLog = logNode->Attribute("Debug");
|
const char *debugLog = logNode->Attribute("Debug");
|
||||||
if (debugLog
|
if (debugLog
|
||||||
&& (strcmp(debugLog, "true") == 0 || strcmp(debugLog, "1") == 0
|
&& (strcmp(debugLog, "true") == 0 || strcmp(debugLog, "1") == 0
|
||||||
|| strcmp(debugLog, "True") == 0 || strcmp(debugLog, "TRUE") == 0)) {
|
|| strcmp(debugLog, "True") == 0 || strcmp(debugLog, "TRUE") == 0)) {
|
||||||
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Debug, true);
|
isDebug = true;
|
||||||
} else {
|
} else {
|
||||||
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Debug, false);
|
isDebug = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取配置文件中的信息日志输出元素
|
// 获取配置文件中的信息日志输出元素
|
||||||
@ -199,9 +210,9 @@ bool XNEngine::SetLogLevel(const std::string &XmlPath)
|
|||||||
if (infoLog
|
if (infoLog
|
||||||
&& (strcmp(infoLog, "true") == 0 || strcmp(infoLog, "1") == 0
|
&& (strcmp(infoLog, "true") == 0 || strcmp(infoLog, "1") == 0
|
||||||
|| strcmp(infoLog, "True") == 0 || strcmp(infoLog, "TRUE") == 0)) {
|
|| strcmp(infoLog, "True") == 0 || strcmp(infoLog, "TRUE") == 0)) {
|
||||||
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Info, true);
|
isInfo = true;
|
||||||
} else {
|
} else {
|
||||||
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Info, false);
|
isInfo = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取配置文件中的警告日志输出元素
|
// 获取配置文件中的警告日志输出元素
|
||||||
@ -209,9 +220,9 @@ bool XNEngine::SetLogLevel(const std::string &XmlPath)
|
|||||||
if (warningLog
|
if (warningLog
|
||||||
&& (strcmp(warningLog, "true") == 0 || strcmp(warningLog, "1") == 0
|
&& (strcmp(warningLog, "true") == 0 || strcmp(warningLog, "1") == 0
|
||||||
|| strcmp(warningLog, "True") == 0 || strcmp(warningLog, "TRUE") == 0)) {
|
|| strcmp(warningLog, "True") == 0 || strcmp(warningLog, "TRUE") == 0)) {
|
||||||
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Warning, true);
|
isWarn = true;
|
||||||
} else {
|
} else {
|
||||||
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Warning, false);
|
isWarn = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取配置文件中的错误日志输出元素
|
// 获取配置文件中的错误日志输出元素
|
||||||
@ -219,18 +230,73 @@ bool XNEngine::SetLogLevel(const std::string &XmlPath)
|
|||||||
if (errorLog
|
if (errorLog
|
||||||
&& (strcmp(errorLog, "true") == 0 || strcmp(errorLog, "1") == 0
|
&& (strcmp(errorLog, "true") == 0 || strcmp(errorLog, "1") == 0
|
||||||
|| strcmp(errorLog, "True") == 0 || strcmp(errorLog, "TRUE") == 0)) {
|
|| strcmp(errorLog, "True") == 0 || strcmp(errorLog, "TRUE") == 0)) {
|
||||||
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Error, true);
|
isError = true;
|
||||||
} else {
|
} else {
|
||||||
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Error, false);
|
isError = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置日志级别
|
||||||
|
SetLogLevel(isDebug, isInfo, isWarn, isError);
|
||||||
|
|
||||||
// 关闭配置文件
|
// 关闭配置文件
|
||||||
file.close();
|
file.close();
|
||||||
// 返回成功
|
// 返回成功
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置控制台输出
|
||||||
|
bool XNEngine::SetConsoleOutput(bool isDebug, bool isInfo, bool isWarn, bool isError)
|
||||||
|
{
|
||||||
|
if (isDebug) {
|
||||||
|
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Debug, true);
|
||||||
|
} else {
|
||||||
|
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Debug, false);
|
||||||
|
}
|
||||||
|
if (isInfo) {
|
||||||
|
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Info, true);
|
||||||
|
} else {
|
||||||
|
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Info, false);
|
||||||
|
}
|
||||||
|
if (isWarn) {
|
||||||
|
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Warning, true);
|
||||||
|
} else {
|
||||||
|
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Warning, false);
|
||||||
|
}
|
||||||
|
if (isError) {
|
||||||
|
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Error, true);
|
||||||
|
} else {
|
||||||
|
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Error, false);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置日志级别
|
||||||
|
bool XNEngine::SetLogLevel(bool isDebug, bool isInfo, bool isWarn, bool isError)
|
||||||
|
{
|
||||||
|
if (isDebug) {
|
||||||
|
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Debug, true);
|
||||||
|
} else {
|
||||||
|
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Debug, false);
|
||||||
|
}
|
||||||
|
if (isInfo) {
|
||||||
|
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Info, true);
|
||||||
|
} else {
|
||||||
|
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Info, false);
|
||||||
|
}
|
||||||
|
if (isWarn) {
|
||||||
|
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Warning, true);
|
||||||
|
} else {
|
||||||
|
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Warning, false);
|
||||||
|
}
|
||||||
|
if (isError) {
|
||||||
|
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Error, true);
|
||||||
|
} else {
|
||||||
|
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Error, false);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// 发布引擎状态
|
// 发布引擎状态
|
||||||
void XNEngine::PublishEngineStatus()
|
void XNEngine::PublishEngineStatus()
|
||||||
{
|
{
|
||||||
@ -332,7 +398,7 @@ void XNEngine::PublishEngineStatus()
|
|||||||
// 写入引擎状态
|
// 写入引擎状态
|
||||||
engineStatusWriter->write(&engineStatus);
|
engineStatusWriter->write(&engineStatus);
|
||||||
// 记录调试日志
|
// 记录调试日志
|
||||||
LOG_DEBUG("XNEngine Write DDS!");
|
LOG_DEBUG("引擎运行状态 DDS 写入成功!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,9 +408,9 @@ bool XNEngine::Run(const std::string &XmlPath)
|
|||||||
if (!framework) {
|
if (!framework) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 设置日志级别
|
// 解析配置文件
|
||||||
bool isReady = SetLogLevel(XmlPath);
|
bool isReady = ParseConfig(XmlPath);
|
||||||
// 如果设置日志级别失败
|
// 如果解析配置文件失败
|
||||||
if (!isReady) {
|
if (!isReady) {
|
||||||
// 返回失败
|
// 返回失败
|
||||||
return false;
|
return false;
|
||||||
@ -357,6 +423,7 @@ bool XNEngine::Run(const std::string &XmlPath)
|
|||||||
bool ret = framework->Initialize(0);
|
bool ret = framework->Initialize(0);
|
||||||
// 如果初始化失败
|
// 如果初始化失败
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
|
LOG_ERROR("0x1012 初始化失败, 引擎将退出!");
|
||||||
// 返回失败
|
// 返回失败
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -364,17 +431,18 @@ bool XNEngine::Run(const std::string &XmlPath)
|
|||||||
// 设置框架状态
|
// 设置框架状态
|
||||||
frameworkStatus = XNFrameObjectStatus::Initialized;
|
frameworkStatus = XNFrameObjectStatus::Initialized;
|
||||||
// 记录信息日志
|
// 记录信息日志
|
||||||
LOG_INFO("XNEngine Initialize Success!");
|
LOG_INFO("引擎初始化成功!");
|
||||||
// 如果测试模式
|
// 如果测试模式
|
||||||
if (isTestMode) {
|
if (isTestMode) {
|
||||||
// 记录信息日志
|
// 记录信息日志
|
||||||
LOG_INFO("Verification passed!");
|
LOG_INFO("引擎测试通过!");
|
||||||
// 返回成功
|
// 返回成功
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
ret = framework->PrepareForExecute();
|
ret = framework->PrepareForExecute();
|
||||||
// 如果准备执行失败
|
// 如果准备执行失败
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
|
LOG_ERROR("0x1013 准备执行失败, 引擎将退出!");
|
||||||
// 返回失败
|
// 返回失败
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -412,15 +480,197 @@ bool XNEngine::Run(const std::string &XmlPath)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 记录错误日志
|
// 记录错误日志
|
||||||
LOG_ERROR("0x1007 Failed to prepare for execution, the engine will exit!");
|
LOG_ERROR("0x1014 无法发送引擎运行状态, 引擎将退出!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回成功
|
// 返回成功
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 运行引擎
|
||||||
|
bool XNEngine::ParseDataBase(const uint32_t &ConfigId)
|
||||||
|
{
|
||||||
|
// 获取数据库路径
|
||||||
|
std::string dbPath = std::getenv("XNCore");
|
||||||
|
if (dbPath.empty()) {
|
||||||
|
LOG_ERROR("0x1015 未设置XNCore环境变量, 引擎将退出!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
dbPath += "/database/XNSim.db";
|
||||||
|
|
||||||
|
// 打开数据库
|
||||||
|
sqlite3 *db;
|
||||||
|
if (sqlite3_open(dbPath.c_str(), &db) != SQLITE_OK) {
|
||||||
|
LOG_ERROR("0x1016 打开数据库失败: {}", sqlite3_errmsg(db));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 准备SQL语句
|
||||||
|
std::string sql = "SELECT * FROM Configuration WHERE ConfID = ?";
|
||||||
|
sqlite3_stmt *stmt;
|
||||||
|
if (sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
|
||||||
|
LOG_ERROR("0x1017 准备SQL语句失败: {}", sqlite3_errmsg(db));
|
||||||
|
sqlite3_close(db);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绑定参数
|
||||||
|
if (sqlite3_bind_int(stmt, 1, ConfigId) != SQLITE_OK) {
|
||||||
|
LOG_ERROR("0x1018 绑定参数失败: {}", sqlite3_errmsg(db));
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
sqlite3_close(db);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行查询
|
||||||
|
if (sqlite3_step(stmt) != SQLITE_ROW) {
|
||||||
|
LOG_ERROR("0x1019 未找到配置ID为{}的记录", ConfigId);
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
sqlite3_close(db);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cpus = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
std::cout << "当前CPU核心数-> " << cpus << std::endl;
|
||||||
|
|
||||||
|
// 设置CPU亲和性
|
||||||
|
cpu_set_t mask;
|
||||||
|
CPU_ZERO(&mask);
|
||||||
|
CPUAffinity = 0;
|
||||||
|
|
||||||
|
// 读取配置信息
|
||||||
|
std::string CPUAff = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 6));
|
||||||
|
|
||||||
|
std::istringstream iss(CPUAff);
|
||||||
|
std::string cpuIndex;
|
||||||
|
while (std::getline(iss, cpuIndex, ',')) {
|
||||||
|
try {
|
||||||
|
int index = std::stoi(cpuIndex);
|
||||||
|
if (index >= 0 && index < cpus) {
|
||||||
|
CPUAffinity |= (1 << index);
|
||||||
|
CPU_SET(index, &mask);
|
||||||
|
}
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
std::cerr << "0x1010 无效的CPU亲和性值: " << cpuIndex << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
|
||||||
|
std::cerr << "0x1011 设置引擎CPU亲和性失败-> " << strerror(errno) << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::cout << "成功设置引擎CPU亲和性-> " << CPUAffinity << std::endl;
|
||||||
|
|
||||||
|
// 锁定内存
|
||||||
|
if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
|
||||||
|
std::cerr << "0x1012 锁定引擎内存失败-> " << strerror(errno) << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::cout << "成功锁定引擎内存!" << std::endl;
|
||||||
|
|
||||||
|
auto readBoolean = [](sqlite3_stmt *stmt, int column) -> bool {
|
||||||
|
return sqlite3_column_int(stmt, column) != 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isDebug = readBoolean(stmt, 11);
|
||||||
|
bool isInfo = readBoolean(stmt, 12);
|
||||||
|
bool isWarn = readBoolean(stmt, 13);
|
||||||
|
bool isError = readBoolean(stmt, 14);
|
||||||
|
|
||||||
|
SetConsoleOutput(isDebug, isInfo, isWarn, isError);
|
||||||
|
|
||||||
|
isDebug = readBoolean(stmt, 15);
|
||||||
|
isInfo = readBoolean(stmt, 16);
|
||||||
|
isWarn = readBoolean(stmt, 17);
|
||||||
|
isError = readBoolean(stmt, 18);
|
||||||
|
|
||||||
|
SetLogLevel(isDebug, isInfo, isWarn, isError);
|
||||||
|
|
||||||
|
// 清理资源
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
sqlite3_close(db);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool XNEngine::Run(const uint32_t &ConfigId)
|
bool XNEngine::Run(const uint32_t &ConfigId)
|
||||||
{
|
{
|
||||||
|
if (!framework) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 解析数据库
|
||||||
|
bool isReady = ParseDataBase(ConfigId);
|
||||||
|
// 如果解析数据库失败
|
||||||
|
if (!isReady) {
|
||||||
|
// 返回失败
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 设置构型ID
|
||||||
|
//framework->SetScenarioId(ConfigId);
|
||||||
|
// 设置CPU亲和性
|
||||||
|
framework->SetCpuAffinity(CPUAffinity);
|
||||||
|
// 单次触发初始化信号
|
||||||
|
bool ret = framework->Initialize(1);
|
||||||
|
// 如果初始化失败
|
||||||
|
if (!ret) {
|
||||||
|
LOG_ERROR("0x1012 初始化失败, 引擎将退出!");
|
||||||
|
// 返回失败
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 如果初始化成功
|
||||||
|
// 设置框架状态
|
||||||
|
frameworkStatus = XNFrameObjectStatus::Initialized;
|
||||||
|
// 记录信息日志
|
||||||
|
LOG_INFO("引擎初始化成功!");
|
||||||
|
// 如果测试模式
|
||||||
|
if (isTestMode) {
|
||||||
|
// 记录信息日志
|
||||||
|
LOG_INFO("引擎测试通过!");
|
||||||
|
// 返回成功
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ret = framework->PrepareForExecute();
|
||||||
|
// 如果准备执行失败
|
||||||
|
if (!ret) {
|
||||||
|
LOG_ERROR("0x1013 准备执行失败, 引擎将退出!");
|
||||||
|
// 返回失败
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 设置框架状态
|
||||||
|
frameworkStatus = XNFrameObjectStatus::Ready;
|
||||||
|
// 获取DDS管理器
|
||||||
|
XNDDSManagerPtr ddsManager = framework->GetDDSManager();
|
||||||
|
// 如果DDS管理器存在
|
||||||
|
if (ddsManager) {
|
||||||
|
// 注册仿真控制订阅者
|
||||||
|
auto func = std::bind(&XNEngine::SimControlListener, this, std::placeholders::_1);
|
||||||
|
ddsManager->RegisterSubscriber<XNSim::XNSimControl::XNRuntimeControlPubSubType>(
|
||||||
|
"XNSim::XNSimControl::XNRuntimeControl", 0, func);
|
||||||
|
// 触发仿真控制信号
|
||||||
|
framework->SimControl(0, SimControlCmd::Start);
|
||||||
|
// 注册引擎状态发布者
|
||||||
|
engineStatusWriter =
|
||||||
|
ddsManager->RegisterPublisher<XNSim::XNSimStatus::XNEngineStatusPubSubType>(
|
||||||
|
"XNSim::XNSimStatus::XNEngineStatus", 0);
|
||||||
|
// 如果引擎状态写入器存在
|
||||||
|
if (engineStatusWriter) {
|
||||||
|
// 设置引擎运行标志
|
||||||
|
engineRunning = true;
|
||||||
|
while (engineRunning) {
|
||||||
|
// 发布一次初始状态
|
||||||
|
PublishEngineStatus();
|
||||||
|
// 等待1秒
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
}
|
||||||
|
if (!engineRunning) {
|
||||||
|
// 取消注册引擎状态发布者
|
||||||
|
//ddsManager->UnregisterPublisher("XNSim::XNSimStatus::XNEngineStatus");
|
||||||
|
//ddsManager->UnregisterSubscriber("XNSim::XNSimControl::XNRuntimeControl");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 记录错误日志
|
||||||
|
LOG_ERROR("0x1014 无法发送引擎运行状态, 引擎将退出!");
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// 设置测试模式
|
// 设置测试模式
|
||||||
|
@ -27,13 +27,14 @@ public:
|
|||||||
* @brief 析构函数
|
* @brief 析构函数
|
||||||
*/
|
*/
|
||||||
~XNEngine();
|
~XNEngine();
|
||||||
|
|
||||||
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief 仿真控制监听器
|
* @brief 仿真控制监听器
|
||||||
* @param cmd 仿真控制命令
|
* @param cmd 仿真控制命令
|
||||||
*/
|
*/
|
||||||
void SimControlListener(const XNSim::XNSimControl::XNRuntimeControl &cmd);
|
void SimControlListener(const XNSim::XNSimControl::XNRuntimeControl &cmd);
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
/**
|
||||||
* @brief 运行引擎
|
* @brief 运行引擎
|
||||||
* @param XmlPath 场景XML路径
|
* @param XmlPath 场景XML路径
|
||||||
@ -54,11 +55,37 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief 设置日志级别
|
* @brief 解析配置文件
|
||||||
* @param XmlPath 场景XML路径
|
* @param XmlPath 配置文件路径
|
||||||
* @return 是否成功
|
* @return 是否成功
|
||||||
*/
|
*/
|
||||||
bool SetLogLevel(const std::string &XmlPath);
|
bool ParseConfig(const std::string &XmlPath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 解析数据库
|
||||||
|
* @param ConfigId 配置ID
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
bool ParseDataBase(const uint32_t &ConfigId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置控制台输出
|
||||||
|
* @param isDebug 是否输出调试日志
|
||||||
|
* @param isInfo 是否输出信息日志
|
||||||
|
* @param isWarn 是否输出警告日志
|
||||||
|
* @param isError 是否输出错误日志
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
bool SetConsoleOutput(bool isDebug, bool isInfo, bool isWarn, bool isError);
|
||||||
|
/**
|
||||||
|
* @brief 设置日志级别
|
||||||
|
* @param isDebug 是否输出调试日志
|
||||||
|
* @param isInfo 是否输出信息日志
|
||||||
|
* @param isWarn 是否输出警告日志
|
||||||
|
* @param isError 是否输出错误日志
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
bool SetLogLevel(bool isDebug, bool isInfo, bool isWarn, bool isError);
|
||||||
/**
|
/**
|
||||||
* @brief 发布引擎状态
|
* @brief 发布引擎状态
|
||||||
*/
|
*/
|
||||||
|
@ -24,7 +24,7 @@ int main(int argc, char *argv[])
|
|||||||
XNEngine engine;
|
XNEngine engine;
|
||||||
//检测输入参数个数
|
//检测输入参数个数
|
||||||
if (argc <= 2) {
|
if (argc <= 2) {
|
||||||
std::cerr << "0x1000 The input parameters is too less!" << std::endl;
|
std::cerr << "0x1000 输入参数太少!" << std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,10 +42,7 @@ int main(int argc, char *argv[])
|
|||||||
hasConfigPath = true;
|
hasConfigPath = true;
|
||||||
i += 2;
|
i += 2;
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "0x1004 After the -f parameter, the configuration file path is not "
|
std::cerr << "0x1001 在-f参数后,未指定配置文件路径,引擎将退出!" << std::endl;
|
||||||
"specified, "
|
|
||||||
"the engine will exit!"
|
|
||||||
<< std::endl;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else if ("-id" == arg) {
|
} else if ("-id" == arg) {
|
||||||
@ -54,52 +51,30 @@ int main(int argc, char *argv[])
|
|||||||
hasConfigId = true;
|
hasConfigId = true;
|
||||||
i += 2;
|
i += 2;
|
||||||
} else {
|
} else {
|
||||||
std::cerr
|
std::cerr << "0x1002 在-id参数后,未指定配置ID,引擎将退出!" << std::endl;
|
||||||
<< "0x1005 After the -id parameter, the configuration ID is not specified, "
|
|
||||||
"the engine will exit!"
|
|
||||||
<< std::endl;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else if ("-test" == arg) {
|
} else if ("-test" == arg) {
|
||||||
engine.SetTestMode(true);
|
engine.SetTestMode(true);
|
||||||
i++;
|
i++;
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "0x1007 The parameter " << arg << " is not valid, the engine will exit!"
|
std::cerr << "0x1003 无法识别的参数 " << arg << " ,引擎将退出!" << std::endl;
|
||||||
<< std::endl;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//检查是否同时包含-f和-id参数
|
//检查是否同时包含-f和-id参数
|
||||||
if (hasConfigPath && hasConfigId) {
|
if (hasConfigPath && hasConfigId) {
|
||||||
std::cerr
|
std::cerr << "0x1004 请指定 -f <config_file> 或 -id <config_id> ,但不要同时指定!"
|
||||||
<< "0x1006 Please specify either -f <config_file> or -id <config_id>, but not both. "
|
<< std::endl;
|
||||||
"The engine will exit!"
|
|
||||||
<< std::endl;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//检测配置文件格式
|
//检测配置文件格式
|
||||||
if (hasConfigPath) {
|
if (hasConfigPath) {
|
||||||
size_t index = configPath.find_last_of('.');
|
|
||||||
if (index != std::string::npos) {
|
|
||||||
std::string suffix = configPath.substr(index);
|
|
||||||
if (suffix != ".xml" && suffix != ".sce") {
|
|
||||||
std::cerr << "0x1001 The configuration file is not a .xml or .sce "
|
|
||||||
"file, the engine will exit!"
|
|
||||||
<< std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std::cerr << "0x1002 The configuration file is not a .xml or .sce "
|
|
||||||
"file, the engine will exit!"
|
|
||||||
<< std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return engine.Run(configPath);
|
return engine.Run(configPath);
|
||||||
} else if (hasConfigId) {
|
} else if (hasConfigId) {
|
||||||
return engine.Run(configId);
|
return engine.Run(configId);
|
||||||
}
|
}
|
||||||
// 引擎运行
|
return -1;
|
||||||
return engine.Run(configId);
|
|
||||||
}
|
}
|
||||||
|
@ -410,7 +410,7 @@ class RunSimulation extends HTMLElement {
|
|||||||
this.currentSimulationId = Date.now().toString();
|
this.currentSimulationId = Date.now().toString();
|
||||||
|
|
||||||
// 准备启动参数
|
// 准备启动参数
|
||||||
const simulationArgs = [selectedScenario];
|
const simulationArgs = ['-f', selectedScenario];
|
||||||
|
|
||||||
// 调用后端API执行仿真
|
// 调用后端API执行仿真
|
||||||
const response = await fetch('/api/run-simulation', {
|
const response = await fetch('/api/run-simulation', {
|
||||||
|
@ -6,7 +6,6 @@ class RunTest extends HTMLElement {
|
|||||||
this.currentScenario = null;
|
this.currentScenario = null;
|
||||||
this.modelGroups = [];
|
this.modelGroups = [];
|
||||||
this.services = [];
|
this.services = [];
|
||||||
this.currentSimulationId = null;
|
|
||||||
this.eventSource = null;
|
this.eventSource = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,12 +172,6 @@ class RunTest extends HTMLElement {
|
|||||||
runButton.disabled = true;
|
runButton.disabled = true;
|
||||||
runButton.textContent = '运行中...';
|
runButton.textContent = '运行中...';
|
||||||
|
|
||||||
// 显示终止按钮
|
|
||||||
const stopButton = this.shadowRoot.querySelector('#stop-button');
|
|
||||||
if (stopButton) {
|
|
||||||
stopButton.style.display = 'block';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清空并初始化输出框
|
// 清空并初始化输出框
|
||||||
const outputContent = this.shadowRoot.querySelector('#output-content');
|
const outputContent = this.shadowRoot.querySelector('#output-content');
|
||||||
outputContent.innerHTML = '开始执行测试...\n';
|
outputContent.innerHTML = '开始执行测试...\n';
|
||||||
@ -189,20 +182,16 @@ class RunTest extends HTMLElement {
|
|||||||
this.eventSource = null;
|
this.eventSource = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存当前仿真信息
|
|
||||||
this.currentSimulationId = Date.now().toString();
|
|
||||||
|
|
||||||
// 准备启动参数
|
// 准备启动参数
|
||||||
const simulationArgs = [selectedScenario, '-test'];
|
const simulationArgs = ['-f', selectedScenario, '-test'];
|
||||||
|
|
||||||
// 调用后端API执行仿真
|
// 调用后端API执行测试
|
||||||
const response = await fetch('/api/run-simulation', {
|
const response = await fetch('/api/run-simulation', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
id: this.currentSimulationId,
|
|
||||||
args: simulationArgs,
|
args: simulationArgs,
|
||||||
timeout: 120000 // 2分钟超时
|
timeout: 120000 // 2分钟超时
|
||||||
})
|
})
|
||||||
@ -218,14 +207,15 @@ class RunTest extends HTMLElement {
|
|||||||
|
|
||||||
const responseData = await response.json();
|
const responseData = await response.json();
|
||||||
|
|
||||||
// 获取仿真ID
|
// 连接到SSE获取实时输出
|
||||||
const simulationId = responseData.simulationId || this.currentSimulationId;
|
this.connectToEventSource(responseData.simulationId);
|
||||||
this.currentSimulationId = simulationId;
|
|
||||||
|
|
||||||
// 设置SSE连接获取实时输出
|
// 根据测试结果更新UI
|
||||||
this.connectToEventSource(simulationId);
|
if (responseData.success) {
|
||||||
|
this.showSuccess('测试已启动');
|
||||||
this.showSuccess(`测试已启动`);
|
} else {
|
||||||
|
this.showError(`测试启动失败: ${responseData.message || '未知错误'}`);
|
||||||
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('执行测试失败:', error);
|
console.error('执行测试失败:', error);
|
||||||
@ -234,16 +224,20 @@ class RunTest extends HTMLElement {
|
|||||||
// 显示错误详情
|
// 显示错误详情
|
||||||
const outputContent = this.shadowRoot.querySelector('#output-content');
|
const outputContent = this.shadowRoot.querySelector('#output-content');
|
||||||
outputContent.innerHTML += `\n\n执行错误: ${error.message}`;
|
outputContent.innerHTML += `\n\n执行错误: ${error.message}`;
|
||||||
|
} finally {
|
||||||
// 重置UI
|
// 重置UI
|
||||||
this.resetUIAfterCompletion();
|
const runButton = this.shadowRoot.querySelector('#run-button');
|
||||||
|
runButton.disabled = false;
|
||||||
|
runButton.textContent = '运行测试';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 连接到SSE事件源获取实时输出
|
// 连接到SSE事件源获取实时输出
|
||||||
connectToEventSource(simulationId) {
|
connectToEventSource(simulationId) {
|
||||||
// 关闭之前的连接
|
// 关闭之前的连接
|
||||||
this.closeEventSource();
|
if (this.eventSource) {
|
||||||
|
this.eventSource.close();
|
||||||
|
}
|
||||||
|
|
||||||
// 创建新的SSE连接
|
// 创建新的SSE连接
|
||||||
const url = `/api/simulation-output/${simulationId}`;
|
const url = `/api/simulation-output/${simulationId}`;
|
||||||
@ -274,11 +268,9 @@ class RunTest extends HTMLElement {
|
|||||||
const data = JSON.parse(event.data);
|
const data = JSON.parse(event.data);
|
||||||
|
|
||||||
if (data.running === false) {
|
if (data.running === false) {
|
||||||
// 仿真已经不存在或已结束
|
// 测试已经结束
|
||||||
this.showMessage(data.message || '测试不存在或已结束');
|
this.showMessage(data.message || '测试已结束');
|
||||||
|
this.closeEventSource();
|
||||||
// 重置UI
|
|
||||||
this.resetUIAfterCompletion();
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('处理状态事件失败:', error);
|
console.error('处理状态事件失败:', error);
|
||||||
@ -296,8 +288,7 @@ class RunTest extends HTMLElement {
|
|||||||
this.showError(`测试执行失败: ${data.message}`);
|
this.showError(`测试执行失败: ${data.message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置UI
|
this.closeEventSource();
|
||||||
this.resetUIAfterCompletion();
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('处理完成事件失败:', error);
|
console.error('处理完成事件失败:', error);
|
||||||
}
|
}
|
||||||
@ -308,59 +299,17 @@ class RunTest extends HTMLElement {
|
|||||||
try {
|
try {
|
||||||
const data = JSON.parse(event.data);
|
const data = JSON.parse(event.data);
|
||||||
this.showError(`测试错误: ${data.message}`);
|
this.showError(`测试错误: ${data.message}`);
|
||||||
|
this.closeEventSource();
|
||||||
// 重置UI
|
|
||||||
this.resetUIAfterCompletion();
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('处理错误事件失败:', error);
|
console.error('处理错误事件失败:', error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 仿真终止
|
// 连接错误处理
|
||||||
this.eventSource.addEventListener('terminated', (event) => {
|
|
||||||
try {
|
|
||||||
const data = JSON.parse(event.data);
|
|
||||||
this.showMessage(`测试已终止: ${data.message}`);
|
|
||||||
|
|
||||||
// 在输出框中添加终止信息
|
|
||||||
const outputContent = this.shadowRoot.querySelector('#output-content');
|
|
||||||
outputContent.innerHTML += `\n\n测试已终止:${data.message}`;
|
|
||||||
|
|
||||||
// 重置UI
|
|
||||||
this.resetUIAfterCompletion();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('处理终止事件失败:', error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 仿真超时
|
|
||||||
this.eventSource.addEventListener('timeout', (event) => {
|
|
||||||
try {
|
|
||||||
const data = JSON.parse(event.data);
|
|
||||||
this.showError(`测试超时: ${data.message}`);
|
|
||||||
|
|
||||||
// 在输出框中添加超时信息
|
|
||||||
const outputContent = this.shadowRoot.querySelector('#output-content');
|
|
||||||
outputContent.innerHTML += `\n\n测试超时:${data.message}`;
|
|
||||||
|
|
||||||
// 重置UI
|
|
||||||
this.resetUIAfterCompletion();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('处理超时事件失败:', error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 连接错误
|
|
||||||
this.eventSource.onerror = (error) => {
|
this.eventSource.onerror = (error) => {
|
||||||
console.error('SSE连接错误:', error);
|
console.error('SSE连接错误:', error);
|
||||||
|
this.showError('实时输出连接已断开');
|
||||||
// 检查是否已经清理了资源
|
this.closeEventSource();
|
||||||
if (this.eventSource && this.eventSource.readyState === 2) { // CLOSED
|
|
||||||
this.showError('实时输出连接已断开');
|
|
||||||
|
|
||||||
// 重置UI
|
|
||||||
this.resetUIAfterCompletion();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,69 +320,6 @@ class RunTest extends HTMLElement {
|
|||||||
this.eventSource = null;
|
this.eventSource = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在仿真完成后重置UI
|
|
||||||
resetUIAfterCompletion() {
|
|
||||||
// 隐藏终止按钮
|
|
||||||
const stopButton = this.shadowRoot.querySelector('#stop-button');
|
|
||||||
if (stopButton) {
|
|
||||||
stopButton.style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置运行按钮
|
|
||||||
const runButton = this.shadowRoot.querySelector('#run-button');
|
|
||||||
if (runButton) {
|
|
||||||
runButton.disabled = false;
|
|
||||||
runButton.textContent = '运行测试';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭SSE连接
|
|
||||||
this.closeEventSource();
|
|
||||||
|
|
||||||
// 清除当前仿真ID
|
|
||||||
this.currentSimulationId = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
async stopSimulation() {
|
|
||||||
if (!this.currentSimulationId) {
|
|
||||||
this.showMessage('没有正在运行的测试');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.showMessage('正在终止测试...');
|
|
||||||
|
|
||||||
const response = await fetch('/api/stop-simulation', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
id: this.currentSimulationId
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
const result = await response.json();
|
|
||||||
this.showSuccess(`${result.message || '测试已终止'}`);
|
|
||||||
|
|
||||||
// 终止信息会通过SSE推送到UI
|
|
||||||
// 此处不需要额外操作
|
|
||||||
} else {
|
|
||||||
const errorData = await response.json();
|
|
||||||
this.showError(`终止测试失败: ${errorData.message || '未知错误'}`);
|
|
||||||
|
|
||||||
// 可能是SSE已断开,手动重置UI
|
|
||||||
this.resetUIAfterCompletion();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('终止测试失败:', error);
|
|
||||||
this.showError('终止测试失败: ' + error.message);
|
|
||||||
|
|
||||||
// 手动重置UI
|
|
||||||
this.resetUIAfterCompletion();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
showError(message) {
|
showError(message) {
|
||||||
const messageElement = this.shadowRoot.querySelector('#message');
|
const messageElement = this.shadowRoot.querySelector('#message');
|
||||||
@ -514,16 +400,6 @@ class RunTest extends HTMLElement {
|
|||||||
background-color: #cccccc;
|
background-color: #cccccc;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
#stop-button {
|
|
||||||
background-color: #d32f2f;
|
|
||||||
display: none;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#stop-button:hover {
|
|
||||||
background-color: #b71c1c;
|
|
||||||
}
|
|
||||||
|
|
||||||
#message {
|
#message {
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
@ -645,10 +521,6 @@ class RunTest extends HTMLElement {
|
|||||||
.output-content .ansi-bold { font-weight: bold; }
|
.output-content .ansi-bold { font-weight: bold; }
|
||||||
.output-content .ansi-italic { font-style: italic; }
|
.output-content .ansi-italic { font-style: italic; }
|
||||||
.output-content .ansi-underline { text-decoration: underline; }
|
.output-content .ansi-underline { text-decoration: underline; }
|
||||||
|
|
||||||
.buttons-container {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
<div class="test-container">
|
<div class="test-container">
|
||||||
<div class="config-selector">
|
<div class="config-selector">
|
||||||
@ -656,10 +528,7 @@ class RunTest extends HTMLElement {
|
|||||||
<select id="scenario-select">
|
<select id="scenario-select">
|
||||||
<option value="" disabled selected>-- 加载配置文件中... --</option>
|
<option value="" disabled selected>-- 加载配置文件中... --</option>
|
||||||
</select>
|
</select>
|
||||||
<div class="buttons-container">
|
<button id="run-button">运行测试</button>
|
||||||
<button id="run-button">运行测试</button>
|
|
||||||
<button id="stop-button">终止测试</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="message"></div>
|
<div id="message"></div>
|
||||||
<div class="content-container">
|
<div class="content-container">
|
||||||
@ -685,9 +554,6 @@ class RunTest extends HTMLElement {
|
|||||||
const runButton = this.shadowRoot.querySelector('#run-button');
|
const runButton = this.shadowRoot.querySelector('#run-button');
|
||||||
runButton.addEventListener('click', () => this.runTest());
|
runButton.addEventListener('click', () => this.runTest());
|
||||||
|
|
||||||
const stopButton = this.shadowRoot.querySelector('#stop-button');
|
|
||||||
stopButton.addEventListener('click', () => this.stopSimulation());
|
|
||||||
|
|
||||||
const scenarioSelect = this.shadowRoot.querySelector('#scenario-select');
|
const scenarioSelect = this.shadowRoot.querySelector('#scenario-select');
|
||||||
scenarioSelect.addEventListener('change', (event) => this.onScenarioSelected(event));
|
scenarioSelect.addEventListener('change', (event) => this.onScenarioSelected(event));
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,7 @@ router.post('/run-simulation', async (req, res) => {
|
|||||||
const logFile = path.join(logDir, `xnengine_${mainProcess.pid}.log`);
|
const logFile = path.join(logDir, `xnengine_${mainProcess.pid}.log`);
|
||||||
|
|
||||||
// 从命令行参数中提取配置文件路径
|
// 从命令行参数中提取配置文件路径
|
||||||
const scenarioFile = args[0];
|
const scenarioFile = args[1];
|
||||||
|
|
||||||
// 将进程信息写入数据库
|
// 将进程信息写入数据库
|
||||||
await saveXNEngineProcess({
|
await saveXNEngineProcess({
|
||||||
@ -261,7 +261,7 @@ router.post('/run-simulation', async (req, res) => {
|
|||||||
isExisting: true,
|
isExisting: true,
|
||||||
startTime: mainProcess.startTime,
|
startTime: mainProcess.startTime,
|
||||||
totalProcesses: sortedProcesses.length,
|
totalProcesses: sortedProcesses.length,
|
||||||
scenarioFile: (existingProcess && existingProcess.scenario_file) || args[0]
|
scenarioFile: (existingProcess && existingProcess.scenario_file) || args[1]
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -313,14 +313,17 @@ router.post('/run-simulation', async (req, res) => {
|
|||||||
const isRunning = await isProcessRunning(processId);
|
const isRunning = await isProcessRunning(processId);
|
||||||
const isXNEngine = await isXNEngineProcess(processId);
|
const isXNEngine = await isXNEngineProcess(processId);
|
||||||
|
|
||||||
if (isRunning && isXNEngine) {
|
// 检查是否是测试模式
|
||||||
|
const isTestMode = args.includes('-test');
|
||||||
|
|
||||||
|
if ((isRunning && isXNEngine) || isTestMode) {
|
||||||
// 将进程信息写入数据库
|
// 将进程信息写入数据库
|
||||||
await saveXNEngineProcess({
|
await saveXNEngineProcess({
|
||||||
pid: processId,
|
pid: processId,
|
||||||
log_file: logFile,
|
log_file: logFile,
|
||||||
start_time: new Date().toISOString(),
|
start_time: new Date().toISOString(),
|
||||||
cmd: `${enginePath} ${args.join(' ')}`,
|
cmd: `${enginePath} ${args.join(' ')}`,
|
||||||
scenario_file: args[0]
|
scenario_file: args[1]
|
||||||
});
|
});
|
||||||
|
|
||||||
// 保存到运行中的仿真Map,但不启动tail进程
|
// 保存到运行中的仿真Map,但不启动tail进程
|
||||||
@ -335,15 +338,17 @@ router.post('/run-simulation', async (req, res) => {
|
|||||||
// 立即响应,返回仿真ID
|
// 立即响应,返回仿真ID
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
message: '仿真已启动',
|
message: isTestMode ? '测试已启动' : '仿真已启动',
|
||||||
simulationId: processId.toString(),
|
simulationId: processId.toString(),
|
||||||
scenarioFile: args[0]
|
scenarioFile: args[1],
|
||||||
|
isTestMode: isTestMode,
|
||||||
|
logFile: logFile
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 进程启动失败或不是XNEngine进程
|
// 进程启动失败或不是XNEngine进程
|
||||||
await deleteXNEngineProcess(processId);
|
await deleteXNEngineProcess(processId);
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
error: '启动仿真失败',
|
error: '启动失败',
|
||||||
message: '进程启动后立即退出或不是XNEngine进程'
|
message: '进程启动后立即退出或不是XNEngine进程'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user