CreoOtkPluging/MFCCreoDll.cpp

2506 lines
104 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 <wfcSession.h>
#include <wfcGlobal.h>
#include <Windows.h>
#include <winhttp.h>
#include <string>
#include <sstream>
#include <regex>
#include <atomic>
#include <memory>
#include <chrono>
#include <ctime>
#include <thread>
#include <vector>
#pragma comment(lib, "winhttp.lib")
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// --- 全局变量 ---
static std::unique_ptr<HttpServer> 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<bool> 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<MessageItem*>(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<DWORD>(json_body.size()),
static_cast<DWORD>(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<int> retry_delays_seconds = {1, 3, 5};
const int max_attempts = 1 + static_cast<int>(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<int>(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<std::string> ExtractJsonArray(const std::string& json, const std::string& key) {
std::vector<std::string> 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<unsigned char>(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<OpenResult*>(open_message_item.result_ptr);
delete static_cast<OpenResult*>(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<HttpResponse*>(shrinkwrap_message_item->result_ptr);
delete static_cast<HttpResponse*>(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<BatchOperation> ExtractBatchOperations(const std::string& json) {
std::vector<BatchOperation> 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<std::string> 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<std::string> 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<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/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;
}
}