diff --git a/Release/Configuration/C909_V1/Services/XNUDPService_V1.0.0.0.mcfg b/Release/Configuration/C909_V1/Services/XNUDPService_V1.0.0.0.mcfg deleted file mode 100644 index 8fa1279..0000000 --- a/Release/Configuration/C909_V1/Services/XNUDPService_V1.0.0.0.mcfg +++ /dev/null @@ -1,17 +0,0 @@ - - - XNUDPService - UDP通信服务 - Jin - 1.0.0 - 2025-02-04 10:00:00 - 2025-02-04 10:00:00 - - - - - 12345 - 127.0.0.1 - 54321 - - diff --git a/Release/Configuration/C909_V1/Services/XNUDPTestService.scfg b/Release/Configuration/C909_V1/Services/XNUDPTestService.scfg deleted file mode 100644 index d80e723..0000000 --- a/Release/Configuration/C909_V1/Services/XNUDPTestService.scfg +++ /dev/null @@ -1,17 +0,0 @@ - - - XNUDPTestService - UDP通信服务 - Jin - 1.0.0 - 2025-02-04 10:00:00 - 2025-02-04 10:00:00 - - - - - 54321 - 127.0.0.1 - 12345 - - diff --git a/Release/ServiceProjects/XNTCPService_1.0.0.0.zip b/Release/ServiceProjects/XNTCPService_1.0.0.0.zip new file mode 100644 index 0000000..d26ecba Binary files /dev/null and b/Release/ServiceProjects/XNTCPService_1.0.0.0.zip differ diff --git a/Release/ServiceProjects/XNTCPService_1.0.0.0/CMakeLists.txt b/Release/ServiceProjects/XNTCPService_1.0.0.0/CMakeLists.txt new file mode 100644 index 0000000..dfa86d4 --- /dev/null +++ b/Release/ServiceProjects/XNTCPService_1.0.0.0/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.16) + +project(XNTCPService LANGUAGES CXX) + +set(SERVICE_VERSION "1.0.0.0") + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +if(DEFINED ENV{XNCore}) + set(XNCore_PATH $ENV{XNCore}) +else() + message(FATAL_ERROR "Environment variable XNCore is not set.") +endif() + +include_directories(${XNCore_PATH}/include) + +add_library(XNTCPService SHARED + XNTCPService_global.h + XNTCPService.cpp + XNTCPService.h + XNTCPService_p.h +) + +set_target_properties(XNTCPService PROPERTIES + LIBRARY_OUTPUT_NAME "libXNTCPService.so.1.0.0.0" + PREFIX "" + SUFFIX "" + SKIP_BUILD_RPATH TRUE + BUILD_WITH_INSTALL_RPATH TRUE +) + +target_link_libraries(XNTCPService PRIVATE + ${XNCore_PATH}/lib/libXNCore.so +) + +target_compile_definitions(XNTCPService PRIVATE XNTCPSERVICE_LIBRARY) + +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${XNCore_PATH}/Services" CACHE PATH "Install path prefix" FORCE) +endif() + +install(TARGETS XNTCPService BUNDLE DESTINATION . LIBRARY DESTINATION . RUNTIME DESTINATION .) + +file(GLOB CONFIG_FILE "*.scfg") + +install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX} RENAME "${CMAKE_PROJECT_NAME}_V${SERVICE_VERSION}.scfg") + diff --git a/Release/ServiceProjects/XNTCPService_1.0.0.0/XNTCPService.cpp b/Release/ServiceProjects/XNTCPService_1.0.0.0/XNTCPService.cpp new file mode 100644 index 0000000..131476b --- /dev/null +++ b/Release/ServiceProjects/XNTCPService_1.0.0.0/XNTCPService.cpp @@ -0,0 +1,29 @@ +#include "XNTCPService.h" +#include "XNTCPService_p.h" +#include + +XN_SERVICE_INITIALIZE(XNTCPService) + +XNTCPService::XNTCPService() : XNServiceObject(new XNTCPServicePrivate()) +{ +} + +XNTCPService::~XNTCPService() { +} + +XNTCPService::XNTCPService(PrivateType *p) : XNServiceObject(p) +{ +} + +void XNTCPService::Initialize() { + T_D(); + SuperType::Initialize(); + /* 在这里进行其它初始化 */ +} + +void XNTCPService::PrepareForExecute() { + T_D(); + SuperType::PrepareForExecute(); + /* 在这里进行其它运行前准备工作 */ +} + diff --git a/Release/ServiceProjects/XNTCPService_1.0.0.0/XNTCPService.h b/Release/ServiceProjects/XNTCPService_1.0.0.0/XNTCPService.h new file mode 100644 index 0000000..905e7ce --- /dev/null +++ b/Release/ServiceProjects/XNTCPService_1.0.0.0/XNTCPService.h @@ -0,0 +1,26 @@ +#pragma once + +#include "XNTCPService_global.h" +#include + +struct XNTCPServicePrivate; + +class XNTCPSERVICE_EXPORT XNTCPService : public XNServiceObject +{ +XN_METATYPE(XNTCPService, XNServiceObject) +XN_DECLARE_PRIVATE(XNTCPService) +public: + XNTCPService(); + virtual ~XNTCPService(); + +protected: + XNTCPService(PrivateType *p); + +public: + virtual void Initialize() override; + virtual void PrepareForExecute() override; + +}; + +XNCLASS_PTR_DECLARE(XNTCPService) + diff --git a/Release/ServiceProjects/XNTCPService_1.0.0.0/XNTCPService.scfg b/Release/ServiceProjects/XNTCPService_1.0.0.0/XNTCPService.scfg new file mode 100644 index 0000000..70e9890 --- /dev/null +++ b/Release/ServiceProjects/XNTCPService_1.0.0.0/XNTCPService.scfg @@ -0,0 +1,10 @@ + + + XNTCPService + TCP通信服务 + Jin + 1.0.0.0 + 2025-06-25 09:16:45 + 2025-06-25 09:16:26 + + diff --git a/Release/ServiceProjects/XNTCPService_1.0.0.0/XNTCPService_global.h b/Release/ServiceProjects/XNTCPService_1.0.0.0/XNTCPService_global.h new file mode 100644 index 0000000..9526fc3 --- /dev/null +++ b/Release/ServiceProjects/XNTCPService_1.0.0.0/XNTCPService_global.h @@ -0,0 +1,11 @@ +#ifndef XNTCPSERVICE_GLOBAL_H +#define XNTCPSERVICE_GLOBAL_H + +#if defined(XNTCPSERVICE_LIBRARY) +#define XNTCPSERVICE_EXPORT __attribute__((visibility("default"))) +#else +#define XNTCPSERVICE_EXPORT __attribute__((visibility("default"))) +#endif + +#endif // XNTCPSERVICE_GLOBAL_H + diff --git a/Release/ServiceProjects/XNTCPService_1.0.0.0/XNTCPService_p.h b/Release/ServiceProjects/XNTCPService_1.0.0.0/XNTCPService_p.h new file mode 100644 index 0000000..9df1708 --- /dev/null +++ b/Release/ServiceProjects/XNTCPService_1.0.0.0/XNTCPService_p.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +struct XNTCPServicePrivate : public XNServiceObjectPrivate{ +}; + diff --git a/Release/ServiceProjects/XNUDPService_1.0.0.0.zip b/Release/ServiceProjects/XNUDPService_1.0.0.0.zip new file mode 100644 index 0000000..ad37f12 Binary files /dev/null and b/Release/ServiceProjects/XNUDPService_1.0.0.0.zip differ diff --git a/XNServices/XNUDPService/CMakeLists.txt b/Release/ServiceProjects/XNUDPService_1.0.0.0/CMakeLists.txt old mode 100755 new mode 100644 similarity index 54% rename from XNServices/XNUDPService/CMakeLists.txt rename to Release/ServiceProjects/XNUDPService_1.0.0.0/CMakeLists.txt index 9c645c2..5f27f0f --- a/XNServices/XNUDPService/CMakeLists.txt +++ b/Release/ServiceProjects/XNUDPService_1.0.0.0/CMakeLists.txt @@ -2,37 +2,36 @@ cmake_minimum_required(VERSION 3.16) project(XNUDPService LANGUAGES CXX) -set(MODEL_VERSION "1.0.0.0") +set(SERVICE_VERSION "1.0.0.0") set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) -# 获取环境变量 if(DEFINED ENV{XNCore}) set(XNCore_PATH $ENV{XNCore}) else() message(FATAL_ERROR "Environment variable XNCore is not set.") endif() -# 添加 XNCore_PATH 下的 include 目录为包含目录 include_directories(${XNCore_PATH}/include) add_library(XNUDPService SHARED - XNUDPService_global.h - XNUDPService.cpp - XNUDPService.h - XNUDPService_p.h + XNUDPService_global.h + XNUDPService.cpp + XNUDPService.h + XNUDPService_p.h ) set_target_properties(XNUDPService PROPERTIES - LIBRARY_OUTPUT_NAME "libXNUDPService.so.${MODEL_VERSION}" + LIBRARY_OUTPUT_NAME "libXNUDPService.so.1.0.0.0" PREFIX "" SUFFIX "" SKIP_BUILD_RPATH TRUE BUILD_WITH_INSTALL_RPATH TRUE ) -target_link_libraries(XNUDPService PRIVATE +target_link_libraries(XNUDPService PRIVATE ${XNCore_PATH}/lib/libXNCore.so ) @@ -42,18 +41,9 @@ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${XNCore_PATH}/Services" CACHE PATH "Install path prefix" FORCE) endif() -include(GNUInstallDirs) -install(TARGETS XNUDPService - BUNDLE DESTINATION . - LIBRARY DESTINATION . - RUNTIME DESTINATION . -) +install(TARGETS XNUDPService BUNDLE DESTINATION . LIBRARY DESTINATION . RUNTIME DESTINATION .) -# 添加自定义命令和目标以拷贝配置文件 file(GLOB CONFIG_FILE "*.scfg") -# 使用 install 命令在安装时拷贝配置文件 -install(FILES ${CONFIG_FILE} - DESTINATION ${CMAKE_INSTALL_PREFIX} - RENAME "XNUDPService_V${MODEL_VERSION}.mcfg" -) \ No newline at end of file +install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX} RENAME "${CMAKE_PROJECT_NAME}_V${SERVICE_VERSION}.scfg") + diff --git a/Release/ServiceProjects/XNUDPService_1.0.0.0/XNUDPService.cpp b/Release/ServiceProjects/XNUDPService_1.0.0.0/XNUDPService.cpp new file mode 100644 index 0000000..e8e9da5 --- /dev/null +++ b/Release/ServiceProjects/XNUDPService_1.0.0.0/XNUDPService.cpp @@ -0,0 +1,29 @@ +#include "XNUDPService.h" +#include "XNUDPService_p.h" +#include + +XN_SERVICE_INITIALIZE(XNUDPService) + +XNUDPService::XNUDPService() : XNServiceObject(new XNUDPServicePrivate()) +{ +} + +XNUDPService::~XNUDPService() { +} + +XNUDPService::XNUDPService(PrivateType *p) : XNServiceObject(p) +{ +} + +void XNUDPService::Initialize() { + T_D(); + SuperType::Initialize(); + /* 在这里进行其它初始化 */ +} + +void XNUDPService::PrepareForExecute() { + T_D(); + SuperType::PrepareForExecute(); + /* 在这里进行其它运行前准备工作 */ +} + diff --git a/Release/ServiceProjects/XNUDPService_1.0.0.0/XNUDPService.h b/Release/ServiceProjects/XNUDPService_1.0.0.0/XNUDPService.h new file mode 100644 index 0000000..ec9b764 --- /dev/null +++ b/Release/ServiceProjects/XNUDPService_1.0.0.0/XNUDPService.h @@ -0,0 +1,26 @@ +#pragma once + +#include "XNUDPService_global.h" +#include + +struct XNUDPServicePrivate; + +class XNUDPSERVICE_EXPORT XNUDPService : public XNServiceObject +{ +XN_METATYPE(XNUDPService, XNServiceObject) +XN_DECLARE_PRIVATE(XNUDPService) +public: + XNUDPService(); + virtual ~XNUDPService(); + +protected: + XNUDPService(PrivateType *p); + +public: + virtual void Initialize() override; + virtual void PrepareForExecute() override; + +}; + +XNCLASS_PTR_DECLARE(XNUDPService) + diff --git a/Release/ServiceProjects/XNUDPService_1.0.0.0/XNUDPService.scfg b/Release/ServiceProjects/XNUDPService_1.0.0.0/XNUDPService.scfg new file mode 100644 index 0000000..c9921b5 --- /dev/null +++ b/Release/ServiceProjects/XNUDPService_1.0.0.0/XNUDPService.scfg @@ -0,0 +1,10 @@ + + + XNUDPService + UDP通信服务,提供UDP数据的发送与接收接口 + Jin + 1.0.0.0 + 2025-02-04 10:00:00 + 2025-02-04 10:00:00 + + diff --git a/XNServices/XNUDPService/XNUDPService_global.h b/Release/ServiceProjects/XNUDPService_1.0.0.0/XNUDPService_global.h old mode 100755 new mode 100644 similarity index 50% rename from XNServices/XNUDPService/XNUDPService_global.h rename to Release/ServiceProjects/XNUDPService_1.0.0.0/XNUDPService_global.h index 2b3bdb0..6ea4ab6 --- a/XNServices/XNUDPService/XNUDPService_global.h +++ b/Release/ServiceProjects/XNUDPService_1.0.0.0/XNUDPService_global.h @@ -2,9 +2,10 @@ #define XNUDPSERVICE_GLOBAL_H #if defined(XNUDPSERVICE_LIBRARY) -# define XNUDPSERVICE_EXPORT __attribute__((visibility("default"))) +#define XNUDPSERVICE_EXPORT __attribute__((visibility("default"))) #else -# define XNUDPSERVICE_EXPORT __attribute__((visibility("default"))) +#define XNUDPSERVICE_EXPORT __attribute__((visibility("default"))) #endif #endif // XNUDPSERVICE_GLOBAL_H + diff --git a/Release/ServiceProjects/XNUDPService_1.0.0.0/XNUDPService_p.h b/Release/ServiceProjects/XNUDPService_1.0.0.0/XNUDPService_p.h new file mode 100644 index 0000000..b94d4f2 --- /dev/null +++ b/Release/ServiceProjects/XNUDPService_1.0.0.0/XNUDPService_p.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +struct XNUDPServicePrivate : public XNServiceObjectPrivate{ +}; + diff --git a/Release/Services/XNTCPService_V1.0.0.0.scfg b/Release/Services/XNTCPService_V1.0.0.0.scfg new file mode 100644 index 0000000..70e9890 --- /dev/null +++ b/Release/Services/XNTCPService_V1.0.0.0.scfg @@ -0,0 +1,10 @@ + + + XNTCPService + TCP通信服务 + Jin + 1.0.0.0 + 2025-06-25 09:16:45 + 2025-06-25 09:16:26 + + diff --git a/Release/Configuration/C909_V1/Services/XNUDPService.scfg b/Release/Services/XNUDPService_V1.0.0.0.scfg similarity index 100% rename from Release/Configuration/C909_V1/Services/XNUDPService.scfg rename to Release/Services/XNUDPService_V1.0.0.0.scfg diff --git a/Release/Services/libXNTCPService.so.1.0.0.0 b/Release/Services/libXNTCPService.so.1.0.0.0 new file mode 100644 index 0000000..0406020 Binary files /dev/null and b/Release/Services/libXNTCPService.so.1.0.0.0 differ diff --git a/Release/Configuration/C909_V1/Services/libXNUDPService.so.1.0.0.0 b/Release/Services/libXNUDPService.so.1.0.0.0 similarity index 100% rename from Release/Configuration/C909_V1/Services/libXNUDPService.so.1.0.0.0 rename to Release/Services/libXNUDPService.so.1.0.0.0 diff --git a/Release/database/XNSim.db b/Release/database/XNSim.db index 22cda0b..086175b 100644 Binary files a/Release/database/XNSim.db and b/Release/database/XNSim.db differ diff --git a/XNCore/XNScenarioManager.cpp b/XNCore/XNScenarioManager.cpp index 285a786..1f07ecb 100755 --- a/XNCore/XNScenarioManager.cpp +++ b/XNCore/XNScenarioManager.cpp @@ -245,7 +245,7 @@ bool XNScenarioManager::ParseConfig(const std::string &ConfigID) std::string modelPath = rootPath + "/Models"; GetFramework()->SetModelPath(modelPath); // 设置服务库目录 - std::string servicePath = rootPath + "/Services"; + std::string servicePath = XNCorePath + "/Services"; GetFramework()->SetServicePath(servicePath); // 设置域ID uint32_t domainID = std::stoul(XNSim::getStringFromSqlite3(stmt, 7)); diff --git a/XNServiceGenServer/XNServiceGen.cpp b/XNServiceGenServer/XNServiceGen.cpp index 2ca830a..2d2ba0f 100644 --- a/XNServiceGenServer/XNServiceGen.cpp +++ b/XNServiceGenServer/XNServiceGen.cpp @@ -250,7 +250,7 @@ bool XNServiceGen::GenerateSourceFile() bool XNServiceGen::GenerateConfigFile() { - std::string configPath = m_codePath + "/" + m_className + ".mcfg"; + std::string configPath = m_codePath + "/" + m_className + ".scfg"; std::ofstream configFile(configPath); if (!configFile.is_open()) { return false; diff --git a/XNServiceGenServer/test/CMakeLists.txt b/XNServiceGenServer/test/CMakeLists.txt index 5e2dc7d..41182b5 100644 --- a/XNServiceGenServer/test/CMakeLists.txt +++ b/XNServiceGenServer/test/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(XNModelGenTest) +project(XNServiceGenTest) # 设置C++标准 set(CMAKE_CXX_STANDARD 11) @@ -9,13 +9,13 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) find_library(DL_LIBRARY dl) # 创建测试可执行文件 -add_executable(test_xnmodel test_xnmodel.cpp) +add_executable(test_xnservice test_xnservice.cpp) # 链接动态库 -target_link_libraries(test_xnmodel ${DL_LIBRARY}) +target_link_libraries(test_xnservice ${DL_LIBRARY}) # 设置运行时库路径 -set_target_properties(test_xnmodel PROPERTIES +set_target_properties(test_xnservice PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE INSTALL_RPATH "${CMAKE_SOURCE_DIR}/.." ) \ No newline at end of file diff --git a/XNServiceGenServer/test/test_xnmodel.cpp b/XNServiceGenServer/test/test_xnmodel.cpp deleted file mode 100644 index 0d46c44..0000000 --- a/XNServiceGenServer/test/test_xnmodel.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include -#include -#include - -// 函数指针类型定义 -typedef int (*XNModelCodeGenFunc)(const char *className, int classNameLen, const char *version, - int versionLen, const char *planeName, int planeNameLen, - char *errorMsg, int errorMsgLen); - -typedef int (*XNModelCodeZipFunc)(const char *className, int classNameLen, const char *version, - int versionLen, const char *planeName, int planeNameLen, - char *dstPath, int dstPathLen, char *errorMsg, int errorMsgLen); - -typedef int (*XNModelCodeUnzipFunc)(const char *className, int classNameLen, const char *version, - int versionLen, const char *planeName, int planeNameLen, - const char *srcPath, int srcPathLen, char *errorMsg, - int errorMsgLen); - -typedef int (*XNModelCodeCompileFunc)(const char *className, int classNameLen, const char *version, - int versionLen, const char *planeName, int planeNameLen, - char *errorMsg, int errorMsgLen); - -// 测试参数 -const char *className = "XNAerodynamics"; -const char *version = "2.0.3.5"; -const char *planeName = "C909"; - -void printResult(const std::string &testName, int result, const char *errorMsg) -{ - std::cout << testName << " 结果: " << result << std::endl; - if (result == 0) { - std::cout << "✓ " << testName << " 成功!" << std::endl; - } else { - std::cout << "✗ " << testName << " 失败!" << std::endl; - } - - if (strlen(errorMsg) > 0) { - std::cout << "错误信息: " << errorMsg << std::endl; - } - std::cout << std::endl; -} - -int main() -{ - // 动态加载.so库 - 修改路径指向build目录 - void *handle = dlopen("../../build/libXNModelGenServer.so", RTLD_LAZY); - if (!handle) { - std::cerr << "无法加载库文件: " << dlerror() << std::endl; - return -1; - } - - // 获取函数指针 - XNModelCodeGenFunc XNModelCodeGen = (XNModelCodeGenFunc)dlsym(handle, "XNModelCodeGen"); - XNModelCodeZipFunc XNModelCodeZip = (XNModelCodeZipFunc)dlsym(handle, "XNModelCodeZip"); - XNModelCodeUnzipFunc XNModelCodeUnzip = (XNModelCodeUnzipFunc)dlsym(handle, "XNModelCodeUnzip"); - XNModelCodeCompileFunc XNModelCodeCompile = - (XNModelCodeCompileFunc)dlsym(handle, "XNModelCodeCompile"); - - if (!XNModelCodeGen || !XNModelCodeZip || !XNModelCodeUnzip || !XNModelCodeCompile) { - std::cerr << "无法找到函数: " << dlerror() << std::endl; - dlclose(handle); - return -1; - } - - int classNameLen = strlen(className); - int versionLen = strlen(version); - int planeNameLen = strlen(planeName); - - // 错误消息缓冲区 - char errorMsg[1024]; - int errorMsgLen = sizeof(errorMsg); - - std::cout << "开始测试XNModelGen函数..." << std::endl; - std::cout << "参数:" << std::endl; - std::cout << " className: " << className << " (长度: " << classNameLen << ")" << std::endl; - std::cout << " version: " << version << " (长度: " << versionLen << ")" << std::endl; - std::cout << " planeName: " << planeName << " (长度: " << planeNameLen << ")" << std::endl; - std::cout << std::endl; - - // 测试1: XNModelCodeGen - std::cout << "=== 测试1: XNModelCodeGen ===" << std::endl; - memset(errorMsg, 0, sizeof(errorMsg)); - int result1 = XNModelCodeGen(className, classNameLen, version, versionLen, planeName, - planeNameLen, errorMsg, errorMsgLen); - printResult("XNModelCodeGen", result1, errorMsg); - - // 测试2: XNModelCodeZip - std::cout << "=== 测试2: XNModelCodeZip ===" << std::endl; - char dstPath[1024]; - int dstPathLen = sizeof(dstPath); - memset(errorMsg, 0, sizeof(errorMsg)); - memset(dstPath, 0, sizeof(dstPath)); - - int result2 = XNModelCodeZip(className, classNameLen, version, versionLen, planeName, - planeNameLen, dstPath, dstPathLen, errorMsg, errorMsgLen); - printResult("XNModelCodeZip", result2, errorMsg); - - if (result2 == 0 && strlen(dstPath) > 0) { - std::cout << "生成的zip文件路径: " << dstPath << std::endl; - } - - // 测试3: XNModelCodeUnzip - std::cout << "=== 测试3: XNModelCodeUnzip ===" << std::endl; - const char *srcZipPath = dstPath; // 使用上面生成的zip文件路径 - int srcZipPathLen = strlen(srcZipPath); - memset(errorMsg, 0, sizeof(errorMsg)); - - int result3 = XNModelCodeUnzip(className, classNameLen, version, versionLen, planeName, - planeNameLen, srcZipPath, srcZipPathLen, errorMsg, errorMsgLen); - printResult("XNModelCodeUnzip", result3, errorMsg); - - // 测试4: XNModelCodeCompile - std::cout << "=== 测试4: XNModelCodeCompile ===" << std::endl; - memset(errorMsg, 0, sizeof(errorMsg)); - int result4 = XNModelCodeCompile(className, classNameLen, version, versionLen, planeName, - planeNameLen, errorMsg, errorMsgLen); - printResult("XNModelCodeCompile", result4, errorMsg); - - // 清理资源 - dlclose(handle); - - std::cout << "=== 测试总结 ===" << std::endl; - std::cout << "XNModelCodeGen: " << (result1 == 0 ? "成功" : "失败") << std::endl; - std::cout << "XNModelCodeZip: " << (result2 == 0 ? "成功" : "失败") << std::endl; - std::cout << "XNModelCodeUnzip: " << (result3 == 0 ? "成功" : "失败") << std::endl; - std::cout << "XNModelCodeCompile: " << (result4 == 0 ? "成功" : "失败") << std::endl; - - return (result1 == 0 && result2 == 0 && result3 == 0 && result4 == 0) ? 0 : -1; -} \ No newline at end of file diff --git a/XNServiceGenServer/test/test_xnservice.cpp b/XNServiceGenServer/test/test_xnservice.cpp new file mode 100644 index 0000000..9fa2b0c --- /dev/null +++ b/XNServiceGenServer/test/test_xnservice.cpp @@ -0,0 +1,126 @@ +#include +#include +#include + +// 函数指针类型定义 +typedef int (*XNServiceCodeGenFunc)(const char *className, int classNameLen, const char *version, + int versionLen, char *errorMsg, int errorMsgLen); + +typedef int (*XNServiceCodeZipFunc)(const char *className, int classNameLen, const char *version, + int versionLen, char *dstPath, int dstPathLen, char *errorMsg, + int errorMsgLen); + +typedef int (*XNServiceCodeUnzipFunc)(const char *className, int classNameLen, const char *version, + int versionLen, const char *srcPath, int srcPathLen, + char *errorMsg, int errorMsgLen); + +typedef int (*XNServiceCodeCompileFunc)(const char *className, int classNameLen, + const char *version, int versionLen, char *errorMsg, + int errorMsgLen); + +// 测试参数 +const char *className = "XNUDPService"; +const char *version = "1.0.0.0"; +const char *planeName = "XNUDPServer"; + +void printResult(const std::string &testName, int result, const char *errorMsg) +{ + std::cout << testName << " 结果: " << result << std::endl; + if (result == 0) { + std::cout << "✓ " << testName << " 成功!" << std::endl; + } else { + std::cout << "✗ " << testName << " 失败!" << std::endl; + } + + if (strlen(errorMsg) > 0) { + std::cout << "错误信息: " << errorMsg << std::endl; + } + std::cout << std::endl; +} + +int main() +{ + // 动态加载.so库 - 修改路径指向build目录 + void *handle = dlopen("../../build/libXNServiceGenServer.so", RTLD_LAZY); + if (!handle) { + std::cerr << "无法加载库文件: " << dlerror() << std::endl; + return -1; + } + + // 获取函数指针 + XNServiceCodeGenFunc XNServiceCodeGen = (XNServiceCodeGenFunc)dlsym(handle, "XNServiceCodeGen"); + XNServiceCodeZipFunc XNServiceCodeZip = (XNServiceCodeZipFunc)dlsym(handle, "XNServiceCodeZip"); + XNServiceCodeUnzipFunc XNServiceCodeUnzip = + (XNServiceCodeUnzipFunc)dlsym(handle, "XNServiceCodeUnzip"); + XNServiceCodeCompileFunc XNServiceCodeCompile = + (XNServiceCodeCompileFunc)dlsym(handle, "XNServiceCodeCompile"); + + if (!XNServiceCodeGen || !XNServiceCodeZip || !XNServiceCodeUnzip || !XNServiceCodeCompile) { + std::cerr << "无法找到函数: " << dlerror() << std::endl; + dlclose(handle); + return -1; + } + + int classNameLen = strlen(className); + int versionLen = strlen(version); + + // 错误消息缓冲区 + char errorMsg[1024]; + int errorMsgLen = sizeof(errorMsg); + + std::cout << "开始测试XNModelGen函数..." << std::endl; + std::cout << "参数:" << std::endl; + std::cout << " className: " << className << " (长度: " << classNameLen << ")" << std::endl; + std::cout << " version: " << version << " (长度: " << versionLen << ")" << std::endl; + std::cout << std::endl; + + // 测试1: XNModelCodeGen + std::cout << "=== 测试1: XNModelCodeGen ===" << std::endl; + memset(errorMsg, 0, sizeof(errorMsg)); + int result1 = + XNServiceCodeGen(className, classNameLen, version, versionLen, errorMsg, errorMsgLen); + printResult("XNServiceCodeGen", result1, errorMsg); + + // 测试2: XNModelCodeZip + std::cout << "=== 测试2: XNModelCodeZip ===" << std::endl; + char dstPath[1024]; + int dstPathLen = sizeof(dstPath); + memset(errorMsg, 0, sizeof(errorMsg)); + memset(dstPath, 0, sizeof(dstPath)); + + int result2 = XNServiceCodeZip(className, classNameLen, version, versionLen, dstPath, + dstPathLen, errorMsg, errorMsgLen); + printResult("XNServiceCodeZip", result2, errorMsg); + + if (result2 == 0 && strlen(dstPath) > 0) { + std::cout << "生成的zip文件路径: " << dstPath << std::endl; + } + + // 测试3: XNModelCodeUnzip + std::cout << "=== 测试3: XNModelCodeUnzip ===" << std::endl; + const char *srcZipPath = dstPath; // 使用上面生成的zip文件路径 + int srcZipPathLen = strlen(srcZipPath); + memset(errorMsg, 0, sizeof(errorMsg)); + + int result3 = XNServiceCodeUnzip(className, classNameLen, version, versionLen, srcZipPath, + srcZipPathLen, errorMsg, errorMsgLen); + printResult("XNServiceCodeUnzip", result3, errorMsg); + + // 测试4: XNModelCodeCompile + std::cout << "=== 测试4: XNModelCodeCompile ===" << std::endl; + memset(errorMsg, 0, sizeof(errorMsg)); + int result4 = + XNServiceCodeCompile(className, classNameLen, version, versionLen, errorMsg, errorMsgLen); + printResult("XNServiceCodeCompile", result4, errorMsg); + + // 清理资源 + dlclose(handle); + + std::cout << "=== 测试总结 ===" << std::endl; + std::cout << "XNServiceCodeGen: " << (result1 == 0 ? "成功" : "失败") << std::endl; + std::cout << "XNServiceCodeZip: " << (result2 == 0 ? "成功" : "失败") << std::endl; + std::cout << "XNServiceCodeUnzip: " << (result3 == 0 ? "成功" : "失败") << std::endl; + std::cout << "XNServiceCodeCompile: " << (result4 == 0 ? "成功" : "失败") << std::endl; + + return (result1 == 0 && result2 == 0 && result3 == 0 && result4 == 0) ? 0 : -1; +} \ No newline at end of file diff --git a/XNServices/XNUDPService/.vscode/c_cpp_properties.json b/XNServices/XNUDPService/.vscode/c_cpp_properties.json deleted file mode 100755 index 0b3cbd5..0000000 --- a/XNServices/XNUDPService/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "configurations": [ - { - "compileCommands": "${workspaceFolder}/build/compile_commands.json", - "configurationProvider": "ms-vscode.cmake-tools" - } - ], - "version": 4 -} \ No newline at end of file diff --git a/XNServices/XNUDPService/.vscode/settings.json b/XNServices/XNUDPService/.vscode/settings.json deleted file mode 100644 index 9b6b487..0000000 --- a/XNServices/XNUDPService/.vscode/settings.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "files.associations": { - "cctype": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "csignal": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "any": "cpp", - "array": "cpp", - "atomic": "cpp", - "bit": "cpp", - "*.tcc": "cpp", - "bitset": "cpp", - "chrono": "cpp", - "codecvt": "cpp", - "compare": "cpp", - "complex": "cpp", - "concepts": "cpp", - "condition_variable": "cpp", - "cstdint": "cpp", - "deque": "cpp", - "forward_list": "cpp", - "list": "cpp", - "map": "cpp", - "set": "cpp", - "unordered_map": "cpp", - "unordered_set": "cpp", - "vector": "cpp", - "exception": "cpp", - "algorithm": "cpp", - "functional": "cpp", - "iterator": "cpp", - "memory": "cpp", - "memory_resource": "cpp", - "numeric": "cpp", - "optional": "cpp", - "random": "cpp", - "ratio": "cpp", - "regex": "cpp", - "string": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "fstream": "cpp", - "future": "cpp", - "initializer_list": "cpp", - "iomanip": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "mutex": "cpp", - "new": "cpp", - "ostream": "cpp", - "ranges": "cpp", - "span": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "stop_token": "cpp", - "streambuf": "cpp", - "thread": "cpp", - "cinttypes": "cpp", - "typeindex": "cpp", - "typeinfo": "cpp", - "valarray": "cpp", - "variant": "cpp" - } -} \ No newline at end of file diff --git a/XNServices/XNUDPService/CMakeLists.txt.user b/XNServices/XNUDPService/CMakeLists.txt.user deleted file mode 100755 index 3432be7..0000000 --- a/XNServices/XNUDPService/CMakeLists.txt.user +++ /dev/null @@ -1,424 +0,0 @@ - - - - - - EnvironmentId - {5b958118-2d32-49ab-8eab-9018ac74c7d6} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - true - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - UTF-8 - false - 4 - false - 80 - true - true - 1 - 0 - false - true - false - 2 - true - true - 0 - 8 - true - false - 1 - true - true - true - *.md, *.MD, Makefile - false - true - true - - - - ProjectExplorer.Project.PluginSettings - - - true - false - true - true - true - true - - false - - - 0 - true - - true - true - Builtin.DefaultTidyAndClazy - 5 - true - - - - true - - - true - true - - - - - ProjectExplorer.Project.Target.0 - - Desktop - Desktop Qt 6.7.2 - Desktop Qt 6.7.2 - qt.qt6.672.linux_gcc_64_kit - 0 - 0 - 0 - - Debug - 2 - false - - -DCMAKE_GENERATOR:STRING=Unix Makefiles --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_BUILD_TYPE:STRING=Debug - 0 - /media/jin/E/MyCode/xnsim/XNModels/XNAerodynamics/build/Desktop_Qt_6_7_2-Debug - - - - - all - - false - - true - 构建 - CMakeProjectManager.MakeStep - - 1 - 构建 - 构建 - ProjectExplorer.BuildSteps.Build - - - - - - clean - - false - - true - 构建 - CMakeProjectManager.MakeStep - - 1 - 清除 - 清除 - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Debug - CMakeProjectManager.CMakeBuildConfiguration - - - Release - 2 - false - - -DCMAKE_GENERATOR:STRING=Unix Makefiles --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_BUILD_TYPE:STRING=Release - /media/jin/E/MyCode/xnsim/XNModels/XNAerodynamics/build/Desktop_Qt_6_7_2-Release - - - - - all - - false - - true - CMakeProjectManager.MakeStep - - 1 - 构建 - 构建 - ProjectExplorer.BuildSteps.Build - - - - - - clean - - false - - true - CMakeProjectManager.MakeStep - - 1 - 清除 - 清除 - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Release - CMakeProjectManager.CMakeBuildConfiguration - - - RelWithDebInfo - 2 - false - - -DCMAKE_GENERATOR:STRING=Unix Makefiles --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo - /media/jin/E/MyCode/xnsim/XNModels/XNAerodynamics/build/Desktop_Qt_6_7_2-RelWithDebInfo - - - - - all - - false - - true - CMakeProjectManager.MakeStep - - 1 - 构建 - 构建 - ProjectExplorer.BuildSteps.Build - - - - - - clean - - false - - true - CMakeProjectManager.MakeStep - - 1 - 清除 - 清除 - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Release with Debug Information - CMakeProjectManager.CMakeBuildConfiguration - - - RelWithDebInfo - 2 - false - - -DCMAKE_GENERATOR:STRING=Unix Makefiles --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo - 0 - /media/jin/E/MyCode/xnsim/XNModels/XNAerodynamics/build/Desktop_Qt_6_7_2-Profile - - - - - all - - false - - true - CMakeProjectManager.MakeStep - - 1 - 构建 - 构建 - ProjectExplorer.BuildSteps.Build - - - - - - clean - - false - - true - CMakeProjectManager.MakeStep - - 1 - 清除 - 清除 - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Profile - CMakeProjectManager.CMakeBuildConfiguration - - - MinSizeRel - 2 - false - - -DCMAKE_GENERATOR:STRING=Unix Makefiles --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_BUILD_TYPE:STRING=MinSizeRel - /media/jin/E/MyCode/xnsim/XNModels/XNAerodynamics/build/Desktop_Qt_6_7_2-MinSizeRel - - - - - all - - false - - true - CMakeProjectManager.MakeStep - - 1 - 构建 - 构建 - ProjectExplorer.BuildSteps.Build - - - - - - clean - - false - - true - CMakeProjectManager.MakeStep - - 1 - 清除 - 清除 - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Minimum Size Release - CMakeProjectManager.CMakeBuildConfiguration - - 5 - - - 0 - 部署 - 部署 - ProjectExplorer.BuildSteps.Deploy - - 1 - - false - ProjectExplorer.DefaultDeployConfiguration - - 1 - - true - true - 0 - true - - 2 - - false - -e cpu-cycles --call-graph dwarf,4096 -F 250 - - ProjectExplorer.CustomExecutableRunConfiguration - - false - true - true - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 22 - - - Version - 22 - - diff --git a/XNServices/XNUDPService/XNUDPService.cpp b/XNServices/XNUDPService/XNUDPService.cpp deleted file mode 100755 index ed97f0b..0000000 --- a/XNServices/XNUDPService/XNUDPService.cpp +++ /dev/null @@ -1,229 +0,0 @@ -#include "XNUDPService.h" -#include "XNUDPService_p.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -XN_SERVICE_INITIALIZE(XNUDPService) - -XNUDPService::XNUDPService() : XNServiceObject(new XNUDPServicePrivate()) -{ -} - -XNUDPService::~XNUDPService() -{ - T_D(); - if (d->udpSocket >= 0) { - close(d->udpSocket); - d->udpSocket = -1; - } -}; - -XNUDPService::XNUDPService(PrivateType *p) : XNServiceObject(p) -{ -} - -void XNUDPService::Initialize() -{ - XNServiceObject::Initialize(); - T_D(); - if (d->_initialType == 0) { - // 读取配置文件 - std::ifstream file(GetXmlPath()); - if (!file.is_open()) { - LOG_WARNING("无法打开配置文件:%1,使用默认值", GetXmlPath().c_str()); - d->localPort = 12345; - d->targetHost = "127.0.0.1"; - d->targetPort = 54321; - return; - } - - std::stringstream buffer; - buffer << file.rdbuf(); - std::string content = buffer.str(); - file.close(); - - // 简单的XML解析 - size_t udpPos = content.find(""); - if (udpPos != std::string::npos) { - size_t localPortPos = content.find("", udpPos); - size_t targetHostPos = content.find("", udpPos); - size_t targetPortPos = content.find("", udpPos); - - if (localPortPos != std::string::npos) { - size_t endPos = content.find("", localPortPos); - d->localPort = - std::stoi(content.substr(localPortPos + 11, endPos - localPortPos - 11)); - } - if (targetHostPos != std::string::npos) { - size_t endPos = content.find("", targetHostPos); - d->targetHost = content.substr(targetHostPos + 12, endPos - targetHostPos - 12); - } - if (targetPortPos != std::string::npos) { - size_t endPos = content.find("", targetPortPos); - d->targetPort = - std::stoi(content.substr(targetPortPos + 12, endPos - targetPortPos - 12)); - } - } else { - LOG_WARNING("未找到UDP配置, 使用默认值"); - d->localPort = 12345; - d->targetHost = "127.0.0.1"; - d->targetPort = 54321; - } - } else { - try { - if (d->_otherParams.contains("LocalPort")) { - d->localPort = d->_otherParams["LocalPort"].get(); - } - if (d->_otherParams.contains("TargetHost")) { - d->targetHost = d->_otherParams["TargetHost"].get(); - } - if (d->_otherParams.contains("TargetPort")) { - d->targetPort = d->_otherParams["TargetPort"].get(); - } - LOG_INFO("UDP配置: 本地端口:%1, 目标主机:%2, 目标端口:%3", d->localPort, d->targetHost, - d->targetPort); - } catch (const std::exception &e) { - LOG_WARNING("解析JSON参数失败: %1, 使用默认值", e.what()); - d->localPort = 12345; - d->targetHost = "127.0.0.1"; - d->targetPort = 54321; - } - } -} - -void XNUDPService::PrepareForExecute() -{ - XNServiceObject::PrepareForExecute(); - T_D(); - // 初始化UDP socket - d->udpSocket = socket(AF_INET, SOCK_DGRAM, 0); - if (d->udpSocket < 0) { - LOG_WARNING("无法创建UDP socket"); - return; - } - - // 设置非阻塞模式 - int flags = fcntl(d->udpSocket, F_GETFL, 0); - fcntl(d->udpSocket, F_SETFL, flags | O_NONBLOCK); - - // 绑定本地端口 - struct sockaddr_in localAddr; - memset(&localAddr, 0, sizeof(localAddr)); - localAddr.sin_family = AF_INET; - localAddr.sin_addr.s_addr = INADDR_ANY; - localAddr.sin_port = htons(d->localPort); - - if (bind(d->udpSocket, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0) { - LOG_WARNING("UDP socket 绑定失败, 端口:%d", d->localPort); - close(d->udpSocket); - d->udpSocket = -1; - return; - } - - RegisterRTEventHandler("SendUDPData", - std::bind(&XNUDPService::SendData, this, std::placeholders::_1)); -} - -void XNUDPService::HandleIncomingData() -{ - T_D(); - if (d->udpSocket < 0) - return; - - char buffer[65536]; - struct sockaddr_in senderAddr; - socklen_t senderLen = sizeof(senderAddr); - - while (true) { - ssize_t bytesRead = recvfrom(d->udpSocket, buffer, sizeof(buffer), 0, - (struct sockaddr *)&senderAddr, &senderLen); - - if (bytesRead <= 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - break; // 没有更多数据 - } - LOG_WARNING("读取UDP socket失败"); - break; - } - - if (bytesRead <= 8) { - LOG_WARNING("UDP 数据包小于8字节"); - continue; - } - - // 将数据转换为XNByteArray - XNByteArray datagram; - datagram.resize(bytesRead); - memcpy(datagram.data(), buffer, bytesRead); - if (datagram[0] != 0xa6) { - LOG_WARNING("UDP 数据包头无效, 头:%1", datagram[0]); - continue; - } - - if (datagram[5] != 0x00) { - LOG_WARNING("UDP 数据包传输方向错误, 方向:%1", datagram[5]); - continue; - } - - uint16_t dataSize = ((uint16_t)datagram[6] << 8) | (uint16_t)datagram[7]; - if (dataSize != bytesRead) { - LOG_WARNING("UDP 数据包大小无效, 大小:%d, 实际大小:%zd", dataSize, bytesRead - 8); - continue; - } - - uint8_t planeHeader = datagram[1]; - uint8_t ataHeader = datagram[2]; - uint8_t modelHeader = datagram[3]; - uint8_t structHeader = datagram[4]; - - if (planeHeader == 0xc0) { //C909数据 - if (ataHeader == 0x04) { //ATA04章节数据 - if (modelHeader == 0x00 && structHeader == 0x00) { //气动输入数据 - TriggerRTEvent("C909::ATA04::AeroInput", datagram); - continue; - } else if (modelHeader == 0x01 && structHeader == 0x00) { //地操输入数据 - TriggerRTEvent("C909::ATA04::GhInput", datagram); - continue; - } else if (modelHeader == 0x02 && structHeader == 0x00) { //质量输入数据 - TriggerRTEvent("C909::ATA04::WbInput", datagram); - continue; - } - } - } else { - TriggerRTEvent("ReceiveUDPData", datagram); - } - } -} - -void XNUDPService::SendData(const std::any &data) -{ - T_D(); - if (d->udpSocket < 0) { - LOG_WARNING("UDP socket not initialized"); - return; - } - - struct sockaddr_in targetAddr; - memset(&targetAddr, 0, sizeof(targetAddr)); - targetAddr.sin_family = AF_INET; - targetAddr.sin_port = htons(d->targetPort); - inet_pton(AF_INET, d->targetHost.c_str(), &targetAddr.sin_addr); - - XNByteArray packet = std::any_cast(data); - ssize_t bytesSent = sendto(d->udpSocket, packet.data(), packet.size(), 0, - (struct sockaddr *)&targetAddr, sizeof(targetAddr)); - - if (bytesSent < 0) { - LOG_WARNING("Failed to send UDP datagram: %s", strerror(errno)); - } -} diff --git a/XNServices/XNUDPService/XNUDPService.h b/XNServices/XNUDPService/XNUDPService.h deleted file mode 100755 index 5c9a44a..0000000 --- a/XNServices/XNUDPService/XNUDPService.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include "XNUDPService_global.h" -#include -#include -#include - -struct XNUDPServicePrivate; - -class XNUDPSERVICE_EXPORT XNUDPService : public XNServiceObject -{ - XN_METATYPE(XNUDPService, XNServiceObject) - XN_DECLARE_PRIVATE(XNUDPService) -public: - explicit XNUDPService(); - virtual ~XNUDPService(); - -protected: - XNUDPService(PrivateType *p); - -public: - virtual void Initialize() override; - virtual void PrepareForExecute() override; - void HandleIncomingData(); - void SendData(const std::any &data); -}; - -XNCLASS_PTR_DECLARE(XNUDPService) diff --git a/XNServices/XNUDPService/XNUDPService.scfg b/XNServices/XNUDPService/XNUDPService.scfg deleted file mode 100755 index 8fa1279..0000000 --- a/XNServices/XNUDPService/XNUDPService.scfg +++ /dev/null @@ -1,17 +0,0 @@ - - - XNUDPService - UDP通信服务 - Jin - 1.0.0 - 2025-02-04 10:00:00 - 2025-02-04 10:00:00 - - - - - 12345 - 127.0.0.1 - 54321 - - diff --git a/XNServices/XNUDPService/XNUDPService_p.h b/XNServices/XNUDPService/XNUDPService_p.h deleted file mode 100755 index 1a2a6df..0000000 --- a/XNServices/XNUDPService/XNUDPService_p.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include - -struct XNUDPServicePrivate : public XNServiceObjectPrivate { - int udpSocket{-1}; - std::string targetHost; - uint16_t targetPort{0}; - uint16_t localPort{0}; -}; diff --git a/XNServices/XNUDPTestService/.vscode/c_cpp_properties.json b/XNServices/XNUDPTestService/.vscode/c_cpp_properties.json deleted file mode 100755 index 0b3cbd5..0000000 --- a/XNServices/XNUDPTestService/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "configurations": [ - { - "compileCommands": "${workspaceFolder}/build/compile_commands.json", - "configurationProvider": "ms-vscode.cmake-tools" - } - ], - "version": 4 -} \ No newline at end of file diff --git a/XNServices/XNUDPTestService/.vscode/settings.json b/XNServices/XNUDPTestService/.vscode/settings.json deleted file mode 100644 index 1507357..0000000 --- a/XNServices/XNUDPTestService/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "files.associations": { - "functional": "cpp" - } -} \ No newline at end of file diff --git a/XNServices/XNUDPTestService/CMakeLists.txt b/XNServices/XNUDPTestService/CMakeLists.txt deleted file mode 100755 index 61ba363..0000000 --- a/XNServices/XNUDPTestService/CMakeLists.txt +++ /dev/null @@ -1,65 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -project(XNUDPTestService LANGUAGES CXX) - -set(CMAKE_AUTOUIC ON) -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -# 获取环境变量 -if(DEFINED ENV{XNCore}) - set(XNCore_PATH $ENV{XNCore}) -else() - message(FATAL_ERROR "Environment variable XNCore is not set.") -endif() - -# 添加 XNCore_PATH 下的 include 目录为包含目录 -include_directories(${XNCore_PATH}/include) - -find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Network Xml) -find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Network Xml) - -add_library(XNUDPTestService SHARED - XNUDPTestService_global.h - XNUDPTestService.cpp - XNUDPTestService.h - XNUDPTestService_p.h -) - -target_link_libraries(XNUDPTestService PRIVATE - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Network - Qt${QT_VERSION_MAJOR}::Xml - ${XNCore_PATH}/lib/libXNCore.so - ) - -# 获取Qt库的安装路径 -get_target_property(QT_LIB_DIR Qt${QT_VERSION_MAJOR}::Core LOCATION) -get_filename_component(QT_LIB_DIR ${QT_LIB_DIR} DIRECTORY) - -# 设置rpath -set_target_properties(XNUDPTestService PROPERTIES - BUILD_WITH_INSTALL_RPATH TRUE - INSTALL_RPATH "${QT_LIB_DIR}" -) - -target_compile_definitions(XNUDPTestService PRIVATE XNUDPSERVICE_LIBRARY) - -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${XNCore_PATH}/Services" CACHE PATH "Install path prefix" FORCE) -endif() - -include(GNUInstallDirs) -install(TARGETS XNUDPTestService - BUNDLE DESTINATION . - LIBRARY DESTINATION . - RUNTIME DESTINATION . -) - -# 添加自定义命令和目标以拷贝配置文件 -file(GLOB CONFIG_FILE "*.scfg") - -# 使用 install 命令在安装时拷贝配置文件 -install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}) diff --git a/XNServices/XNUDPTestService/CMakeLists.txt.user b/XNServices/XNUDPTestService/CMakeLists.txt.user deleted file mode 100755 index 3432be7..0000000 --- a/XNServices/XNUDPTestService/CMakeLists.txt.user +++ /dev/null @@ -1,424 +0,0 @@ - - - - - - EnvironmentId - {5b958118-2d32-49ab-8eab-9018ac74c7d6} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - true - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - UTF-8 - false - 4 - false - 80 - true - true - 1 - 0 - false - true - false - 2 - true - true - 0 - 8 - true - false - 1 - true - true - true - *.md, *.MD, Makefile - false - true - true - - - - ProjectExplorer.Project.PluginSettings - - - true - false - true - true - true - true - - false - - - 0 - true - - true - true - Builtin.DefaultTidyAndClazy - 5 - true - - - - true - - - true - true - - - - - ProjectExplorer.Project.Target.0 - - Desktop - Desktop Qt 6.7.2 - Desktop Qt 6.7.2 - qt.qt6.672.linux_gcc_64_kit - 0 - 0 - 0 - - Debug - 2 - false - - -DCMAKE_GENERATOR:STRING=Unix Makefiles --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_BUILD_TYPE:STRING=Debug - 0 - /media/jin/E/MyCode/xnsim/XNModels/XNAerodynamics/build/Desktop_Qt_6_7_2-Debug - - - - - all - - false - - true - 构建 - CMakeProjectManager.MakeStep - - 1 - 构建 - 构建 - ProjectExplorer.BuildSteps.Build - - - - - - clean - - false - - true - 构建 - CMakeProjectManager.MakeStep - - 1 - 清除 - 清除 - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Debug - CMakeProjectManager.CMakeBuildConfiguration - - - Release - 2 - false - - -DCMAKE_GENERATOR:STRING=Unix Makefiles --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_BUILD_TYPE:STRING=Release - /media/jin/E/MyCode/xnsim/XNModels/XNAerodynamics/build/Desktop_Qt_6_7_2-Release - - - - - all - - false - - true - CMakeProjectManager.MakeStep - - 1 - 构建 - 构建 - ProjectExplorer.BuildSteps.Build - - - - - - clean - - false - - true - CMakeProjectManager.MakeStep - - 1 - 清除 - 清除 - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Release - CMakeProjectManager.CMakeBuildConfiguration - - - RelWithDebInfo - 2 - false - - -DCMAKE_GENERATOR:STRING=Unix Makefiles --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo - /media/jin/E/MyCode/xnsim/XNModels/XNAerodynamics/build/Desktop_Qt_6_7_2-RelWithDebInfo - - - - - all - - false - - true - CMakeProjectManager.MakeStep - - 1 - 构建 - 构建 - ProjectExplorer.BuildSteps.Build - - - - - - clean - - false - - true - CMakeProjectManager.MakeStep - - 1 - 清除 - 清除 - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Release with Debug Information - CMakeProjectManager.CMakeBuildConfiguration - - - RelWithDebInfo - 2 - false - - -DCMAKE_GENERATOR:STRING=Unix Makefiles --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo - 0 - /media/jin/E/MyCode/xnsim/XNModels/XNAerodynamics/build/Desktop_Qt_6_7_2-Profile - - - - - all - - false - - true - CMakeProjectManager.MakeStep - - 1 - 构建 - 构建 - ProjectExplorer.BuildSteps.Build - - - - - - clean - - false - - true - CMakeProjectManager.MakeStep - - 1 - 清除 - 清除 - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Profile - CMakeProjectManager.CMakeBuildConfiguration - - - MinSizeRel - 2 - false - - -DCMAKE_GENERATOR:STRING=Unix Makefiles --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_BUILD_TYPE:STRING=MinSizeRel - /media/jin/E/MyCode/xnsim/XNModels/XNAerodynamics/build/Desktop_Qt_6_7_2-MinSizeRel - - - - - all - - false - - true - CMakeProjectManager.MakeStep - - 1 - 构建 - 构建 - ProjectExplorer.BuildSteps.Build - - - - - - clean - - false - - true - CMakeProjectManager.MakeStep - - 1 - 清除 - 清除 - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Minimum Size Release - CMakeProjectManager.CMakeBuildConfiguration - - 5 - - - 0 - 部署 - 部署 - ProjectExplorer.BuildSteps.Deploy - - 1 - - false - ProjectExplorer.DefaultDeployConfiguration - - 1 - - true - true - 0 - true - - 2 - - false - -e cpu-cycles --call-graph dwarf,4096 -F 250 - - ProjectExplorer.CustomExecutableRunConfiguration - - false - true - true - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 22 - - - Version - 22 - - diff --git a/XNServices/XNUDPTestService/XNUDPTestService.cpp b/XNServices/XNUDPTestService/XNUDPTestService.cpp deleted file mode 100755 index 72a533a..0000000 --- a/XNServices/XNUDPTestService/XNUDPTestService.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include "XNUDPTestService.h" -#include "XNUDPTestService_p.h" -#include -#include -#include -#include - -XN_DLL_INITIALIZE(XNUDPTestService) - -XN_REGISTER_SERVICE_BEGIN_SERVICE(XNUDPTestService) -XN_REGISTER_SERVICE_END_SERVICE(XNUDPTestService) - -XNUDPTestService::XNUDPTestService(QObject *parent) - : XNServiceObject(*new XNUDPTestServicePrivate(this), parent) -{ -} - -XNUDPTestService::~XNUDPTestService() -{ -} - -XNUDPTestService::XNUDPTestService(XNUDPTestServicePrivate &dd, QObject *parent) - : XNServiceObject(dd, parent) -{ -} - -void XNUDPTestService::OnInitialize() -{ - Q_D(XNUDPTestService); - XNServiceObject::OnInitialize(); - - // 读取配置文件 - QFile file(GetXmlPath()); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - LOG_WARNING("Failed to open config file:%1", GetXmlPath()); - return; - } - - QDomDocument doc; - if (!doc.setContent(&file)) { - file.close(); - LOG_WARNING("Failed to parse config file:%1", GetXmlPath()); - return; - } - file.close(); - - // 读取UDP配置 - QDomElement udpElement = doc.documentElement().firstChildElement("UDP"); - if (!udpElement.isNull()) { - d->localPort = udpElement.firstChildElement("LocalPort").text().toUInt(); - d->targetHost = udpElement.firstChildElement("TargetHost").text(); - d->targetPort = udpElement.firstChildElement("TargetPort").text().toUInt(); - } else { - LOG_WARNING("UDP configuration not found, using default values"); - d->localPort = 12345; - d->targetHost = "127.0.0.1"; - d->targetPort = 54321; - } -} - -void XNUDPTestService::OnPrepareForExecute() -{ - Q_D(XNUDPTestService); - XNServiceObject::OnPrepareForExecute(); - - // 初始化UDP socket - d->udpSocket = new QUdpSocket(this); - - // 绑定本地端口 - if (!d->udpSocket->bind(QHostAddress::Any, d->localPort)) { - LOG_WARNING("UDP socket bind failed on port:%1", d->localPort); - return; - } - - // 连接UDP socket的信号 - //connect(d->udpSocket, &QUdpSocket::readyRead, this, &XNUDPTestService::HandleIncomingData); - - RegisterRTEventHandler("SendTestUDPData", - std::bind(&XNUDPTestService::SendData, this, std::placeholders::_1)); -} - -void XNUDPTestService::HandleIncomingData() -{ - Q_D(XNUDPTestService); - return; - while (d->udpSocket->hasPendingDatagrams()) { - QByteArray datagram; - datagram.resize(d->udpSocket->pendingDatagramSize()); - QHostAddress sender; - quint16 senderPort; - - d->udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); - - // 处理接收到的数据 - if (datagram.size() <= 5 || datagram[0] != 0x0b || datagram[4] != datagram.size()) { - LOG_WARNING("Invalid UDP datagram received"); - continue; - } - if (datagram[1] == 0x04) { - if (datagram[2] == 0x00 && datagram[3] == 0x00) { - TriggerRTEvent("ATA04AeroInput", datagram); - continue; - } else if (datagram[2] == 0x01 && datagram[3] == 0x00) { - TriggerRTEvent("ATA04GhInput", datagram); - continue; - } else if (datagram[2] == 0x02 && datagram[3] == 0x00) { - TriggerRTEvent("ATA04WbInput", datagram); - continue; - } - } - // TODO: 根据具体需求处理其它数据 - //TriggerRTEvent("ReceiveUDPData", datagram); - } -} - -void XNUDPTestService::SendData(const QVariant &data) -{ - Q_D(XNUDPTestService); - if (!d->udpSocket) { - LOG_WARNING("UDP socket not initialized"); - return; - } - - // 将QVariant转换为字节数组 - QByteArray datagram = data.toByteArray(); - - // 发送数据 - qint64 bytesSent = - d->udpSocket->writeDatagram(datagram, QHostAddress(d->targetHost), d->targetPort); - if (bytesSent == -1) { - LOG_WARNING("Failed to send UDP datagram:%1", d->udpSocket->errorString()); - } -} diff --git a/XNServices/XNUDPTestService/XNUDPTestService.h b/XNServices/XNUDPTestService/XNUDPTestService.h deleted file mode 100755 index 0ca8f22..0000000 --- a/XNServices/XNUDPTestService/XNUDPTestService.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#include "XNUDPTestService_global.h" -#include -#include -class XNUDPTestServicePrivate; - -class XNUDPTESTSERVICE_EXPORT XNUDPTestService : public XNServiceObject -{ - Q_OBJECT - Q_DISABLE_COPY(XNUDPTestService) - Q_DECLARE_PRIVATE(XNUDPTestService) - XN_DECLARE_DDS_SERVICE() -public: - explicit XNUDPTestService(QObject *parent = nullptr); - virtual ~XNUDPTestService(); - -protected: - XNUDPTestService(XNUDPTestServicePrivate &dd, QObject *parent = nullptr); - -public slots: - virtual void OnInitialize() override; - virtual void OnPrepareForExecute() override; - void HandleIncomingData(); - -public: - void SendData(const QVariant &data); -}; - -Q_DECLARE_METATYPE(XNUDPTestService) diff --git a/XNServices/XNUDPTestService/XNUDPTestService.scfg b/XNServices/XNUDPTestService/XNUDPTestService.scfg deleted file mode 100755 index d80e723..0000000 --- a/XNServices/XNUDPTestService/XNUDPTestService.scfg +++ /dev/null @@ -1,17 +0,0 @@ - - - XNUDPTestService - UDP通信服务 - Jin - 1.0.0 - 2025-02-04 10:00:00 - 2025-02-04 10:00:00 - - - - - 54321 - 127.0.0.1 - 12345 - - diff --git a/XNServices/XNUDPTestService/XNUDPTestService_global.h b/XNServices/XNUDPTestService/XNUDPTestService_global.h deleted file mode 100755 index ad16e20..0000000 --- a/XNServices/XNUDPTestService/XNUDPTestService_global.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef XNUDPTESTSERVICE_GLOBAL_H -#define XNUDPTESTSERVICE_GLOBAL_H - -#include - -#if defined(XNUDPTESTSERVICE_LIBRARY) -# define XNUDPTESTSERVICE_EXPORT Q_DECL_EXPORT -#else -# define XNUDPTESTSERVICE_EXPORT Q_DECL_IMPORT -#endif - -#endif // XNUDPTESTSERVICE_GLOBAL_H diff --git a/XNServices/XNUDPTestService/XNUDPTestService_p.h b/XNServices/XNUDPTestService/XNUDPTestService_p.h deleted file mode 100755 index 636b0bb..0000000 --- a/XNServices/XNUDPTestService/XNUDPTestService_p.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include -#include -#include - -class XNUDPTestServicePrivate : public XNServiceObjectPrivate -{ -public: - Q_DECLARE_PUBLIC(XNUDPTestService) - - XNUDPTestServicePrivate(XNUDPTestService *q) : XNServiceObjectPrivate(q) {} - - QUdpSocket *udpSocket{nullptr}; - QString targetHost; - quint16 targetPort{0}; - quint16 localPort{0}; -}; diff --git a/XNSimPortal/components/service-development.js b/XNSimPortal/components/service-development.js index e78abe7..ad58c3b 100644 --- a/XNSimPortal/components/service-development.js +++ b/XNSimPortal/components/service-development.js @@ -407,7 +407,7 @@ class ServiceDevelopment extends HTMLElement { async init() { try { - const response = await fetch('/api/services'); + const response = await fetch('/api/service-dev/services'); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } @@ -421,7 +421,7 @@ class ServiceDevelopment extends HTMLElement { async fetchServiceVersions(className, serviceName) { try { - const response = await fetch(`/api/service-versions/${encodeURIComponent(className)}`); + const response = await fetch(`/api/service-dev/service-versions/${encodeURIComponent(className)}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } @@ -466,7 +466,7 @@ class ServiceDevelopment extends HTMLElement { versionData.OtherParam = '{}'; } - const response = await fetch('/api/service-versions', { + const response = await fetch('/api/service-dev/service-versions', { method: 'POST', headers: { 'Content-Type': 'application/json' @@ -1758,7 +1758,7 @@ class ServiceDevelopment extends HTMLElement { Description: serviceData.Description || '' }; - const response = await fetch('/api/services', { + const response = await fetch('/api/service-dev/services', { method: 'POST', headers: { 'Content-Type': 'application/json' @@ -1779,31 +1779,376 @@ class ServiceDevelopment extends HTMLElement { } // 生成模板代码 - generateTemplateCode() { - console.log('生成模板代码功能'); - // TODO: 实现生成模板代码的具体功能 - alert('生成模板代码功能即将上线'); + async generateTemplateCode() { + try { + // 检查是否有当前版本数据 + if (!this.currentVersion || !this.currentVersion.ClassName || !this.currentVersion.Version) { + alert('请先保存版本信息,然后再生成模板代码'); + return; + } + + // 找到对应的按钮并更新状态 + const buttons = this.shadowRoot.querySelectorAll('button'); + const button = Array.from(buttons).find(btn => + btn.textContent.includes('生成模板代码') || + btn.onclick && btn.onclick.toString().includes('generateTemplateCode') + ); + const originalText = button ? button.textContent : '生成模板代码'; + + if (button) { + button.textContent = '正在生成...'; + button.disabled = true; + } + + // 调用生成代码API + const response = await fetch('/api/service-dev/generate-code', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + className: this.currentVersion.ClassName, + version: this.currentVersion.Version + }) + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.error || `HTTP错误! 状态码: ${response.status}`); + } + + const result = await response.json(); + + if (result.success) { + alert(`模板代码生成成功!\n${result.message}`); + } else { + throw new Error(result.error || '生成失败'); + } + } catch (error) { + console.error('生成模板代码失败:', error); + alert(`生成模板代码失败: ${error.message}`); + } finally { + // 恢复按钮状态 + const buttons = this.shadowRoot.querySelectorAll('button'); + const button = Array.from(buttons).find(btn => + btn.textContent.includes('正在生成...') || + btn.textContent.includes('生成模板代码') + ); + if (button) { + button.textContent = '生成模板代码'; + button.disabled = false; + } + } } // 下载模板代码 - downloadTemplateCode() { - console.log('下载模板代码功能'); - // TODO: 实现下载模板代码的具体功能 - alert('下载模板代码功能即将上线'); + async downloadTemplateCode() { + try { + // 检查是否有当前版本数据 + if (!this.currentVersion || !this.currentVersion.ClassName || !this.currentVersion.Version) { + alert('请先保存版本信息,然后再下载模板代码'); + return; + } + + // 找到对应的按钮并更新状态 + const buttons = this.shadowRoot.querySelectorAll('button'); + const button = Array.from(buttons).find(btn => + btn.textContent.includes('下载模板代码') || + btn.onclick && btn.onclick.toString().includes('downloadTemplateCode') + ); + const originalText = button ? button.textContent : '下载模板代码'; + + if (button) { + button.textContent = '正在打包...'; + button.disabled = true; + } + + // 第一步:调用打包API + const zipResponse = await fetch('/api/service-dev/zip-code', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + className: this.currentVersion.ClassName, + version: this.currentVersion.Version + }) + }); + + if (!zipResponse.ok) { + const errorData = await zipResponse.json(); + throw new Error(errorData.error || `打包失败! 状态码: ${zipResponse.status}`); + } + + const zipResult = await zipResponse.json(); + + if (!zipResult.success) { + throw new Error(zipResult.error || '打包失败'); + } + + // 更新按钮状态为下载中 + if (button) { + button.textContent = '正在下载...'; + } + + // 第二步:调用下载API + const downloadResponse = await fetch('/api/service-dev/download-zip', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + filePath: zipResult.dstPath + }) + }); + + if (!downloadResponse.ok) { + const errorData = await downloadResponse.json(); + throw new Error(errorData.error || `下载失败! 状态码: ${downloadResponse.status}`); + } + + // 获取文件名 + const fileName = `${this.currentVersion.ClassName}_${this.currentVersion.Version}.zip`; + + // 创建下载链接 + const blob = await downloadResponse.blob(); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = fileName; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + document.body.removeChild(a); + + alert(`模板代码下载成功!\n文件路径: ${zipResult.dstPath}\n文件名: ${fileName}`); + } catch (error) { + console.error('下载模板代码失败:', error); + alert(`下载模板代码失败: ${error.message}`); + } finally { + // 恢复按钮状态 + const buttons = this.shadowRoot.querySelectorAll('button'); + const button = Array.from(buttons).find(btn => + btn.textContent.includes('正在下载...') || + btn.textContent.includes('正在打包...') || + btn.textContent.includes('下载模板代码') + ); + if (button) { + button.textContent = '下载模板代码'; + button.disabled = false; + } + } } // 上传服务代码 - uploadServiceCode() { - console.log('上传服务代码功能'); - // TODO: 实现上传服务代码的具体功能 - alert('上传服务代码功能即将上线'); + async uploadServiceCode() { + try { + // 检查是否有当前版本数据 + if (!this.currentVersion || !this.currentVersion.ClassName || !this.currentVersion.Version) { + alert('请先保存版本信息,然后再上传服务代码'); + return; + } + + // 找到对应的按钮并更新状态 + const buttons = this.shadowRoot.querySelectorAll('button'); + const button = Array.from(buttons).find(btn => + btn.textContent.includes('上传服务代码') || + btn.onclick && btn.onclick.toString().includes('uploadServiceCode') + ); + const originalText = button ? button.textContent : '上传服务代码'; + + if (button) { + button.textContent = '选择文件中...'; + button.disabled = true; + } + + // 创建文件输入元素 + const fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.accept = '.zip'; + fileInput.style.display = 'none'; + + // 添加到DOM + document.body.appendChild(fileInput); + + // 监听文件选择 + fileInput.addEventListener('change', async (event) => { + const file = event.target.files[0]; + if (!file) { + // 恢复按钮状态 + const buttons = this.shadowRoot.querySelectorAll('button'); + const button = Array.from(buttons).find(btn => + btn.textContent.includes('选择文件中...') || + btn.textContent.includes('上传服务代码') + ); + if (button) { + button.textContent = '上传服务代码'; + button.disabled = false; + } + document.body.removeChild(fileInput); + return; + } + + try { + // 验证文件类型 + if (!file.name.toLowerCase().endsWith('.zip')) { + throw new Error('请选择ZIP格式的压缩包文件'); + } + + // 更新按钮状态为上传中 + if (button) { + button.textContent = '正在上传...'; + } + + // 第一步:上传文件 + const formData = new FormData(); + formData.append('file', file); + formData.append('className', this.currentVersion.ClassName); + formData.append('version', this.currentVersion.Version); + + const uploadResponse = await fetch('/api/service-dev/upload-zip', { + method: 'POST', + body: formData + }); + + if (!uploadResponse.ok) { + const errorData = await uploadResponse.json(); + throw new Error(errorData.error || `上传失败! 状态码: ${uploadResponse.status}`); + } + + const uploadResult = await uploadResponse.json(); + + if (!uploadResult.success) { + throw new Error(uploadResult.error || '上传失败'); + } + + // 更新按钮状态为解压中 + if (button) { + button.textContent = '正在解压...'; + } + + // 第二步:解压文件 + const unzipResponse = await fetch('/api/service-dev/unzip-code', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + className: this.currentVersion.ClassName, + version: this.currentVersion.Version, + srcPath: uploadResult.filePath + }) + }); + + if (!unzipResponse.ok) { + const errorData = await unzipResponse.json(); + throw new Error(errorData.error || `解压失败! 状态码: ${unzipResponse.status}`); + } + + const unzipResult = await unzipResponse.json(); + + if (unzipResult.success) { + alert(`服务代码上传并解压成功!\n原始文件名: ${uploadResult.originalName}\n保存路径: ${uploadResult.filePath}\n${unzipResult.message}`); + } else { + throw new Error(unzipResult.error || '解压失败'); + } + + } catch (error) { + console.error('上传服务代码失败:', error); + alert(`上传服务代码失败: ${error.message}`); + } finally { + // 恢复按钮状态 + if (button) { + button.textContent = '上传服务代码'; + button.disabled = false; + } + // 清理文件输入元素 + document.body.removeChild(fileInput); + } + }); + + // 触发文件选择对话框 + fileInput.click(); + + } catch (error) { + console.error('上传服务代码失败:', error); + alert(`上传服务代码失败: ${error.message}`); + // 恢复按钮状态 + const buttons = this.shadowRoot.querySelectorAll('button'); + const button = Array.from(buttons).find(btn => + btn.textContent.includes('选择文件中...') || + btn.textContent.includes('正在上传...') || + btn.textContent.includes('正在解压...') || + btn.textContent.includes('上传服务代码') + ); + if (button) { + button.textContent = '上传服务代码'; + button.disabled = false; + } + } } // 服务编译发布 - compileAndPublishService() { - console.log('服务编译发布功能'); - // TODO: 实现服务编译发布的具体功能 - alert('服务编译发布功能即将上线'); + async compileAndPublishService() { + try { + // 检查是否有当前版本数据 + if (!this.currentVersion || !this.currentVersion.ClassName || !this.currentVersion.Version) { + alert('请先保存版本信息,然后再编译发布服务'); + return; + } + + // 找到对应的按钮并更新状态 + const buttons = this.shadowRoot.querySelectorAll('button'); + const button = Array.from(buttons).find(btn => + btn.textContent.includes('服务编译发布') || + btn.onclick && btn.onclick.toString().includes('compileAndPublishService') + ); + const originalText = button ? button.textContent : '服务编译发布'; + + if (button) { + button.textContent = '正在编译...'; + button.disabled = true; + } + + // 调用编译API + const response = await fetch('/api/service-dev/compile-code', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + className: this.currentVersion.ClassName, + version: this.currentVersion.Version + }) + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.error || `HTTP错误! 状态码: ${response.status}`); + } + + const result = await response.json(); + + if (result.success) { + alert(`服务编译发布成功!\n${result.message}`); + } else { + throw new Error(result.error || '编译失败'); + } + } catch (error) { + console.error('服务编译发布失败:', error); + alert(`服务编译发布失败: ${error.message}`); + } finally { + // 恢复按钮状态 + const buttons = this.shadowRoot.querySelectorAll('button'); + const button = Array.from(buttons).find(btn => + btn.textContent.includes('正在编译...') || + btn.textContent.includes('服务编译发布') + ); + if (button) { + button.textContent = '服务编译发布'; + button.disabled = false; + } + } } } diff --git a/XNSimPortal/routes/service-dev.js b/XNSimPortal/routes/service-dev.js index 1c5a731..333e90b 100644 --- a/XNSimPortal/routes/service-dev.js +++ b/XNSimPortal/routes/service-dev.js @@ -1,11 +1,20 @@ const express = require('express'); const router = express.Router(); +const multer = require('multer'); +const path = require('path'); +const fs = require('fs'); const { getServices, getServiceVersionsByClassName, saveServiceVersion, createService } = require('../utils/service-utils'); +const { + serviceCodeGen, + serviceCodeZip, + serviceCodeUnzip, + serviceCodeCompile +} = require('../utils/xnCoreService'); // 获取所有服务列表 router.get('/services', (req, res) => { @@ -105,4 +114,222 @@ router.post('/services', (req, res) => { } }); +// 生成服务代码 +router.post('/generate-code', (req, res) => { + try { + const { className, version } = req.body; + + if (!className || !version) { + return res.status(400).json({ error: '缺少必要的参数:className 和 version' }); + } + + const result = serviceCodeGen(className, version); + + if (result.includes('成功')) { + res.json({ success: true, message: result }); + } else { + res.status(500).json({ success: false, error: result }); + } + } catch (error) { + console.error(`生成服务代码失败: ${error.message}`); + res.status(500).json({ error: '生成服务代码失败', details: error.message }); + } +}); + +// 压缩服务代码 +router.post('/zip-code', (req, res) => { + try { + const { className, version } = req.body; + + if (!className || !version) { + return res.status(400).json({ error: '缺少必要的参数:className 和 version' }); + } + + const result = serviceCodeZip(className, version); + + if (result.success) { + res.json({ + success: true, + message: result.message, + dstPath: result.dstPath + }); + } else { + res.status(500).json({ success: false, error: result.message }); + } + } catch (error) { + console.error(`压缩服务代码失败: ${error.message}`); + res.status(500).json({ error: '压缩服务代码失败', details: error.message }); + } +}); + +// 解压服务代码 +router.post('/unzip-code', (req, res) => { + try { + const { className, version, srcPath } = req.body; + + if (!className || !version || !srcPath) { + return res.status(400).json({ error: '缺少必要的参数:className、version 和 srcPath' }); + } + + const result = serviceCodeUnzip(className, version, srcPath); + + if (result.includes('成功')) { + res.json({ success: true, message: result }); + } else { + res.status(500).json({ success: false, error: result }); + } + } catch (error) { + console.error(`解压服务代码失败: ${error.message}`); + res.status(500).json({ error: '解压服务代码失败', details: error.message }); + } +}); + +// 编译服务代码 +router.post('/compile-code', (req, res) => { + try { + const { className, version } = req.body; + + if (!className || !version) { + return res.status(400).json({ error: '缺少必要的参数:className 和 version' }); + } + + const result = serviceCodeCompile(className, version); + + if (result.includes('成功')) { + res.json({ success: true, message: result }); + } else { + res.status(500).json({ success: false, error: result }); + } + } catch (error) { + console.error(`编译服务代码失败: ${error.message}`); + res.status(500).json({ error: '编译服务代码失败', details: error.message }); + } +}); + +// 下载ZIP文件 +router.post('/download-zip', (req, res) => { + try { + const { filePath } = req.body; + + if (!filePath) { + return res.status(400).json({ error: '缺少文件路径参数' }); + } + + // 检查文件是否存在 + if (!fs.existsSync(filePath)) { + return res.status(404).json({ error: '文件不存在' }); + } + + // 检查文件是否为ZIP格式 + if (!filePath.toLowerCase().endsWith('.zip')) { + return res.status(400).json({ error: '只能下载ZIP格式的文件' }); + } + + // 获取文件名 + const fileName = path.basename(filePath); + + // 设置响应头 + res.setHeader('Content-Type', 'application/zip'); + res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`); + + // 发送文件 + res.sendFile(filePath); + } catch (error) { + console.error(`下载ZIP文件失败: ${error.message}`); + res.status(500).json({ error: '下载ZIP文件失败', details: error.message }); + } +}); + +// 配置multer用于文件上传 +const storage = multer.diskStorage({ + destination: function (req, file, cb) { + // 获取XNCore环境变量 + const xnCorePath = process.env.XNCore || ''; + if (!xnCorePath) { + return cb(new Error('XNCore环境变量未设置')); + } + + // 创建ServiceProjects目录 + const serviceProjectsDir = path.join(xnCorePath, 'ServiceProjects'); + if (!fs.existsSync(serviceProjectsDir)) { + fs.mkdirSync(serviceProjectsDir, { recursive: true }); + } + cb(null, serviceProjectsDir); + }, + filename: function (req, file, cb) { + cb(null, file.originalname); + } +}); + +const upload = multer({ + storage: storage, + fileFilter: function (req, file, cb) { + // 只允许ZIP文件 + if (file.mimetype === 'application/zip' || file.originalname.toLowerCase().endsWith('.zip')) { + cb(null, true); + } else { + cb(new Error('只允许上传ZIP格式的文件'), false); + } + }, + limits: { + fileSize: 100 * 1024 * 1024 // 限制100MB + } +}); + +// 上传ZIP文件 +router.post('/upload-zip', upload.single('file'), (req, res) => { + try { + // 检查XNCore环境变量 + const xnCorePath = process.env.XNCore || ''; + if (!xnCorePath) { + return res.status(500).json({ error: 'XNCore环境变量未设置' }); + } + + if (!req.file) { + return res.status(400).json({ error: '没有选择文件' }); + } + + const filePath = req.file.path; + const fileName = req.file.filename; + + // 验证文件是否成功保存到ServiceProjects目录 + if (!fs.existsSync(filePath)) { + return res.status(500).json({ error: '文件上传失败,文件未保存到目标目录' }); + } + + res.json({ + success: true, + message: '文件上传成功', + filePath: filePath, + fileName: fileName, + originalName: req.file.originalname, + uploadDir: path.dirname(filePath) + }); + } catch (error) { + console.error(`上传ZIP文件失败: ${error.message}`); + res.status(500).json({ error: '上传ZIP文件失败', details: error.message }); + } +}); + +// 处理multer错误 +router.use('/upload-zip', (error, req, res, next) => { + if (error instanceof multer.MulterError) { + if (error.code === 'LIMIT_FILE_SIZE') { + return res.status(400).json({ error: '文件大小超过限制(最大100MB)' }); + } + return res.status(400).json({ error: `文件上传错误: ${error.message}` }); + } + + if (error.message === 'XNCore环境变量未设置') { + return res.status(500).json({ error: 'XNCore环境变量未设置,无法上传文件' }); + } + + if (error.message.includes('只允许上传ZIP格式的文件')) { + return res.status(400).json({ error: '只允许上传ZIP格式的文件' }); + } + + console.error('文件上传错误:', error); + res.status(500).json({ error: '文件上传失败', details: error.message }); +}); + module.exports = router; \ No newline at end of file diff --git a/XNSimPortal/server.js b/XNSimPortal/server.js index 61225a1..24ecb65 100644 --- a/XNSimPortal/server.js +++ b/XNSimPortal/server.js @@ -94,7 +94,7 @@ app.use('/api', authRoutes); app.use('/api', versionRoutes); app.use('/api/filesystem', filesystemRoutes); app.use('/api', systemInfoRoutes); -app.use('/api', serviceApiRoutes); +app.use('/api/service-dev', serviceApiRoutes); app.use('/api', ataChaptersRoutes); app.use('/api', simulationRoutes); app.use('/api/udp-monitor', udpMonitorRoutes); diff --git a/XNSimPortal/utils/xnCoreService.js b/XNSimPortal/utils/xnCoreService.js index 3bfe521..253e8b5 100644 --- a/XNSimPortal/utils/xnCoreService.js +++ b/XNSimPortal/utils/xnCoreService.js @@ -27,6 +27,10 @@ const interfaceGenLibPath = path.join(xnCorePath, 'lib', interfaceGenLibName); const modelGenLibName = `${libPrefix}XNModelGenServer${libExtension}`; const modelGenLibPath = path.join(xnCorePath, 'lib', modelGenLibName); +// ServiceGenServer库配置 +const serviceGenLibName = `${libPrefix}XNServiceGenServer${libExtension}`; +const serviceGenLibPath = path.join(xnCorePath, 'lib', serviceGenLibName); + // 定义Buffer类型 const BufferType = ref.refType(ref.types.void); const StringType = ref.types.CString; @@ -37,6 +41,7 @@ let loginLib; let monitorLib; let interfaceGenLib; let modelGenLib; +let serviceGenLib; try { loginLib = ffi.Library(loginLibPath, { @@ -115,6 +120,17 @@ try { console.error(`加载 ${modelGenLibName} 失败:`, error); } +try { + serviceGenLib = ffi.Library(serviceGenLibPath, { + 'XNServiceCodeGen': ['int', [StringType, 'int', StringType, 'int', StringType, 'int']], + 'XNServiceCodeZip': ['int', [StringType, 'int', StringType, 'int', StringType, 'int', StringType, 'int']], + 'XNServiceCodeUnzip': ['int', [StringType, 'int', StringType, 'int', StringType, 'int', StringType, 'int']], + 'XNServiceCodeCompile': ['int', [StringType, 'int', StringType, 'int', StringType, 'int']] + }); +} catch (error) { + console.error(`加载 ${serviceGenLibName} 失败:`, error); +} + // 注册进程退出时的清理函数 function performCleanup() { console.log('正在执行清理操作...'); @@ -907,11 +923,108 @@ function modelCodeCompile(className, version, planeName) { } } +// ========== XNServiceGenServer 封装函数 ========== + +// 生成服务代码 +function serviceCodeGen(className, version) { + if (!serviceGenLib) { + return '服务生成库未加载'; + } + try { + const errorMsg = Buffer.alloc(1024); + const result = serviceGenLib.XNServiceCodeGen( + className, className.length, + version, version.length, + errorMsg, errorMsg.length + ); + if (result !== 0) { + return `生成服务代码失败: ${errorMsg.toString('utf8').replace(/\0/g, '')}`; + } + return '生成服务代码成功'; + } catch (error) { + return `生成服务代码失败: ${error.message}`; + } +} + +// 压缩服务代码 +function serviceCodeZip(className, version) { + if (!serviceGenLib) { + return '服务生成库未加载'; + } + try { + const dstPath = Buffer.alloc(1024); + const errorMsg = Buffer.alloc(1024); + const result = serviceGenLib.XNServiceCodeZip( + className, className.length, + version, version.length, + dstPath, dstPath.length, + errorMsg, errorMsg.length + ); + if (result !== 0) { + return `压缩服务代码失败: ${errorMsg.toString('utf8').replace(/\0/g, '')}`; + } + return { + success: true, + dstPath: dstPath.toString('utf8').replace(/\0/g, ''), + message: '压缩服务代码成功' + }; + } catch (error) { + return { + success: false, + message: `压缩服务代码失败: ${error.message}` + }; + } +} + +// 解压服务代码 +function serviceCodeUnzip(className, version, srcPath) { + if (!serviceGenLib) { + return '服务生成库未加载'; + } + try { + const errorMsg = Buffer.alloc(1024); + const result = serviceGenLib.XNServiceCodeUnzip( + className, className.length, + version, version.length, + srcPath, srcPath.length, + errorMsg, errorMsg.length + ); + if (result !== 0) { + return `解压服务代码失败: ${errorMsg.toString('utf8').replace(/\0/g, '')}`; + } + return '解压服务代码成功'; + } catch (error) { + return `解压服务代码失败: ${error.message}`; + } +} + +// 编译服务代码 +function serviceCodeCompile(className, version) { + if (!serviceGenLib) { + return '服务生成库未加载'; + } + try { + const errorMsg = Buffer.alloc(1024); + const result = serviceGenLib.XNServiceCodeCompile( + className, className.length, + version, version.length, + errorMsg, errorMsg.length + ); + if (result !== 0) { + return `编译服务代码失败: ${errorMsg.toString('utf8').replace(/\0/g, '')}`; + } + return '编译服务代码成功'; + } catch (error) { + return `编译服务代码失败: ${error.message}`; + } +} + module.exports = { loginLib, monitorLib, interfaceGenLib, modelGenLib, + serviceGenLib, performCleanup, stringToBuffer, initializeMonitor, @@ -954,5 +1067,9 @@ module.exports = { modelCodeGen, modelCodeZip, modelCodeUnzip, - modelCodeCompile + modelCodeCompile, + serviceCodeGen, + serviceCodeZip, + serviceCodeUnzip, + serviceCodeCompile }; \ No newline at end of file