2506 lines
104 KiB
C++
2506 lines
104 KiB
C++
// 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;
|
||
}
|
||
}
|