// MFCCreoDll.cpp: 定义 DLL 的初始化例程。 // #include "pch.h" #include "framework.h" #include "MFCCreoDll.h" #include "HttpServer.h" #include "CreoManager.h" #include "ShellExportHandler.h" #include "PathDeleteManager.h" #include "GeometryAnalyzer.h" #include "ModelSearchHandler.h" #include "HierarchyStatisticsAnalyzer.h" #include "ComponentChildrenManager.h" #include "BatchOperationManager.h" #include "Config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #pragma comment(lib, "winhttp.lib") #ifdef _DEBUG #define new DEBUG_NEW #endif // --- 全局变量 --- static std::unique_ptr g_http_server; static UINT_PTR timer_id = 0; // 无锁消息队列项 struct MessageItem { std::string type; // "SHOW_MESSAGE", "OPEN_MODEL_REQUEST", "SHRINKWRAP_SHELL_REQUEST", 或 "TIMEOUT_CLEANUP" std::string data; // 消息内容或文件路径或JSON数据 std::string extra; // 额外参数(如open_mode) volatile bool completed; // 完成标志 volatile bool timed_out; // 超时标志,用于指示HTTP请求已超时返回 void* result_ptr; // 结果指针 MessageItem() : completed(false), timed_out(false), result_ptr(nullptr) {} }; // 无锁同步机制 static volatile MessageItem* pending_message_item = nullptr; static std::atomic has_pending_item{false}; // --- 辅助函数:将 std::string 转换为 xstring --- xstring ConvertStringToXstring(const std::string& str) { std::wstring wstr(str.begin(), str.end()); return xstring(wstr.c_str()); } // 定时器回调函数,使用无锁消息机制处理消息 VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { // 使用无锁机制检查待处理消息 if (has_pending_item.load() && pending_message_item) { MessageItem* item = const_cast(pending_message_item); try { if (item->type == "OPEN_MODEL_REQUEST") { OpenResult result = CreoManager::Instance().OpenModel(item->data, item->extra); // 如果模式是active且模型成功打开,激活窗口 if (result.success && item->extra == "active") { try { pfcSession_ptr session = pfcGetCurrentSession(); if (session) { // 获取刚刚打开的模型 xstring filename_xstr = ConvertStringToXstring(result.model_name); pfcModelDescriptor_ptr desc = pfcModelDescriptor::CreateFromFileName(filename_xstr); pfcModel_ptr model = session->GetModelFromDescr(desc); if (model) { // 创建或激活模型窗口 pfcWindow_ptr modelWindow = session->CreateModelWindow(model); if (modelWindow) { try { modelWindow->Activate(); model->Display(); modelWindow->Refresh(); } catch (...) { // 激活失败,尝试设置为当前窗口 try { session->SetCurrentWindow(modelWindow); } catch (...) { } } // 尝试刷新窗口 try { modelWindow->Refresh(); } catch (...) { // 刷新失败不影响主要功能 } } } } } catch (...) { } } item->result_ptr = new OpenResult(result); item->completed = true; } else if (item->type == "SHRINKWRAP_SHELL_REQUEST") { // Shrinkwrap外壳导出处理 // 将JSON数据转换为HttpRequest格式 HttpRequest shrinkwrap_request; shrinkwrap_request.method = "POST"; shrinkwrap_request.path = "/api/creo/shrinkwrap/shell"; shrinkwrap_request.body = item->data; // 执行Shrinkwrap处理 HttpResponse response = ShellExportHandler::HandleShrinkwrapShellRequest(shrinkwrap_request); // 检查是否已超时,若超时则清理内存并跳过 if (item->timed_out) { // HTTP请求已超时返回,清理堆分配的MessageItem // 注意:response 是栈上的局部变量,不需要 delete delete item; pending_message_item = nullptr; has_pending_item = false; return; // 直接返回,不设置completed } // 保存结果(正常完成) item->result_ptr = new HttpResponse(response); item->completed = true; } else if (item->type == "SHOW_MESSAGE") { // 消息显示处理 CreoManager::Instance().ShowMessage(item->data); item->completed = true; } // 清理状态 pending_message_item = nullptr; has_pending_item = false; } catch (...) { // 异常处理 if (item->type == "OPEN_MODEL_REQUEST") { OpenResult* error_result = new OpenResult(); error_result->success = false; error_result->error_message = "Unexpected error during operation execution"; item->result_ptr = error_result; } else if (item->type == "SHRINKWRAP_SHELL_REQUEST") { HttpResponse* error_response = new HttpResponse(); error_response->status_code = 500; error_response->body = "{\"success\": false, \"error\": \"Unexpected error during shrinkwrap operation\"}"; item->result_ptr = error_response; } item->completed = true; pending_message_item = nullptr; has_pending_item = false; } } } // 测试路由处理器 HttpResponse TestHandler(const HttpRequest& request) { bool creo_connected = false; try { pfcSession_ptr session = pfcGetCurrentSessionWithCompatibility(pfcC4Compatible); creo_connected = (session != nullptr); } catch (...) { creo_connected = false; } std::ostringstream json; json << "{" << "\"success\": true," << "\"data\": {" << "\"running\": " << (creo_connected ? "true" : "false") << "," << "\"message\": \"" << (creo_connected ? "CREOSON 与 Creo 均已启动" : "Creo 未连接") << "\"" << "}," << "\"error\": null" << "}"; HttpResponse response; response.body = json.str(); return response; } // 显示消息路由处理器 HttpResponse ShowMessageHandler(const HttpRequest& request) { // 从查询参数获取消息 std::string message = "Default message"; size_t text_pos = request.query.find("text="); if (text_pos != std::string::npos) { text_pos += 5; // 跳过"text=" size_t end_pos = request.query.find("&", text_pos); if (end_pos == std::string::npos) { end_pos = request.query.length(); } message = request.query.substr(text_pos, end_pos - text_pos); } // 使用无锁消息机制 MessageItem message_item; message_item.type = "SHOW_MESSAGE"; message_item.data = message; // 原子设置(无锁) pending_message_item = &message_item; has_pending_item = true; // 等待主线程处理完成 while (!message_item.completed) { Sleep(10); } HttpResponse response; response.body = "{\"status\":\"ok\",\"message\":\"Message sent to Creo\"}"; return response; } // Creo状态检测路由处理器 HttpResponse CreoStatusHandler(const HttpRequest& request) { CreoStatus status = CreoManager::Instance().GetCreoStatus(); std::ostringstream json; json << "{" << "\"is_connected\":" << (status.is_connected ? "true" : "false") << "," << "\"version\":\"" << status.version << "\"," << "\"build\":\"" << status.build << "\"," << "\"working_directory\":\"" << status.working_directory << "\"," << "\"session_id\":" << status.session_id << "}"; HttpResponse response; response.body = json.str(); return response; } // 模型状态检测路由处理器 HttpResponse ModelStatusHandler(const HttpRequest& request) { ModelStatus status = CreoManager::Instance().GetModelStatus(); std::ostringstream json; if (status.has_model) { json << "{" << "\"success\": true," << "\"data\": {" << "\"name\": \"" << status.name << "\"," << "\"filename\": \"" << status.filename << "\"," << "\"type\": \"" << status.type << "\"," << "\"software\": \"" << status.software << "\"," << "\"version\": \"" << status.version << "\"," << "\"connectionTime\": \"" << status.connection_time << "\"," << "\"isAssembly\": " << (status.is_assembly ? "true" : "false") << ","; if (status.is_assembly) { json << "\"basicStats\": {" << "\"totalParts\": " << status.total_parts << "," << "\"assemblyLevels\": " << status.assembly_levels << "," << "\"fileSize\": \"" << status.file_size << "\"" << "},"; } json << "\"fileName\": \"" << status.filename << "\"," << "\"sourceSoftware\": \"" << status.software << "\"," << "\"partCount\": " << status.total_parts << "," << "\"assemblyLevel\": " << status.assembly_levels << "," << "\"fileSize\": \"" << status.file_size << "\"," << "\"connectionStatus\": \"" << status.connection_status << "\"," << "\"openTime\": \"" << status.open_time << "\"" << "}," << "\"error\": null" << "}"; } else { json << "{" << "\"success\": false," << "\"data\": null," << "\"error\": \"No model is currently open\"" << "}"; } HttpResponse response; response.body = json.str(); return response; } // 简单的JSON解析函数 std::string ExtractJsonValue(const std::string& json, const std::string& key) { // 查找键值对 "key": "value" std::string key_pattern = "\"" + key + "\""; size_t key_pos = json.find(key_pattern); if (key_pos != std::string::npos) { // 找到冒号 size_t colon_pos = json.find(":", key_pos); if (colon_pos != std::string::npos) { // 跳过空格找到值的开始 size_t value_start = colon_pos + 1; while (value_start < json.length() && (json[value_start] == ' ' || json[value_start] == '\t' || json[value_start] == '\n' || json[value_start] == '\r')) { value_start++; } // 检查是否是字符串值(以双引号开始) if (value_start < json.length() && json[value_start] == '"') { size_t value_end = json.find('"', value_start + 1); if (value_end != std::string::npos) { return json.substr(value_start + 1, value_end - value_start - 1); } } // 处理数字值(不以双引号开始) else if (value_start < json.length()) { size_t value_end = value_start; while (value_end < json.length() && json[value_end] != ',' && json[value_end] != '}' && json[value_end] != ']' && json[value_end] != ' ' && json[value_end] != '\t' && json[value_end] != '\n' && json[value_end] != '\r') { value_end++; } if (value_end > value_start) { return json.substr(value_start, value_end - value_start); } } } } return ""; } bool ExtractJsonBool(const std::string& json, const std::string& key) { std::regex pattern("\"" + key + "\"\s*:\s*(true|false)"); std::smatch match; if (std::regex_search(json, match, pattern)) { return match[1].str() == "true"; } return false; } // JSON字符串转义函数 std::string EscapeJsonString(const std::string& str) { std::string escaped = str; // Replace backslashes size_t pos = 0; while ((pos = escaped.find("\\", pos)) != std::string::npos) { escaped.replace(pos, 1, "\\\\"); pos += 2; } // Replace double quotes pos = 0; while ((pos = escaped.find("\"", pos)) != std::string::npos) { escaped.replace(pos, 1, "\\\""); pos += 2; } // Replace newlines pos = 0; while ((pos = escaped.find("\n", pos)) != std::string::npos) { escaped.replace(pos, 1, "\\n"); pos += 2; } // Replace tabs pos = 0; while ((pos = escaped.find("\t", pos)) != std::string::npos) { escaped.replace(pos, 1, "\\t"); pos += 2; } return escaped; } std::wstring Utf8ToWide(const std::string& input) { if (input.empty()) { return L""; } int required = MultiByteToWideChar(CP_UTF8, 0, input.c_str(), -1, nullptr, 0); if (required <= 0) { return L""; } std::wstring output(required, L'\0'); MultiByteToWideChar(CP_UTF8, 0, input.c_str(), -1, &output[0], required); if (!output.empty() && output.back() == L'\0') { output.pop_back(); } return output; } std::string GetCurrentIsoUtcTimeString() { std::time_t now = std::time(nullptr); std::tm utc_tm{}; gmtime_s(&utc_tm, &now); char buffer[32] = {0}; std::strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%SZ", &utc_tm); return std::string(buffer); } std::string BuildBatchCallbackUrl(const std::string& callback_server_address) { if (callback_server_address.empty()) { return ""; } std::string base = callback_server_address; while (!base.empty() && base.back() == '/') { base.pop_back(); } return base + "/api/v1/plugin-callbacks/task-result"; } std::string BuildBatchCallbackResultJson(const BatchOperationsResponse& batch_result) { std::ostringstream json; json << "{" << "\"total_operations\": " << batch_result.total_operations << "," << "\"successful_operations\": " << batch_result.successful_operations << "," << "\"failed_operations\": " << batch_result.failed_operations << "," << "\"execution_time\": \"" << EscapeJsonString(batch_result.execution_time) << "\"," << "\"results\": ["; for (size_t i = 0; i < batch_result.results.size(); ++i) { if (i > 0) json << ","; const BatchOperationResult& op_result = batch_result.results[i]; json << "{" << "\"operation_index\": " << op_result.operation_index << "," << "\"operation_type\": \"" << EscapeJsonString(op_result.operation_type) << "\"," << "\"success\": " << (op_result.success ? "true" : "false") << "," << "\"execution_time\": \"" << EscapeJsonString(op_result.execution_time) << "\""; if (op_result.success) { json << ",\"result\": " << op_result.result_json << ",\"error\": null"; } else { json << ",\"result\": null," << "\"error\": \"" << EscapeJsonString(op_result.error_message) << "\""; } json << "}"; } json << "]" << "}"; return json.str(); } std::string BuildTaskResultCallbackPayload(const std::string& execution_id, const std::string& software_id, bool is_success, const std::string& error_message, const std::string& result_json, const std::string& token) { std::ostringstream json; json << "{" << "\"execution_id\": \"" << EscapeJsonString(execution_id) << "\"," << "\"software_id\": \"" << EscapeJsonString(software_id) << "\"," << "\"status\": \"" << (is_success ? "success" : "failed") << "\","; if (is_success) { json << "\"error_message\": null,"; } else { json << "\"error_message\": \"" << EscapeJsonString(error_message) << "\","; } if (is_success) { json << "\"result\": " << result_json << ","; } else { json << "\"result\": {},"; } json << "\"finished_at\": \"" << GetCurrentIsoUtcTimeString() << "\"," << "\"token\": \"" << EscapeJsonString(token) << "\"" << "}"; return json.str(); } bool PostJsonToUrl(const std::string& url, const std::string& json_body, DWORD& http_status_code, std::string& error_message) { http_status_code = 0; error_message.clear(); std::wstring wurl = Utf8ToWide(url); if (wurl.empty()) { error_message = "Invalid callback URL"; return false; } URL_COMPONENTS components; ZeroMemory(&components, sizeof(components)); components.dwStructSize = sizeof(components); components.dwSchemeLength = (DWORD)-1; components.dwHostNameLength = (DWORD)-1; components.dwUrlPathLength = (DWORD)-1; components.dwExtraInfoLength = (DWORD)-1; if (!WinHttpCrackUrl(wurl.c_str(), 0, 0, &components)) { error_message = "WinHttpCrackUrl failed"; return false; } std::wstring host(components.lpszHostName, components.dwHostNameLength); std::wstring path(components.lpszUrlPath ? std::wstring(components.lpszUrlPath, components.dwUrlPathLength) : L"/"); if (components.dwExtraInfoLength > 0 && components.lpszExtraInfo) { path += std::wstring(components.lpszExtraInfo, components.dwExtraInfoLength); } bool secure = (components.nScheme == INTERNET_SCHEME_HTTPS); INTERNET_PORT port = components.nPort; DWORD flags = secure ? WINHTTP_FLAG_SECURE : 0; HINTERNET session = WinHttpOpen(L"MFCCreoDll/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); if (!session) { error_message = "WinHttpOpen failed"; return false; } DWORD timeout = 10000; WinHttpSetTimeouts(session, timeout, timeout, timeout, timeout); HINTERNET connection = WinHttpConnect(session, host.c_str(), port, 0); if (!connection) { WinHttpCloseHandle(session); error_message = "WinHttpConnect failed"; return false; } HINTERNET request = WinHttpOpenRequest(connection, L"POST", path.c_str(), nullptr, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, flags); if (!request) { WinHttpCloseHandle(connection); WinHttpCloseHandle(session); error_message = "WinHttpOpenRequest failed"; return false; } std::wstring headers = L"Content-Type: application/json\r\n"; bool send_ok = WinHttpSendRequest(request, headers.c_str(), (DWORD)-1, (LPVOID)json_body.data(), static_cast(json_body.size()), static_cast(json_body.size()), 0) == TRUE; if (!send_ok || WinHttpReceiveResponse(request, nullptr) != TRUE) { WinHttpCloseHandle(request); WinHttpCloseHandle(connection); WinHttpCloseHandle(session); error_message = "WinHTTP send/receive failed"; return false; } DWORD size = sizeof(http_status_code); WinHttpQueryHeaders(request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &http_status_code, &size, WINHTTP_NO_HEADER_INDEX); WinHttpCloseHandle(request); WinHttpCloseHandle(connection); WinHttpCloseHandle(session); return (http_status_code >= 200 && http_status_code < 300); } void SendTaskResultCallbackWithRetry(const std::string& callback_server_address, const std::string& execution_id, const std::string& software_id, const BatchOperationsResponse& batch_result, const std::string& callback_token) { if (callback_server_address.empty() || execution_id.empty() || callback_token.empty()) { return; } bool is_success = batch_result.success; std::string callback_error = batch_result.error_message; if (!is_success && callback_error.empty()) { callback_error = "Batch operations failed"; } std::string result_json = BuildBatchCallbackResultJson(batch_result); std::string payload = BuildTaskResultCallbackPayload( execution_id, software_id.empty() ? "creo" : software_id, is_success, callback_error, result_json, callback_token ); std::string callback_url = BuildBatchCallbackUrl(callback_server_address); if (callback_url.empty()) { return; } const std::vector retry_delays_seconds = {1, 3, 5}; const int max_attempts = 1 + static_cast(retry_delays_seconds.size()); for (int attempt = 0; attempt < max_attempts; ++attempt) { DWORD status_code = 0; std::string post_error; bool ok = PostJsonToUrl(callback_url, payload, status_code, post_error); if (ok) { return; } if (attempt < static_cast(retry_delays_seconds.size())) { std::this_thread::sleep_for(std::chrono::seconds(retry_delays_seconds[attempt])); } } } // 模型导出路由处理器 HttpResponse ExportModelHandler(const HttpRequest& request) { if (request.method != "POST") { HttpResponse response; response.status_code = 405; response.body = "{\"success\": false, \"error\": \"Method not allowed\"}"; return response; } // 解析JSON请求体 std::string software_type = ExtractJsonValue(request.body, "software_type"); std::string format_type = ExtractJsonValue(request.body, "format_type"); std::string export_path = ExtractJsonValue(request.body, "export_path"); // 提取options中的geom_flags - 简化处理,避免正则表达式崩溃 std::string geom_flags = "solids"; // 默认值 // 简单的字符串查找方式,避免正则表达式 size_t options_pos = request.body.find("\"options\""); if (options_pos != std::string::npos) { size_t start_brace = request.body.find("{", options_pos); if (start_brace != std::string::npos) { size_t end_brace = request.body.find("}", start_brace); if (end_brace != std::string::npos) { std::string options_content = request.body.substr(start_brace + 1, end_brace - start_brace - 1); std::string extracted_geom_flags = ExtractJsonValue(options_content, "geom_flags"); if (!extracted_geom_flags.empty()) { geom_flags = extracted_geom_flags; } } } } // 验证参数 if (software_type != "creo" || format_type != "step" || export_path.empty()) { HttpResponse response; response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Invalid parameters\"}"; return response; } // 执行导出 ExportResult result = CreoManager::Instance().ExportModelToSTEP(export_path, geom_flags); HttpResponse response; if (result.success) { std::ostringstream json; json << "{" << "\"success\": true," << "\"data\": {" << "\"exportPath\": \"" << EscapeJsonString(result.export_path) << "\"," << "\"fileSize\": \"" << result.file_size << "\"," << "\"format\": \"" << result.format << "\"," << "\"exportTime\": \"" << result.export_time << "\"," << "\"software\": \"" << result.software << "\"," << "\"originalFile\": \"" << EscapeJsonString(result.original_file) << "\"," << "\"details\": {" << "\"dirname\": \"" << EscapeJsonString(result.dirname) << "\"," << "\"filename\": \"" << EscapeJsonString(result.filename) << "\"," << "\"creoson_response\": {" << "\"dirname\": \"" << EscapeJsonString(result.dirname) << "\"," << "\"filename\": \"" << EscapeJsonString(result.filename) << "\"," << "\"full_path\": \"" << EscapeJsonString(result.export_path) << "\"" << "}" << "}" << "}," << "\"error\": null" << "}"; response.body = json.str(); } else { std::ostringstream json; json << "{" << "\"success\": false," << "\"data\": null," << "\"error\": \"" << EscapeJsonString(result.error_message) << "\"" << "}"; response.body = json.str(); response.status_code = 500; } return response; } // JSON数组解析函数 std::vector ExtractJsonArray(const std::string& json, const std::string& key) { std::vector result; try { // 查找键值对 "key": [...] std::string key_pattern = "\"" + key + "\""; size_t key_pos = json.find(key_pattern); if (key_pos != std::string::npos) { // 找到冒号 size_t colon_pos = json.find(":", key_pos); if (colon_pos != std::string::npos) { // 跳过空格找到数组开始 size_t array_start = colon_pos + 1; while (array_start < json.length() && (json[array_start] == ' ' || json[array_start] == '\t' || json[array_start] == '\n' || json[array_start] == '\r')) { array_start++; } // 检查是否是数组(以方括号开始) if (array_start < json.length() && json[array_start] == '[') { size_t array_end = json.find(']', array_start); if (array_end != std::string::npos) { std::string array_content = json.substr(array_start + 1, array_end - array_start - 1); // 解析数组中的字符串元素 size_t pos = 0; while (pos < array_content.length()) { // 跳过空格和逗号 while (pos < array_content.length() && (array_content[pos] == ' ' || array_content[pos] == '\t' || array_content[pos] == '\n' || array_content[pos] == '\r' || array_content[pos] == ',')) { pos++; } // 查找字符串开始 if (pos < array_content.length() && array_content[pos] == '"') { size_t str_start = pos + 1; size_t str_end = array_content.find('"', str_start); if (str_end != std::string::npos) { std::string element = array_content.substr(str_start, str_end - str_start); if (!element.empty()) { result.push_back(element); } pos = str_end + 1; } else { break; } } else { break; } } } } } } } catch (...) { // 解析失败,返回空数组 } return result; } // 按路径删除组件处理器 HttpResponse PathDeleteHandler(const HttpRequest& request) { HttpResponse response; if (request.method != "POST") { response.status_code = 405; response.body = "{\"success\": false, \"error\": \"Method not allowed\"}"; return response; } try { // 解析JSON请求参数 PathDeleteManager::PathDeleteRequest delete_request; delete_request.software_type = ExtractJsonValue(request.body, "software_type"); delete_request.component_paths = ExtractJsonArray(request.body, "component_paths"); std::string force_delete_str = ExtractJsonValue(request.body, "force_delete"); delete_request.force_delete = (force_delete_str == "true"); // 参数验证 if (delete_request.software_type.empty()) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Missing required parameter: software_type\"}"; return response; } if (delete_request.software_type != "creo") { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}"; return response; } if (delete_request.component_paths.empty()) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Missing required parameter: component_paths\"}"; return response; } // 执行按路径删除 PathDeleteManager::PathDeleteResult result = PathDeleteManager::Instance().DeleteComponentsByPaths(delete_request); if (result.success) { // 构建成功响应 std::ostringstream json; json << "{" << "\"success\": true," << "\"data\": {" << "\"successfully_deleted\": ["; // 构建成功删除列表 for (size_t i = 0; i < result.successfully_deleted.size(); i++) { if (i > 0) json << ","; json << "\"" << EscapeJsonString(result.successfully_deleted[i]) << "\""; } json << "]," << "\"failed_to_delete\": ["; // 构建失败删除列表 for (size_t i = 0; i < result.failed_to_delete.size(); i++) { if (i > 0) json << ","; json << "\"" << EscapeJsonString(result.failed_to_delete[i]) << "\""; } json << "]," << "\"deletion_summary\": {" << "\"total_requested\": " << result.total_requested << "," << "\"successful\": " << result.successful << "," << "\"failed\": " << result.failed << "}," << "\"deletion_reasons\": {"; // 构建删除原因映射 bool first_reason = true; for (const auto& reason_pair : result.deletion_reasons) { if (!first_reason) json << ","; first_reason = false; json << "\"" << EscapeJsonString(reason_pair.first) << "\": \"" << EscapeJsonString(reason_pair.second) << "\""; } json << "}" << "}," << "\"error\": null" << "}"; response.status_code = 200; response.body = json.str(); } else { // 构建失败响应 std::ostringstream json; json << "{" << "\"success\": false," << "\"data\": {" << "\"successfully_deleted\": []," << "\"failed_to_delete\": ["; // 构建失败删除列表 for (size_t i = 0; i < result.failed_to_delete.size(); i++) { if (i > 0) json << ","; json << "\"" << EscapeJsonString(result.failed_to_delete[i]) << "\""; } json << "]," << "\"deletion_summary\": {" << "\"total_requested\": " << result.total_requested << "," << "\"successful\": " << result.successful << "," << "\"failed\": " << result.failed << "}," << "\"deletion_reasons\": {"; // 构建删除原因映射 bool first_reason = true; for (const auto& reason_pair : result.deletion_reasons) { if (!first_reason) json << ","; first_reason = false; json << "\"" << EscapeJsonString(reason_pair.first) << "\": \"" << EscapeJsonString(reason_pair.second) << "\""; } json << "}" << "}," << "\"error\": \"" << EscapeJsonString(result.error_message) << "\"" << "}"; response.status_code = 500; response.body = json.str(); } } catch (const std::exception& e) { response.status_code = 500; response.body = "{\"success\": false, \"error\": \"Request processing error: " + std::string(e.what()) + "\"}"; } catch (...) { response.status_code = 500; response.body = "{\"success\": false, \"error\": \"Unknown error during path deletion\"}"; } return response; } // 层级分析路由处理器 HttpResponse HierarchyAnalysisHandler(const HttpRequest& request) { HttpResponse response; if (request.method != "POST") { response.status_code = 405; response.body = "{\"success\": false, \"error\": \"Method not allowed\"}"; return response; } try { // 解析JSON请求 HierarchyAnalysisRequest analysis_request; // 简单的JSON解析(参考现有的ExtractJsonValue方法) analysis_request.software_type = ExtractJsonValue(request.body, "software_type"); analysis_request.project_name = ExtractJsonValue(request.body, "project_name"); analysis_request.include_geometry = ExtractJsonValue(request.body, "include_geometry") == "true"; // 解析max_depth参数(保持兼容性,但不实际使用) std::string max_depth_str = ExtractJsonValue(request.body, "max_depth"); if (!max_depth_str.empty()) { try { analysis_request.max_depth = std::stoi(max_depth_str); } catch (...) { analysis_request.max_depth = 0; // 0表示无限制 } } else { analysis_request.max_depth = 0; // 0表示无限制 } // 解析target_level参数(指定返回的层级) std::string target_level_str = ExtractJsonValue(request.body, "target_level"); if (!target_level_str.empty()) { try { analysis_request.target_level = std::stoi(target_level_str); } catch (...) { analysis_request.target_level = -1; // -1表示返回所有层级 } } else { analysis_request.target_level = -1; // -1表示返回所有层级 } // 执行层级分析 HierarchyAnalysisResult result = CreoManager::Instance().AnalyzeModelHierarchy(analysis_request); if (result.success) { // 构建成功响应 std::ostringstream json; json << "{" << "\"success\": true," << "\"message\": \"" << result.message << "\"," << "\"data\": {" << "\"project_name\": \"" << EscapeJsonString(result.project_name) << "\"," << "\"total_levels\": " << result.total_levels << "," << "\"total_components\": " << result.total_components << "," << "\"hierarchy\": ["; // 构建层级数据 for (size_t level = 0; level < result.hierarchy.size(); level++) { if (level > 0) json << ","; json << "{" << "\"level\": " << level << "," << "\"name\": \"" << (level == 0 ? "Main Assembly" : level == 1 ? "Sub Assembly" : level == 2 ? "Parts" : "Level " + std::to_string(level + 1) + " Components") << "\"," << "\"components\": ["; for (size_t comp = 0; comp < result.hierarchy[level].size(); comp++) { if (comp > 0) json << ","; const ComponentInfo& component = result.hierarchy[level][comp]; json << "{" << "\"id\": \"" << EscapeJsonString(component.id) << "\"," << "\"name\": \"" << EscapeJsonString(component.name) << "\"," << "\"type\": \"" << EscapeJsonString(component.type) << "\"," << "\"level\": " << component.level << "," << "\"children_count\": " << component.children_count << "," << "\"path\": \"" << EscapeJsonString(component.full_path) << "\"," << "\"file_size\": \"" << EscapeJsonString(component.file_size) << "\"," << "\"deletion_safety\": \"" << EscapeJsonString(component.deletion_safety) << "\"" << "}"; } json << "]}"; } json << "]," << "\"deletion_recommendations\": {" << "\"safe_deletions\": []," << "\"risky_deletions\": ["; // 构建删除建议 for (size_t i = 0; i < result.risky_deletions.size(); i++) { if (i > 0) json << ","; const DeletionRecommendation& rec = result.risky_deletions[i]; json << "{" << "\"component_id\": \"" << EscapeJsonString(rec.component_id) << "\"," << "\"component_name\": \"" << EscapeJsonString(rec.component_name) << "\"," << "\"level\": " << rec.level << "," << "\"reason\": \"" << EscapeJsonString(rec.reason) << "\"," << "\"risk_factors\": ["; for (size_t j = 0; j < rec.risk_factors.size(); j++) { if (j > 0) json << ","; json << "\"" << EscapeJsonString(rec.risk_factors[j]) << "\""; } json << "]," << "\"confidence\": " << rec.confidence << "}"; } json << "]" << "}" << "}," << "\"error\": null" << "}"; response.body = json.str(); } else { // 构建失败响应 std::ostringstream json; json << "{" << "\"success\": false," << "\"data\": null," << "\"error\": \"" << result.error_message << "\"" << "}"; response.body = json.str(); response.status_code = 500; } } catch (const std::exception& e) { response.status_code = 500; response.body = "{\"success\": false, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}"; } catch (...) { response.status_code = 500; response.body = "{\"success\": false, \"error\": \"Unknown error during hierarchy analysis\"}"; } return response; } // 层级删除路由处理器 HttpResponse HierarchyDeleteHandler(const HttpRequest& request) { HttpResponse response; if (request.method != "POST") { response.status_code = 405; response.body = "{\"success\": false, \"error\": \"Method not allowed\"}"; return response; } try { // 解析JSON请求 std::string software_type = ExtractJsonValue(request.body, "software_type"); std::string project_name = ExtractJsonValue(request.body, "project_name"); std::string target_level_str = ExtractJsonValue(request.body, "target_level"); if (software_type.empty() || project_name.empty() || target_level_str.empty()) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Missing required parameters: software_type, project_name, target_level\"}"; return response; } int target_level; try { target_level = std::stoi(target_level_str); } catch (...) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Invalid target_level parameter\"}"; return response; } // 执行层级删除 CreoManager::HierarchyDeleteResult result = CreoManager::Instance().DeleteHierarchyComponents(project_name, target_level); if (result.success) { // 构建成功响应 std::ostringstream json; json << "{" << "\"success\": true," << "\"message\": \"" << EscapeJsonString(result.message) << "\"," << "\"data\": {" << "\"original_levels\": " << result.original_levels << "," << "\"target_level\": " << result.target_level << "," << "\"final_levels\": " << result.final_levels << "," << "\"deleted_components\": {"; // 构建删除组件数据 bool first_level = true; for (const auto& level_pair : result.deleted_components) { if (!first_level) json << ","; first_level = false; json << "\"level_" << level_pair.first << "\": ["; bool first_component = true; for (const auto& component : level_pair.second) { if (!first_component) json << ","; first_component = false; json << "\"" << EscapeJsonString(component) << "\""; } json << "]"; } json << "}," << "\"deletion_summary\": {" << "\"total_deleted\": " << result.total_deleted << "," << "\"successful\": " << result.successful << "," << "\"failed\": " << result.failed << "}" << "}," << "\"error\": null" << "}"; response.body = json.str(); } else { // 构建错误响应 std::ostringstream json; json << "{" << "\"success\": false," << "\"message\": \"" << EscapeJsonString(result.message) << "\"," << "\"error\": \"" << EscapeJsonString(result.error_message) << "\"" << "}"; response.status_code = 500; response.body = json.str(); } } catch (const std::exception& e) { response.status_code = 500; response.body = "{\"success\": false, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}"; } catch (...) { response.status_code = 500; response.body = "{\"success\": false, \"error\": \"Unknown error during hierarchy deletion\"}"; } return response; } // 子装配体层级删除路由处理器 HttpResponse SubassemblyHierarchyDeleteHandler(const HttpRequest& request) { HttpResponse response; if (request.method != "POST") { response.status_code = 405; response.body = "{\"success\": false, \"error\": \"Method not allowed\"}"; return response; } try { // 解析JSON请求 std::string software_type = ExtractJsonValue(request.body, "software_type"); std::string subassembly_path = ExtractJsonValue(request.body, "subassembly_path"); std::string target_level_str = ExtractJsonValue(request.body, "target_level"); if (software_type.empty() || subassembly_path.empty() || target_level_str.empty()) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Missing required parameters: software_type, subassembly_path, target_level\"}"; return response; } if (software_type != "creo") { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}"; return response; } int target_level; try { target_level = std::stoi(target_level_str); } catch (...) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Invalid target_level parameter\"}"; return response; } // 执行子装配体层级删除 CreoManager::HierarchyDeleteResult result = CreoManager::Instance().DeleteSubassemblyHierarchyComponents(subassembly_path, target_level); if (result.success) { // 构建成功响应 std::ostringstream json; json << "{" << "\"success\": true," << "\"message\": \"" << EscapeJsonString(result.message) << "\"," << "\"data\": {" << "\"subassembly_path\": \"" << EscapeJsonString(subassembly_path) << "\"," << "\"original_levels\": " << result.original_levels << "," << "\"target_level\": " << result.target_level << "," << "\"final_levels\": " << result.final_levels << "," << "\"deleted_components\": {"; // 构建删除组件数据 bool first_level = true; for (const auto& level_pair : result.deleted_components) { if (!first_level) json << ","; first_level = false; json << "\"level_" << level_pair.first << "\": ["; bool first_component = true; for (const auto& component : level_pair.second) { if (!first_component) json << ","; first_component = false; json << "\"" << EscapeJsonString(component) << "\""; } json << "]"; } json << "}," << "\"deletion_summary\": {" << "\"total_deleted\": " << result.total_deleted << "," << "\"successful\": " << result.successful << "," << "\"failed\": " << result.failed << "}" << "}," << "\"error\": null" << "}"; response.body = json.str(); } else { // 构建错误响应 std::ostringstream json; json << "{" << "\"success\": false," << "\"message\": \"" << EscapeJsonString(result.message) << "\"," << "\"error\": \"" << EscapeJsonString(result.error_message) << "\"" << "}"; response.status_code = 500; response.body = json.str(); } } catch (const std::exception& e) { response.status_code = 500; response.body = "{\"success\": false, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}"; } catch (...) { response.status_code = 500; response.body = "{\"success\": false, \"error\": \"Unknown error during subassembly hierarchy deletion\"}"; } return response; } // 薄壳化分析处理器 HttpResponse ShellAnalysisHandler(const HttpRequest& request) { HttpResponse response; if (request.method != "POST") { response.status_code = 405; response.body = "{\"success\": false, \"error\": \"Method not allowed\"}"; return response; } try { // 解析JSON请求参数 CreoManager::ShellAnalysisRequest analysis_request; // 必填参数 analysis_request.software_type = ExtractJsonValue(request.body, "software_type"); if (analysis_request.software_type.empty()) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Missing required parameter: software_type\"}"; return response; } if (analysis_request.software_type != "creo") { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}"; return response; } // 可选参数解析 std::string project_name = ExtractJsonValue(request.body, "projectName"); if (!project_name.empty()) { analysis_request.project_name = project_name; } std::string analysis_type = ExtractJsonValue(request.body, "analysisType"); if (!analysis_type.empty()) { analysis_request.analysis_type = analysis_type; } std::string preserve_external = ExtractJsonValue(request.body, "preserveExternalSurfaces"); if (!preserve_external.empty()) { analysis_request.preserve_external_surfaces = (preserve_external == "true"); } std::string min_thickness = ExtractJsonValue(request.body, "minWallThickness"); if (!min_thickness.empty()) { try { analysis_request.min_wall_thickness = std::stod(min_thickness); } catch (...) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Invalid minWallThickness parameter\"}"; return response; } } std::string confidence = ExtractJsonValue(request.body, "confidenceThreshold"); if (!confidence.empty()) { try { analysis_request.confidence_threshold = std::stod(confidence); if (analysis_request.confidence_threshold < 0.0 || analysis_request.confidence_threshold > 1.0) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"confidenceThreshold must be between 0.0 and 1.0\"}"; return response; } } catch (...) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Invalid confidenceThreshold parameter\"}"; return response; } } // Execute enhanced shell analysis (uses new algorithm with real geometry APIs) CreoManager::ShellAnalysisResult result = CreoManager::Instance().AnalyzeShellFeaturesEnhanced(analysis_request); if (result.success) { // 构建成功响应 std::ostringstream json; json << "{" << "\"success\": true," << "\"data\": {" << "\"safeDeletions\": ["; // 构建安全删除列表 bool first_item = true; for (const auto& deletion : result.safe_deletions) { if (!first_item) json << ","; first_item = false; json << "{" << "\"id\": " << deletion.id << "," << "\"name\": \"" << EscapeJsonString(deletion.name) << "\"," << "\"type\": \"" << EscapeJsonString(deletion.type) << "\"," << "\"reason\": \"" << EscapeJsonString(deletion.reason) << "\"," << "\"confidence\": " << deletion.confidence << "," << "\"volumeReduction\": " << deletion.volume_reduction << "," << "\"partFile\": \"" << EscapeJsonString(deletion.part_file) << "\"," << "\"partPath\": \"" << EscapeJsonString(deletion.part_path) << "\"," << "\"componentType\": \"" << EscapeJsonString(deletion.component_type) << "\"," << "\"voteCount\": " << deletion.vote_count << "}"; } json << "]," << "\"suggestedDeletions\": ["; // 构建建议删除列表 first_item = true; for (const auto& deletion : result.suggested_deletions) { if (!first_item) json << ","; first_item = false; json << "{" << "\"id\": " << deletion.id << "," << "\"name\": \"" << EscapeJsonString(deletion.name) << "\"," << "\"type\": \"" << EscapeJsonString(deletion.type) << "\"," << "\"reason\": \"" << EscapeJsonString(deletion.reason) << "\"," << "\"confidence\": " << deletion.confidence << "," << "\"volumeReduction\": " << deletion.volume_reduction << "," << "\"partFile\": \"" << EscapeJsonString(deletion.part_file) << "\"," << "\"partPath\": \"" << EscapeJsonString(deletion.part_path) << "\"," << "\"componentType\": \"" << EscapeJsonString(deletion.component_type) << "\"," << "\"voteCount\": " << deletion.vote_count << "}"; } json << "]," << "\"preserveList\": ["; // 构建保留列表 first_item = true; for (const auto& preserve : result.preserve_list) { if (!first_item) json << ","; first_item = false; json << "{" << "\"id\": " << preserve.id << "," << "\"name\": \"" << EscapeJsonString(preserve.name) << "\"," << "\"type\": \"" << EscapeJsonString(preserve.type) << "\"," << "\"reason\": \"" << EscapeJsonString(preserve.reason) << "\"," << "\"confidence\": " << preserve.confidence << "," << "\"volumeReduction\": " << preserve.volume_reduction << "," << "\"partFile\": \"" << EscapeJsonString(preserve.part_file) << "\"," << "\"partPath\": \"" << EscapeJsonString(preserve.part_path) << "\"," << "\"componentType\": \"" << EscapeJsonString(preserve.component_type) << "\"," << "\"voteCount\": " << preserve.vote_count << "}"; } json << "]," << "\"estimatedReduction\": {" << "\"volumeReduction\": \"" << EscapeJsonString(result.estimated_reduction.volume_reduction) << "\"," << "\"fileSizeReduction\": \"" << EscapeJsonString(result.estimated_reduction.file_size_reduction) << "\"," << "\"performanceImprovement\": \"" << EscapeJsonString(result.estimated_reduction.performance_improvement) << "\"" << "}," << "\"analysisParameters\": {" << "\"preserveExternalSurfaces\": " << (result.analysis_parameters.preserve_external_surfaces ? "true" : "false") << "," << "\"minWallThickness\": " << result.analysis_parameters.min_wall_thickness << "," << "\"confidenceThreshold\": " << result.analysis_parameters.confidence_threshold << "," << "\"totalFeatures\": " << result.analysis_parameters.total_features << "," << "\"deletableFeatures\": " << result.analysis_parameters.deletable_features << "," << "\"preservedFeatures\": " << result.analysis_parameters.preserved_features << "," << "\"assemblyAnalysis\": " << (result.analysis_parameters.assembly_analysis ? "true" : "false") << "," << "\"analysisStrategy\": \"" << EscapeJsonString(result.analysis_parameters.analysis_strategy) << "\"," << "\"surfaceCount\": " << result.analysis_parameters.surface_count << "," << "\"shellSurfaces\": " << result.analysis_parameters.shell_surfaces << "," << "\"internalSurfaces\": " << result.analysis_parameters.internal_surfaces << "," << "\"shellFeatureWhitelist\": " << result.analysis_parameters.shell_feature_whitelist; // 添加层次分析信息 if (result.analysis_parameters.hierarchy_analysis.enabled) { json << "," << "\"hierarchyAnalysis\": {" << "\"enabled\": true," << "\"totalParts\": " << result.analysis_parameters.hierarchy_analysis.total_parts << "," << "\"outerParts\": " << result.analysis_parameters.hierarchy_analysis.outer_parts << "," << "\"internalParts\": " << result.analysis_parameters.hierarchy_analysis.internal_parts << "," << "\"containmentRelationships\": " << result.analysis_parameters.hierarchy_analysis.containment_relationships << "," << "\"performanceStats\": {"; bool first_stat = true; for (const auto& stat : result.analysis_parameters.hierarchy_analysis.performance_stats) { if (!first_stat) json << ","; first_stat = false; json << "\"" << EscapeJsonString(stat.first) << "\": \"" << EscapeJsonString(stat.second) << "\""; } json << "}" << "}"; } json << "}" // 结束 analysisParameters (不加逗号) << "}," // 结束 data (加逗号) << "\"error\": null" << "}"; response.body = json.str(); } else { // 构建错误响应 std::ostringstream json; json << "{" << "\"success\": false," << "\"data\": null," << "\"error\": \"" << EscapeJsonString(result.error_message) << "\"" << "}"; response.status_code = 500; response.body = json.str(); } } catch (const std::exception& e) { response.status_code = 500; response.body = "{\"success\": false, \"data\": null, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}"; } catch (...) { response.status_code = 500; response.body = "{\"success\": false, \"data\": null, \"error\": \"Unknown error during shell analysis\"}"; } return response; } // 保存模型路由处理器 HttpResponse SaveModelHandler(const HttpRequest& request) { HttpResponse response; if (request.method != "POST") { response.status_code = 405; response.body = "{\"success\": false, \"error\": \"Method not allowed\"}"; return response; } try { // 解析JSON请求参数 std::string software_type = ExtractJsonValue(request.body, "software_type"); // 参数验证 if (software_type.empty()) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Missing required parameter: software_type\"}"; return response; } if (software_type != "creo") { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}"; return response; } // 执行保存操作 SaveResult result = CreoManager::Instance().SaveModel(); if (result.success) { // 构建成功响应 std::ostringstream json; json << "{" << "\"success\": true," << "\"data\": {" << "\"file_size\": \"" << EscapeJsonString(result.file_size) << "\"," << "\"save_time\": \"" << EscapeJsonString(result.save_time) << "\"," << "\"software\": \"" << EscapeJsonString(result.software) << "\"," << "\"original_file\": \"" << EscapeJsonString(result.original_file) << "\"" << "}," << "\"error\": null" << "}"; response.body = json.str(); } else { // 构建错误响应 std::ostringstream json; json << "{" << "\"success\": false," << "\"data\": null," << "\"error\": \"" << EscapeJsonString(result.error_message) << "\"" << "}"; response.status_code = 500; response.body = json.str(); } } catch (const std::exception& e) { response.status_code = 500; response.body = "{\"success\": false, \"data\": null, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}"; } catch (...) { response.status_code = 500; response.body = "{\"success\": false, \"data\": null, \"error\": \"Unknown error during save operation\"}"; } return response; } // 关闭模型路由处理器 HttpResponse CloseModelHandler(const HttpRequest& request) { HttpResponse response; if (request.method != "POST") { response.status_code = 405; response.body = "{\"success\": false, \"error\": \"Method not allowed\"}"; return response; } try { // 解析JSON请求参数 std::string software_type = ExtractJsonValue(request.body, "software_type"); std::string force_close_str = ExtractJsonValue(request.body, "force_close"); // 参数验证 if (software_type.empty()) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Missing required parameter: software_type\"}"; return response; } if (software_type != "creo") { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}"; return response; } // 解析force_close参数 bool force_close = (force_close_str == "true"); // 执行关闭操作 CloseResult result = CreoManager::Instance().CloseModel(force_close); if (result.success) { // 构建成功响应 std::ostringstream json; json << "{" << "\"success\": true," << "\"data\": {" << "\"model_name\": \"" << EscapeJsonString(result.model_name) << "\"," << "\"was_modified\": " << (result.was_modified ? "true" : "false") << "," << "\"close_time\": \"" << EscapeJsonString(result.close_time) << "\"" << "}," << "\"error\": null" << "}"; response.body = json.str(); } else { // 构建错误响应 std::ostringstream json; json << "{" << "\"success\": false," << "\"data\": null," << "\"error\": \"" << EscapeJsonString(result.error_message) << "\"" << "}"; response.status_code = 500; response.body = json.str(); } } catch (const std::exception& e) { response.status_code = 500; response.body = "{\"success\": false, \"data\": null, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}"; } catch (...) { response.status_code = 500; response.body = "{\"success\": false, \"data\": null, \"error\": \"Unknown error during close operation\"}"; } return response; } // 辅助函数:去除 Creo 文件路径末尾的版本号后缀 // 例如: D:\path\file.prt.1 -> D:\path\file.prt // D:\path\file.asm.123 -> D:\path\file.asm std::string StripCreoVersionSuffix(const std::string& file_path) { // 查找最后一个路径分隔符 size_t last_sep = file_path.find_last_of("/\\"); std::string dir_part = (last_sep != std::string::npos) ? file_path.substr(0, last_sep + 1) : ""; std::string file_name = (last_sep != std::string::npos) ? file_path.substr(last_sep + 1) : file_path; // 检查文件名是否以 .数字 结尾 (Creo 版本号格式) size_t last_dot = file_name.rfind('.'); if (last_dot != std::string::npos && last_dot < file_name.length() - 1) { std::string suffix = file_name.substr(last_dot + 1); // 检查后缀是否全为数字 bool all_digits = !suffix.empty(); for (char c : suffix) { if (!isdigit(static_cast(c))) { all_digits = false; break; } } if (all_digits) { // 去除版本号后缀 std::string stripped_name = file_name.substr(0, last_dot); // 确保去掉版本号后仍然有 Creo 扩展名 (.prt, .asm 等) size_t ext_dot = stripped_name.rfind('.'); if (ext_dot != std::string::npos) { std::string ext = stripped_name.substr(ext_dot + 1); // 验证是 Creo 扩展名 if (ext == "prt" || ext == "asm" || ext == "drw" || ext == "frm" || ext == "lay" || ext == "sec") { return dir_part + stripped_name; } } } } // 不匹配 Creo 版本号格式,返回原路径 return file_path; } // 打开模型路由处理器 HttpResponse OpenModelHandler(const HttpRequest& request) { HttpResponse response; if (request.method != "POST") { response.status_code = 405; response.body = "{\"success\": false, \"error\": \"Method not allowed\"}"; return response; } try { // 解析JSON请求参数 std::string software_type = ExtractJsonValue(request.body, "software_type"); std::string file_path = ExtractJsonValue(request.body, "file_path"); std::string dirname = ExtractJsonValue(request.body, "dirname"); std::string filename = ExtractJsonValue(request.body, "filename"); std::string open_mode = ExtractJsonValue(request.body, "open_mode"); // 参数验证 if (software_type.empty()) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Missing required parameter: software_type\"}"; return response; } // 支持两种路径格式:完整路径或分离的dirname+filename if (file_path.empty()) { if (dirname.empty() || filename.empty()) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Missing required parameters: either 'file_path' or both 'dirname' and 'filename'\"}"; return response; } // 组合dirname和filename为完整路径(creoson风格) file_path = dirname + "/" + filename; } // 去除 Creo 文件版本号后缀 (如 .prt.1 -> .prt) file_path = StripCreoVersionSuffix(file_path); if (software_type != "creo") { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}"; return response; } // 设置默认打开模式 if (open_mode.empty()) { open_mode = "active"; } // 使用无锁消息机制 MessageItem open_message_item; open_message_item.type = "OPEN_MODEL_REQUEST"; open_message_item.data = file_path; open_message_item.extra = open_mode; // 原子设置(无锁) pending_message_item = &open_message_item; has_pending_item = true; // 等待主线程完成操作(带超时) int timeout_ms = 10000; // 10秒超时 while (!open_message_item.completed && timeout_ms > 0) { Sleep(50); timeout_ms -= 50; } OpenResult result; if (open_message_item.completed && open_message_item.result_ptr) { result = *static_cast(open_message_item.result_ptr); delete static_cast(open_message_item.result_ptr); // 清理内存 } else { // 超时处理 result.success = false; result.error_message = "Operation timeout: OpenModel took too long to complete"; } if (result.success) { // 构建成功响应 std::ostringstream json; json << "{" << "\"success\": true," << "\"data\": {" << "\"model_name\": \"" << EscapeJsonString(result.model_name) << "\"," << "\"model_type\": \"" << EscapeJsonString(result.model_type) << "\"," << "\"file_path\": \"" << EscapeJsonString(result.file_path) << "\"," << "\"file_size\": \"" << EscapeJsonString(result.file_size) << "\"," << "\"open_time\": \"" << EscapeJsonString(result.open_time) << "\"," << "\"is_assembly\": " << (result.is_assembly ? "true" : "false") << "," << "\"total_parts\": " << result.total_parts << "," << "\"model_in_session\": " << (result.model_in_session ? "true" : "false") << "," << "\"window_model_match\": " << (result.window_model_match ? "true" : "false") << "}," << "\"error\": null" << "}"; response.body = json.str(); } else { // 构建错误响应 std::ostringstream json; json << "{" << "\"success\": false," << "\"data\": null," << "\"error\": \"" << EscapeJsonString(result.error_message) << "\"" << "}"; response.status_code = 500; response.body = json.str(); } } catch (const std::exception& e) { response.status_code = 500; response.body = "{\"success\": false, \"data\": null, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}"; } catch (...) { response.status_code = 500; response.body = "{\"success\": false, \"data\": null, \"error\": \"Unknown error during open operation\"}"; } return response; } // 几何复杂度分析路由处理器 HttpResponse GeometryComplexityHandler(const HttpRequest& request) { HttpResponse response; if (request.method != "POST") { response.status_code = 405; response.body = "{\"success\": false, \"error\": \"Method not allowed\"}"; return response; } try { // 解析请求参数 GeometryComplexityRequest complexity_request; // 提取JSON参数 complexity_request.software_type = ExtractJsonValue(request.body, "software_type"); complexity_request.project_name = ExtractJsonValue(request.body, "project_name"); std::string max_results_str = ExtractJsonValue(request.body, "max_results"); if (!max_results_str.empty()) { complexity_request.max_results = std::stoi(max_results_str); } std::string include_details_str = ExtractJsonValue(request.body, "include_details"); if (!include_details_str.empty()) { complexity_request.include_details = (include_details_str == "true"); } complexity_request.sort_order = ExtractJsonValue(request.body, "sort_order"); if (complexity_request.sort_order.empty()) { complexity_request.sort_order = "desc"; } std::string threshold_str = ExtractJsonValue(request.body, "complexity_threshold"); if (!threshold_str.empty()) { complexity_request.complexity_threshold = std::stod(threshold_str); } // 参数验证 if (complexity_request.software_type.empty()) { complexity_request.software_type = "creo"; } if (complexity_request.project_name.empty()) { complexity_request.project_name = "Geometry Complexity Analysis"; } if (complexity_request.software_type != "creo") { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}"; return response; } // 执行几何复杂度分析 GeometryComplexityResult result = GeometryAnalyzer::Instance().AnalyzeGeometryComplexity(complexity_request); if (result.success) { // 构建成功响应 std::ostringstream json; json << "{" << "\"success\": true," << "\"message\": \"" << EscapeJsonString(result.message) << "\"," << "\"data\": {" << "\"parts\": ["; for (size_t i = 0; i < result.parts.size(); ++i) { const GeometryComplexityInfo& part = result.parts[i]; if (i > 0) json << ","; json << "{" << "\"part_name\": \"" << EscapeJsonString(part.part_name) << "\"," << "\"part_path\": \"" << EscapeJsonString(part.part_path) << "\"," << "\"file_size\": \"" << EscapeJsonString(part.file_size) << "\"," << "\"complexity_score\": " << part.complexity_score << "," << "\"complexity_level\": \"" << EscapeJsonString(part.complexity_level) << "\"," << "\"feature_count\": " << part.feature_count << "," << "\"surface_count\": " << part.surface_count << "," << "\"curved_surface_count\": " << part.curved_surface_count << "," << "\"hole_count\": " << part.hole_count << "," << "\"fillet_count\": " << part.fillet_count << "," << "\"pattern_count\": " << part.pattern_count << "," << "\"sketch_count\": " << part.sketch_count << "," << "\"volume\": " << part.volume << "," << "\"surface_area\": " << part.surface_area << "," << "\"bounding_box_volume\": " << part.bounding_box_volume << "," << "\"complexity_factors\": ["; for (size_t j = 0; j < part.complexity_factors.size(); ++j) { if (j > 0) json << ","; json << "\"" << EscapeJsonString(part.complexity_factors[j]) << "\""; } json << "]" << "}"; } json << "]," << "\"total_parts_analyzed\": " << result.total_parts_analyzed << "," << "\"analysis_time\": \"" << EscapeJsonString(result.analysis_time) << "\"," << "\"average_complexity\": " << result.average_complexity << "," << "\"max_complexity\": " << result.max_complexity << "," << "\"min_complexity\": " << result.min_complexity << "}," << "\"error\": null" << "}"; response.body = json.str(); } else { // 构建错误响应 std::ostringstream json; json << "{" << "\"success\": false," << "\"data\": null," << "\"error\": \"" << EscapeJsonString(result.error_message) << "\"" << "}"; response.status_code = 500; response.body = json.str(); } } catch (const std::exception& e) { response.status_code = 500; response.body = "{\"success\": false, \"data\": null, \"error\": \"Exception during geometry complexity analysis: " + std::string(e.what()) + "\"}"; } catch (...) { response.status_code = 500; response.body = "{\"success\": false, \"data\": null, \"error\": \"Unknown error during geometry complexity analysis\"}"; } return response; } // Shrinkwrap外壳导出路由处理器 HttpResponse ShrinkwrapShellHandler(const HttpRequest& request) { HttpResponse response; if (request.method != "POST") { response.status_code = 405; response.body = "{\"success\": false, \"error\": \"Method not allowed\"}"; return response; } try { // 解析请求获取超时参数 int timeout_seconds = 60; // 默认值改为60秒 try { // 简单解析JSON获取timeout_seconds std::string json_body = request.body; std::string search_pattern = "\"timeout_seconds\"\\s*:\\s*(\\d+)"; std::regex timeout_regex(search_pattern); std::smatch match; if (std::regex_search(json_body, match, timeout_regex)) { int parsed_timeout = std::stoi(match[1].str()); if (parsed_timeout >= 10 && parsed_timeout <= 300) { timeout_seconds = parsed_timeout; } } } catch (...) { // 解析失败,使用默认值 timeout_seconds = 60; } // 使用堆分配的MessageItem,避免超时后悬空指针问题 MessageItem* shrinkwrap_message_item = new MessageItem(); shrinkwrap_message_item->type = "SHRINKWRAP_SHELL_REQUEST"; shrinkwrap_message_item->data = request.body; // 原子设置(无锁) pending_message_item = shrinkwrap_message_item; has_pending_item = true; // 等待主线程完成操作(带动态超时) int timeout_ms = timeout_seconds * 1000; // 转换为毫秒 while (!shrinkwrap_message_item->completed && timeout_ms > 0) { Sleep(100); // 稍长的间隔,因为Shrinkwrap是重操作 timeout_ms -= 100; } if (shrinkwrap_message_item->completed && shrinkwrap_message_item->result_ptr) { // 操作成功完成 HttpResponse result = *static_cast(shrinkwrap_message_item->result_ptr); delete static_cast(shrinkwrap_message_item->result_ptr); // 清理结果内存 delete shrinkwrap_message_item; // 清理MessageItem内存 return result; } else { // 超时处理:标记为已超时,让TimerProc负责清理 shrinkwrap_message_item->timed_out = true; response.status_code = 504; response.body = "{\"success\": false, \"error\": \"Operation timeout: Shrinkwrap export exceeded " + std::to_string(timeout_seconds) + " seconds limit\", \"note\": \"The Creo operation may still complete in background. Check Creo for results.\"}"; return response; } } catch (const std::exception& e) { response.status_code = 500; response.body = "{\"success\": false, \"error\": \"Request processing error: " + std::string(e.what()) + "\"}"; } catch (...) { response.status_code = 500; response.body = "{\"success\": false, \"error\": \"Unknown error during shrinkwrap shell export\"}"; } return response; } // 层级统计分析路由处理器 HttpResponse HierarchyStatisticsHandler(const HttpRequest& request) { HttpResponse response; response.headers["Content-Type"] = "application/json"; // 只支持POST请求 if (request.method != "POST") { response.status_code = 405; response.body = "{\"success\": false, \"error\": \"Method not allowed. Use POST.\"}"; return response; } try { // 解析请求参数 HierarchyStatisticsRequest stats_request; // 提取project_name参数(可选) std::string project_name_str = ExtractJsonValue(request.body, "project_name"); if (!project_name_str.empty()) { stats_request.project_name = project_name_str; } // 提取subassembly_path参数(可选) std::string subassembly_path_str = ExtractJsonValue(request.body, "subassembly_path"); if (!subassembly_path_str.empty()) { stats_request.subassembly_path = subassembly_path_str; } // 执行层级统计分析 HierarchyStatisticsResult result = HierarchyStatisticsAnalyzer::Instance().AnalyzeHierarchyStatistics(stats_request); if (result.success) { // 构建成功响应 std::ostringstream json; json << "{" << "\"success\": true," << "\"message\": \"" << result.message << "\"," << "\"data\": {" << "\"model_name\": \"" << EscapeJsonString(result.model_name) << "\"," << "\"model_type\": \"" << result.model_type << "\"," << "\"total_levels\": " << result.total_levels << "," << "\"analysis_time\": \"" << result.analysis_time << "\"," << "\"statistics\": {"; // 构建层级统计数据 bool first = true; for (const auto& stat : result.level_statistics) { if (!first) json << ","; json << "\"" << stat.first << "\": " << stat.second; first = false; } json << "}" << "}" << "}"; response.body = json.str(); } else { // 构建失败响应 std::ostringstream json; json << "{" << "\"success\": false," << "\"data\": null," << "\"error\": \"" << EscapeJsonString(result.error_message) << "\"" << "}"; response.body = json.str(); response.status_code = 500; } } catch (const std::exception& e) { response.status_code = 500; response.body = "{\"success\": false, \"error\": \"Exception: " + std::string(e.what()) + "\"}"; } catch (...) { response.status_code = 500; response.body = "{\"success\": false, \"error\": \"Unknown error during hierarchy statistics analysis\"}"; } return response; } // Component Children Handler HttpResponse ComponentChildrenHandler(const HttpRequest& request) { HttpResponse response; response.headers["Content-Type"] = "application/json"; response.headers["Access-Control-Allow-Origin"] = "*"; response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"; response.headers["Access-Control-Allow-Headers"] = "Content-Type, Authorization"; if (request.method != "POST") { response.status_code = 405; response.body = "{\"success\": false, \"error\": \"Method not allowed\"}"; return response; } try { // Parse JSON request ComponentChildrenManager::ComponentChildrenRequest children_request; children_request.component_path = ExtractJsonValue(request.body, "component_path"); // Parse component_id as integer (Creo Feature ID) std::string component_id_str = ExtractJsonValue(request.body, "component_id"); if (!component_id_str.empty()) { try { children_request.component_id = std::stoi(component_id_str); } catch (...) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Invalid component_id: must be a number\"}"; return response; } } if (children_request.component_path.empty()) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Missing required parameter: component_path\"}"; return response; } // Call ComponentChildrenManager ComponentChildrenManager::ComponentChildrenResult result = ComponentChildrenManager::Instance().GetComponentFirstLevelChildren(children_request); if (result.success) { // Build success response std::ostringstream json; json << "{" << "\"success\": true," << "\"message\": \"" << EscapeJsonString(result.message) << "\"," << "\"data\": {" << "\"parent_component_id\": " << result.parent_component_id << "," << "\"parent_component_filename\": \"" << EscapeJsonString(result.parent_component_filename) << "\"," << "\"parent_component_path\": \"" << EscapeJsonString(result.parent_component_path) << "\"," << "\"children_count\": " << result.children_count << "," << "\"children\": ["; // Build children array for (size_t i = 0; i < result.children.size(); ++i) { if (i > 0) json << ","; const auto& child = result.children[i]; json << "{" << "\"id\": " << child.id << "," << "\"filename\": \"" << EscapeJsonString(child.filename) << "\"," << "\"name\": \"" << EscapeJsonString(child.name) << "\"," << "\"type\": \"" << child.type << "\"," << "\"level\": " << child.level << "," << "\"path\": \"" << EscapeJsonString(child.path) << "\"," << "\"full_path\": \"" << EscapeJsonString(child.full_path) << "\"," << "\"file_size\": \"" << child.file_size << "\"," << "\"is_visible\": " << (child.is_visible ? "true" : "false") << "," << "\"model_type\": \"" << child.model_type << "\"," << "\"children_count\": " << child.children_count << "}"; } json << "]" << "}" << "}"; response.body = json.str(); } else { // Build error response std::ostringstream json; json << "{" << "\"success\": false," << "\"data\": null," << "\"error\": \"" << EscapeJsonString(result.error_message) << "\"" << "}"; response.body = json.str(); response.status_code = 500; } } catch (const std::exception& e) { response.status_code = 500; response.body = "{\"success\": false, \"error\": \"Exception: " + std::string(e.what()) + "\"}"; } catch (...) { response.status_code = 500; response.body = "{\"success\": false, \"error\": \"Unknown error during component children retrieval\"}"; } return response; } // Helper function to extract operations array from JSON std::vector ExtractBatchOperations(const std::string& json) { std::vector operations; try { // Find "operations" array in JSON std::string key_pattern = "\"operations\""; size_t key_pos = json.find(key_pattern); if (key_pos == std::string::npos) { return operations; } // Find the colon after "operations" size_t colon_pos = json.find(":", key_pos); if (colon_pos == std::string::npos) { return operations; } // Skip whitespace to find array start size_t array_start = colon_pos + 1; while (array_start < json.length() && (json[array_start] == ' ' || json[array_start] == '\t' || json[array_start] == '\n' || json[array_start] == '\r')) { array_start++; } // Verify it's an array if (array_start >= json.length() || json[array_start] != '[') { return operations; } // Find matching closing bracket int bracket_count = 1; size_t array_end = array_start + 1; while (array_end < json.length() && bracket_count > 0) { if (json[array_end] == '[') bracket_count++; if (json[array_end] == ']') bracket_count--; array_end++; } if (bracket_count != 0) { return operations; } // Extract array content std::string array_content = json.substr(array_start + 1, array_end - array_start - 2); // Parse individual operation objects size_t pos = 0; while (pos < array_content.length()) { // Skip whitespace and commas while (pos < array_content.length() && (array_content[pos] == ' ' || array_content[pos] == '\t' || array_content[pos] == '\n' || array_content[pos] == '\r' || array_content[pos] == ',')) { pos++; } // Find operation object start if (pos >= array_content.length() || array_content[pos] != '{') { break; } // Find matching closing brace for this operation int brace_count = 1; size_t obj_start = pos; pos++; while (pos < array_content.length() && brace_count > 0) { if (array_content[pos] == '{') brace_count++; if (array_content[pos] == '}') brace_count--; pos++; } if (brace_count != 0) { break; } // Extract operation object std::string op_json = array_content.substr(obj_start, pos - obj_start); // Parse operation BatchOperation operation; operation.operation_type = ExtractJsonValue(op_json, "operation_type"); // Extract parameters object size_t params_pos = op_json.find("\"parameters\""); if (params_pos != std::string::npos) { size_t params_colon = op_json.find(":", params_pos); if (params_colon != std::string::npos) { size_t params_start = params_colon + 1; while (params_start < op_json.length() && (op_json[params_start] == ' ' || op_json[params_start] == '\t')) { params_start++; } if (params_start < op_json.length() && op_json[params_start] == '{') { int params_brace_count = 1; size_t params_end = params_start + 1; while (params_end < op_json.length() && params_brace_count > 0) { if (op_json[params_end] == '{') params_brace_count++; if (op_json[params_end] == '}') params_brace_count--; params_end++; } std::string params_json = op_json.substr(params_start, params_end - params_start); // Extract simple key-value parameters // For export_path, geom_flags, force_delete, etc. std::vector param_keys = {"export_path", "geom_flags", "force_delete", "project_name", "target_level", "quality", "chord_height", "output_file_path", "file_path", "open_mode", "working_directory", "input_file_path", "shrinkwrap_output_path", "step_export_path"}; for (const auto& key : param_keys) { std::string value = ExtractJsonValue(params_json, key); if (!value.empty()) { operation.parameters[key] = value; } } // Extract component_paths array if present std::vector comp_paths = ExtractJsonArray(params_json, "component_paths"); if (!comp_paths.empty()) { operation.array_parameters = comp_paths; } } } } operations.push_back(operation); } } catch (...) { // Parse error, return what we have } return operations; } // Batch Operations Handler HttpResponse BatchOperationsHandler(const HttpRequest& request) { HttpResponse response; if (request.method != "POST") { response.status_code = 405; response.body = "{\"success\": false, \"error\": \"Method not allowed\"}"; return response; } try { // Parse batch operations request BatchOperationsRequest batch_request; std::string execution_id = ExtractJsonValue(request.body, "execution_id"); std::string callback_server_address = Config::BATCH_CALLBACK_SERVER_ADDRESS; if (callback_server_address.empty()) { callback_server_address = ExtractJsonValue(request.body, "callback_server_address"); } if (callback_server_address.empty()) { callback_server_address = ExtractJsonValue(request.body, "callback_server"); } if (callback_server_address.empty()) { callback_server_address = ExtractJsonValue(request.body, "server_address"); } if (callback_server_address.empty()) { callback_server_address = ExtractJsonValue(request.body, "callback_base_url"); } std::string callback_token = Config::BATCH_CALLBACK_TOKEN; if (callback_token.empty()) { callback_token = ExtractJsonValue(request.body, "callback_token"); } if (callback_token.empty()) { callback_token = ExtractJsonValue(request.body, "token"); } batch_request.software_type = ExtractJsonValue(request.body, "software_type"); // Validate software_type if (batch_request.software_type.empty()) { batch_request.software_type = "creo"; } if (batch_request.software_type != "creo") { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}"; return response; } // Extract operations array batch_request.operations = ExtractBatchOperations(request.body); if (batch_request.operations.empty()) { response.status_code = 400; response.body = "{\"success\": false, \"error\": \"No operations specified or invalid operations format\"}"; return response; } // Execute batch operations BatchOperationsResponse batch_result = BatchOperationManager::Instance().ExecuteBatchOperations(batch_request); SendTaskResultCallbackWithRetry( callback_server_address, execution_id, batch_request.software_type, batch_result, callback_token ); // Build response JSON std::ostringstream json; json << "{" << "\"success\": " << (batch_result.success ? "true" : "false") << "," << "\"message\": \"" << EscapeJsonString(batch_result.message) << "\"," << "\"data\": {" << "\"total_operations\": " << batch_result.total_operations << "," << "\"successful_operations\": " << batch_result.successful_operations << "," << "\"failed_operations\": " << batch_result.failed_operations << "," << "\"execution_time\": \"" << EscapeJsonString(batch_result.execution_time) << "\"," << "\"results\": ["; // Build results array for (size_t i = 0; i < batch_result.results.size(); i++) { if (i > 0) json << ","; const BatchOperationResult& op_result = batch_result.results[i]; json << "{" << "\"operation_index\": " << op_result.operation_index << "," << "\"operation_type\": \"" << EscapeJsonString(op_result.operation_type) << "\"," << "\"success\": " << (op_result.success ? "true" : "false") << "," << "\"execution_time\": \"" << EscapeJsonString(op_result.execution_time) << "\","; if (op_result.success) { json << "\"result\": " << op_result.result_json << "," << "\"error\": null"; } else { json << "\"result\": null," << "\"error\": \"" << EscapeJsonString(op_result.error_message) << "\""; } json << "}"; } json << "]" << "}"; if (!batch_result.error_message.empty()) { json << ",\"error\": \"" << EscapeJsonString(batch_result.error_message) << "\""; } else { json << ",\"error\": null"; } json << "}"; response.body = json.str(); response.status_code = batch_result.success ? 200 : 500; } catch (const std::exception& e) { response.status_code = 500; response.body = "{\"success\": false, \"error\": \"Exception: " + std::string(e.what()) + "\"}"; } catch (...) { response.status_code = 500; response.body = "{\"success\": false, \"error\": \"Unknown error during batch operations\"}"; } return response; } extern "C" int user_initialize( int argc, char* argv[], char* version, char* build, wchar_t errbuf[80]) { pfcSession_ptr Session = pfcGetCurrentSessionWithCompatibility(pfcC4Compatible); wfcWSession_ptr wSession = wfcWSession::cast(Session); xstring info = L"New HTTP Server Starting on port 12345"; wSession->UIShowMessageDialog(info, NULL); // 启动定时器处理消息 timer_id = SetTimer(NULL, 0, 100, TimerProc); // 创建并启动HTTP服务器 g_http_server = std::make_unique(); // 设置路由 g_http_server->SetRouteHandler("/test", TestHandler); g_http_server->SetRouteHandler("/show_message", ShowMessageHandler); g_http_server->SetRouteHandler("/api/status/creo", CreoStatusHandler); g_http_server->SetRouteHandler("/api/status/model", ModelStatusHandler); g_http_server->SetRouteHandler("/api/export/model", ExportModelHandler); g_http_server->SetRouteHandler("/api/creo/analysis/hierarchy", HierarchyAnalysisHandler); g_http_server->SetRouteHandler("/api/creo/hierarchy/delete", HierarchyDeleteHandler); g_http_server->SetRouteHandler("/api/creo/subassembly/hierarchy/delete", SubassemblyHierarchyDeleteHandler); g_http_server->SetRouteHandler("/api/analysis/shell-analysis", ShellAnalysisHandler); g_http_server->SetRouteHandler("/api/model/save", SaveModelHandler); g_http_server->SetRouteHandler("/api/model/close", CloseModelHandler); g_http_server->SetRouteHandler("/api/model/open", OpenModelHandler); g_http_server->SetRouteHandler("/api/analysis/geometry-complexity", GeometryComplexityHandler); g_http_server->SetRouteHandler("/api/creo/shrinkwrap/shell", ShrinkwrapShellHandler); g_http_server->SetRouteHandler("/api/creo/component/delete-by-path", PathDeleteHandler); g_http_server->SetRouteHandler("/api/search/models", ModelSearchHandler::HandleModelSearchRequest); g_http_server->SetRouteHandler("/api/analysis/hierarchy-statistics", HierarchyStatisticsHandler); g_http_server->SetRouteHandler("/api/creo/component/children", ComponentChildrenHandler); g_http_server->SetRouteHandler("/api/creo/batch-operations", BatchOperationsHandler); if (g_http_server->Start()) { return 0; } else { g_http_server.reset(); return 1; } } // --- OTK 出口函数 --- // 这个函数在卸载插件或关闭 Creo 时被调用,非常重要! extern "C" void user_terminate() { if (g_http_server) { g_http_server->Stop(); g_http_server.reset(); } if (timer_id != 0) { KillTimer(NULL, timer_id); timer_id = 0; } }