- 添加关闭模型API端点 POST /api/model/close - 支持安全关闭和强制关闭两种模式 - 实现修改状态检查防止数据丢失 - 添加详细的关闭结果反馈 - 完善的异常处理和错误信息 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
984 lines
40 KiB
C++
984 lines
40 KiB
C++
// MFCCreoDll.cpp: 定义 DLL 的初始化例程。
|
||
//
|
||
|
||
#include "pch.h"
|
||
#include "framework.h"
|
||
#include "MFCCreoDll.h"
|
||
#include "HttpServer.h"
|
||
#include "CreoManager.h"
|
||
#include <wfcSession.h>
|
||
#include <wfcGlobal.h>
|
||
#include <string>
|
||
#include <sstream>
|
||
#include <regex>
|
||
#include <mutex>
|
||
#include <atomic>
|
||
#include <memory>
|
||
|
||
#ifdef _DEBUG
|
||
#define new DEBUG_NEW
|
||
#endif
|
||
|
||
// --- 全局变量 ---
|
||
static std::unique_ptr<HttpServer> g_http_server;
|
||
static std::mutex message_mutex;
|
||
static std::string pending_message; // 待处理的消息
|
||
static std::atomic<bool> has_pending_message{false};
|
||
static UINT_PTR timer_id = 0;
|
||
|
||
// --- 辅助函数:将 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_message.load()) {
|
||
std::lock_guard<std::mutex> lock(message_mutex);
|
||
if (has_pending_message.load()) {
|
||
has_pending_message = false; // 立即清除标志,避免重复触发
|
||
|
||
try {
|
||
pfcSession_ptr Session = pfcGetCurrentSession();
|
||
if (Session) {
|
||
// 创建字符串序列
|
||
xstringsequence_ptr messages = xstringsequence::create();
|
||
messages->append(xstring("Hello World Test"));
|
||
Session->UIDisplayMessage("message.txt", "USER_INFO", messages);
|
||
}
|
||
}
|
||
catch (...) {
|
||
// 处理失败
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// 测试路由处理器
|
||
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);
|
||
}
|
||
|
||
// 设置待处理消息
|
||
{
|
||
std::lock_guard<std::mutex> lock(message_mutex);
|
||
pending_message = message;
|
||
has_pending_message = true;
|
||
}
|
||
|
||
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 << ","
|
||
<< "\"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;
|
||
}
|
||
|
||
// 模型导出路由处理器
|
||
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\": \"" << result.export_path << "\","
|
||
<< "\"fileSize\": \"" << result.file_size << "\","
|
||
<< "\"format\": \"" << result.format << "\","
|
||
<< "\"exportTime\": \"" << result.export_time << "\","
|
||
<< "\"software\": \"" << result.software << "\","
|
||
<< "\"originalFile\": \"" << result.original_file << "\","
|
||
<< "\"details\": {"
|
||
<< "\"dirname\": \"" << result.dirname << "\","
|
||
<< "\"filename\": \"" << result.filename << "\","
|
||
<< "\"creoson_response\": {"
|
||
<< "\"dirname\": \"" << result.dirname << "\","
|
||
<< "\"filename\": \"" << result.filename << "\","
|
||
<< "\"full_path\": \"" << result.export_path << "\""
|
||
<< "}" // 结束 creoson_response
|
||
<< "}" // 结束 details
|
||
<< "}," // 结束 data
|
||
<< "\"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;
|
||
}
|
||
|
||
return response;
|
||
}
|
||
|
||
// JSON字符串转义函数
|
||
std::string EscapeJsonString(const std::string& str) {
|
||
std::string escaped = str;
|
||
|
||
// 替换反斜杠
|
||
size_t pos = 0;
|
||
while ((pos = escaped.find("\\", pos)) != std::string::npos) {
|
||
escaped.replace(pos, 1, "\\\\");
|
||
pos += 2;
|
||
}
|
||
|
||
// 替换双引号
|
||
pos = 0;
|
||
while ((pos = escaped.find("\"", pos)) != std::string::npos) {
|
||
escaped.replace(pos, 1, "\\\"");
|
||
pos += 2;
|
||
}
|
||
|
||
// 替换换行符
|
||
pos = 0;
|
||
while ((pos = escaped.find("\n", pos)) != std::string::npos) {
|
||
escaped.replace(pos, 1, "\\n");
|
||
pos += 2;
|
||
}
|
||
|
||
// 替换制表符
|
||
pos = 0;
|
||
while ((pos = escaped.find("\t", pos)) != std::string::npos) {
|
||
escaped.replace(pos, 1, "\\t");
|
||
pos += 2;
|
||
}
|
||
|
||
return escaped;
|
||
}
|
||
|
||
// 层级分析路由处理器
|
||
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表示无限制
|
||
}
|
||
|
||
// 执行层级分析
|
||
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 << "]"
|
||
<< "}"
|
||
<< "}"
|
||
<< "}";
|
||
|
||
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 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;
|
||
}
|
||
}
|
||
|
||
// 执行薄壳化分析
|
||
CreoManager::ShellAnalysisResult result = CreoManager::Instance().AnalyzeShellFeatures(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;
|
||
if (!deletion.part_file.empty()) {
|
||
json << ",\"partFile\": \"" << EscapeJsonString(deletion.part_file) << "\"";
|
||
}
|
||
if (!deletion.part_path.empty()) {
|
||
json << ",\"partPath\": \"" << EscapeJsonString(deletion.part_path) << "\"";
|
||
}
|
||
json << ",\"componentType\": \"" << EscapeJsonString(deletion.component_type) << "\""
|
||
<< "}";
|
||
}
|
||
|
||
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
|
||
<< "}";
|
||
}
|
||
|
||
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
|
||
<< "}";
|
||
}
|
||
|
||
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 << "}," // 结束 hierarchyAnalysis (加逗号)
|
||
<< "}," // 结束 analysisParameters (加逗号)
|
||
<< "\"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;
|
||
}
|
||
|
||
|
||
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<HttpServer>();
|
||
|
||
// 设置路由
|
||
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/analysis/shell-analysis", ShellAnalysisHandler);
|
||
g_http_server->SetRouteHandler("/api/model/save", SaveModelHandler);
|
||
g_http_server->SetRouteHandler("/api/model/close", CloseModelHandler);
|
||
|
||
|
||
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;
|
||
}
|
||
} |